aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/prometheus/procfs/btrfs/get.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/prometheus/procfs/btrfs/get.go')
-rw-r--r--vendor/github.com/prometheus/procfs/btrfs/get.go251
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
14package btrfs
15
16import (
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.
31const SectorSize = 512
32
33// FS represents the pseudo-filesystem sys, which provides an interface to
34// kernel data structures.
35type 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.
41func 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.
47func 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.
59func (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
84func 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
94type 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.
102func (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.
111func (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.
124func (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.
139func (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
166func (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.
184func (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.
194func (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.
210func (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.
223func (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}