diff options
Diffstat (limited to 'vendor/github.com/prometheus/procfs/btrfs/get.go')
-rw-r--r-- | vendor/github.com/prometheus/procfs/btrfs/get.go | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/vendor/github.com/prometheus/procfs/btrfs/get.go b/vendor/github.com/prometheus/procfs/btrfs/get.go new file mode 100644 index 0000000..fa70daa --- /dev/null +++ b/vendor/github.com/prometheus/procfs/btrfs/get.go | |||
@@ -0,0 +1,251 @@ | |||
1 | // Copyright 2019 The Prometheus Authors | ||
2 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
3 | // you may not use this file except in compliance with the License. | ||
4 | // You may obtain a copy of the License at | ||
5 | // | ||
6 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
7 | // | ||
8 | // Unless required by applicable law or agreed to in writing, software | ||
9 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
11 | // See the License for the specific language governing permissions and | ||
12 | // limitations under the License. | ||
13 | |||
14 | package btrfs | ||
15 | |||
16 | import ( | ||
17 | "io/ioutil" | ||
18 | "os" | ||
19 | "path" | ||
20 | "path/filepath" | ||
21 | "strconv" | ||
22 | "strings" | ||
23 | |||
24 | "github.com/prometheus/procfs/internal/fs" | ||
25 | "github.com/prometheus/procfs/internal/util" | ||
26 | ) | ||
27 | |||
28 | // SectorSize contains the Linux sector size. | ||
29 | // > Linux always considers sectors to be 512 bytes long independently | ||
30 | // > of the devices real block size. | ||
31 | const SectorSize = 512 | ||
32 | |||
33 | // FS represents the pseudo-filesystem sys, which provides an interface to | ||
34 | // kernel data structures. | ||
35 | type FS struct { | ||
36 | sys *fs.FS | ||
37 | } | ||
38 | |||
39 | // NewDefaultFS returns a new Bcache using the default sys fs mount point. It will error | ||
40 | // if the mount point can't be read. | ||
41 | func NewDefaultFS() (FS, error) { | ||
42 | return NewFS(fs.DefaultSysMountPoint) | ||
43 | } | ||
44 | |||
45 | // NewFS returns a new Btrfs filesystem using the given sys fs mount point. It will error | ||
46 | // if the mount point can't be read. | ||
47 | func NewFS(mountPoint string) (FS, error) { | ||
48 | if strings.TrimSpace(mountPoint) == "" { | ||
49 | mountPoint = fs.DefaultSysMountPoint | ||
50 | } | ||
51 | sys, err := fs.NewFS(mountPoint) | ||
52 | if err != nil { | ||
53 | return FS{}, err | ||
54 | } | ||
55 | return FS{&sys}, nil | ||
56 | } | ||
57 | |||
58 | // Stats retrieves Btrfs filesystem runtime statistics for each mounted Btrfs filesystem. | ||
59 | func (fs FS) Stats() ([]*Stats, error) { | ||
60 | matches, err := filepath.Glob(fs.sys.Path("fs/btrfs/*-*")) | ||
61 | if err != nil { | ||
62 | return nil, err | ||
63 | } | ||
64 | |||
65 | stats := make([]*Stats, 0, len(matches)) | ||
66 | for _, uuidPath := range matches { | ||
67 | s, err := GetStats(uuidPath) | ||
68 | if err != nil { | ||
69 | return nil, err | ||
70 | } | ||
71 | |||
72 | // Set the UUID from the path when it could not be retrieved from the filesystem. | ||
73 | if s.UUID == "" { | ||
74 | s.UUID = filepath.Base(uuidPath) | ||
75 | } | ||
76 | |||
77 | stats = append(stats, s) | ||
78 | } | ||
79 | |||
80 | return stats, nil | ||
81 | } | ||
82 | |||
83 | // GetStats collects all Btrfs statistics from sysfs | ||
84 | func GetStats(uuidPath string) (*Stats, error) { | ||
85 | r := &reader{path: uuidPath} | ||
86 | s := r.readFilesystemStats() | ||
87 | if r.err != nil { | ||
88 | return nil, r.err | ||
89 | } | ||
90 | |||
91 | return s, nil | ||
92 | } | ||
93 | |||
94 | type reader struct { | ||
95 | path string | ||
96 | err error | ||
97 | devCount int | ||
98 | } | ||
99 | |||
100 | // readFile reads a file relative to the path of the reader. | ||
101 | // Non-existing files are ignored. | ||
102 | func (r *reader) readFile(n string) string { | ||
103 | b, err := util.SysReadFile(path.Join(r.path, n)) | ||
104 | if err != nil && !os.IsNotExist(err) { | ||
105 | r.err = err | ||
106 | } | ||
107 | return strings.TrimSpace(string(b)) | ||
108 | } | ||
109 | |||
110 | // readValues reads a number of numerical values into an uint64 slice. | ||
111 | func (r *reader) readValue(n string) (v uint64) { | ||
112 | // Read value from file | ||
113 | s := r.readFile(n) | ||
114 | if r.err != nil { | ||
115 | return | ||
116 | } | ||
117 | |||
118 | // Convert number | ||
119 | v, _ = strconv.ParseUint(s, 10, 64) | ||
120 | return | ||
121 | } | ||
122 | |||
123 | // listFiles returns a list of files for a directory of the reader. | ||
124 | func (r *reader) listFiles(p string) []string { | ||
125 | files, err := ioutil.ReadDir(path.Join(r.path, p)) | ||
126 | if err != nil { | ||
127 | r.err = err | ||
128 | return nil | ||
129 | } | ||
130 | |||
131 | names := make([]string, len(files)) | ||
132 | for i, f := range files { | ||
133 | names[i] = f.Name() | ||
134 | } | ||
135 | return names | ||
136 | } | ||
137 | |||
138 | // readAllocationStats reads Btrfs allocation data for the current path. | ||
139 | func (r *reader) readAllocationStats(d string) (a *AllocationStats) { | ||
140 | // Create a reader for this subdirectory | ||
141 | sr := &reader{path: path.Join(r.path, d), devCount: r.devCount} | ||
142 | |||
143 | // Get the stats | ||
144 | a = &AllocationStats{ | ||
145 | // Read basic allocation stats | ||
146 | MayUseBytes: sr.readValue("bytes_may_use"), | ||
147 | PinnedBytes: sr.readValue("bytes_pinned"), | ||
148 | ReadOnlyBytes: sr.readValue("bytes_readonly"), | ||
149 | ReservedBytes: sr.readValue("bytes_reserved"), | ||
150 | UsedBytes: sr.readValue("bytes_used"), | ||
151 | DiskUsedBytes: sr.readValue("disk_used"), | ||
152 | DiskTotalBytes: sr.readValue("disk_total"), | ||
153 | Flags: sr.readValue("flags"), | ||
154 | TotalBytes: sr.readValue("total_bytes"), | ||
155 | TotalPinnedBytes: sr.readValue("total_bytes_pinned"), | ||
156 | Layouts: sr.readLayouts(), | ||
157 | } | ||
158 | |||
159 | // Pass any error back | ||
160 | r.err = sr.err | ||
161 | |||
162 | return | ||
163 | } | ||
164 | |||
165 | // readLayouts reads all Btrfs layout statistics for the current path | ||
166 | func (r *reader) readLayouts() map[string]*LayoutUsage { | ||
167 | files, err := ioutil.ReadDir(r.path) | ||
168 | if err != nil { | ||
169 | r.err = err | ||
170 | return nil | ||
171 | } | ||
172 | |||
173 | m := make(map[string]*LayoutUsage) | ||
174 | for _, f := range files { | ||
175 | if f.IsDir() { | ||
176 | m[f.Name()] = r.readLayout(f.Name()) | ||
177 | } | ||
178 | } | ||
179 | |||
180 | return m | ||
181 | } | ||
182 | |||
183 | // readLayout reads the Btrfs layout statistics for an allocation layout. | ||
184 | func (r *reader) readLayout(p string) (l *LayoutUsage) { | ||
185 | l = new(LayoutUsage) | ||
186 | l.TotalBytes = r.readValue(path.Join(p, "total_bytes")) | ||
187 | l.UsedBytes = r.readValue(path.Join(p, "used_bytes")) | ||
188 | l.Ratio = r.calcRatio(p) | ||
189 | |||
190 | return | ||
191 | } | ||
192 | |||
193 | // calcRatio returns the calculated ratio for a layout mode. | ||
194 | func (r *reader) calcRatio(p string) float64 { | ||
195 | switch p { | ||
196 | case "single", "raid0": | ||
197 | return 1 | ||
198 | case "dup", "raid1", "raid10": | ||
199 | return 2 | ||
200 | case "raid5": | ||
201 | return float64(r.devCount) / (float64(r.devCount) - 1) | ||
202 | case "raid6": | ||
203 | return float64(r.devCount) / (float64(r.devCount) - 2) | ||
204 | default: | ||
205 | return 0 | ||
206 | } | ||
207 | } | ||
208 | |||
209 | // readDeviceInfo returns the information for all devices associated with this filesystem. | ||
210 | func (r *reader) readDeviceInfo(d string) map[string]*Device { | ||
211 | devs := r.listFiles("devices") | ||
212 | info := make(map[string]*Device, len(devs)) | ||
213 | for _, n := range devs { | ||
214 | info[n] = &Device{ | ||
215 | Size: SectorSize * r.readValue("devices/"+n+"/size"), | ||
216 | } | ||
217 | } | ||
218 | |||
219 | return info | ||
220 | } | ||
221 | |||
222 | // readFilesystemStats reads Btrfs statistics for a filesystem. | ||
223 | func (r *reader) readFilesystemStats() (s *Stats) { | ||
224 | // First get disk info, and add it to reader | ||
225 | devices := r.readDeviceInfo("devices") | ||
226 | r.devCount = len(devices) | ||
227 | |||
228 | s = &Stats{ | ||
229 | // Read basic filesystem information | ||
230 | Label: r.readFile("label"), | ||
231 | UUID: r.readFile("metadata_uuid"), | ||
232 | Features: r.listFiles("features"), | ||
233 | CloneAlignment: r.readValue("clone_alignment"), | ||
234 | NodeSize: r.readValue("nodesize"), | ||
235 | QuotaOverride: r.readValue("quota_override"), | ||
236 | SectorSize: r.readValue("sectorsize"), | ||
237 | |||
238 | // Device info | ||
239 | Devices: devices, | ||
240 | |||
241 | // Read allocation data | ||
242 | Allocation: Allocation{ | ||
243 | GlobalRsvReserved: r.readValue("allocation/global_rsv_reserved"), | ||
244 | GlobalRsvSize: r.readValue("allocation/global_rsv_size"), | ||
245 | Data: r.readAllocationStats("allocation/data"), | ||
246 | Metadata: r.readAllocationStats("allocation/metadata"), | ||
247 | System: r.readAllocationStats("allocation/system"), | ||
248 | }, | ||
249 | } | ||
250 | return | ||
251 | } | ||