1// Copyright 2017 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 xfs provides access to statistics exposed by the XFS filesystem.
15package xfs
16
17import (
18	"os"
19	"path/filepath"
20	"strings"
21
22	"github.com/prometheus/procfs/internal/fs"
23)
24
25// Stats contains XFS filesystem runtime statistics, parsed from
26// /proc/fs/xfs/stat.
27//
28// The names and meanings of each statistic were taken from
29// http://xfs.org/index.php/Runtime_Stats and xfs_stats.h in the Linux
30// kernel source. Most counters are uint32s (same data types used in
31// xfs_stats.h), but some of the "extended precision stats" are uint64s.
32type Stats struct {
33	// The name of the filesystem used to source these statistics.
34	// If empty, this indicates aggregated statistics for all XFS
35	// filesystems on the host.
36	Name string
37
38	ExtentAllocation   ExtentAllocationStats
39	AllocationBTree    BTreeStats
40	BlockMapping       BlockMappingStats
41	BlockMapBTree      BTreeStats
42	DirectoryOperation DirectoryOperationStats
43	Transaction        TransactionStats
44	InodeOperation     InodeOperationStats
45	LogOperation       LogOperationStats
46	ReadWrite          ReadWriteStats
47	AttributeOperation AttributeOperationStats
48	InodeClustering    InodeClusteringStats
49	Vnode              VnodeStats
50	Buffer             BufferStats
51	ExtendedPrecision  ExtendedPrecisionStats
52	Xstrat             XstratStats            // xstrat
53	PushAil            PushAilStats           // push_ail
54	Debug              DebugStats             // debug
55	QuotaManager       QuotaManagerStats      // qm
56	BtreeAllocBlocks2  BtreeAllocBlocks2Stats // abtb2
57	BtreeAllocContig2  BtreeAllocContig2Stats // abtc2
58	BtreeBlockMap2     BtreeBlockMap2Stats    // bmbt2
59	BtreeInode2        BtreeInode2Stats       // ibt2
60}
61
62// ExtentAllocationStats contains statistics regarding XFS extent allocations.
63type ExtentAllocationStats struct {
64	ExtentsAllocated uint32
65	BlocksAllocated  uint32
66	ExtentsFreed     uint32
67	BlocksFreed      uint32
68}
69
70// BTreeStats contains statistics regarding an XFS internal B-tree.
71type BTreeStats struct {
72	Lookups         uint32
73	Compares        uint32
74	RecordsInserted uint32
75	RecordsDeleted  uint32
76}
77
78// BlockMappingStats contains statistics regarding XFS block maps.
79type BlockMappingStats struct {
80	Reads                uint32
81	Writes               uint32
82	Unmaps               uint32
83	ExtentListInsertions uint32
84	ExtentListDeletions  uint32
85	ExtentListLookups    uint32
86	ExtentListCompares   uint32
87}
88
89// DirectoryOperationStats contains statistics regarding XFS directory entries.
90type DirectoryOperationStats struct {
91	Lookups  uint32
92	Creates  uint32
93	Removes  uint32
94	Getdents uint32
95}
96
97// TransactionStats contains statistics regarding XFS metadata transactions.
98type TransactionStats struct {
99	Sync  uint32
100	Async uint32
101	Empty uint32
102}
103
104// InodeOperationStats contains statistics regarding XFS inode operations.
105type InodeOperationStats struct {
106	Attempts        uint32
107	Found           uint32
108	Recycle         uint32
109	Missed          uint32
110	Duplicate       uint32
111	Reclaims        uint32
112	AttributeChange uint32
113}
114
115// LogOperationStats contains statistics regarding the XFS log buffer.
116type LogOperationStats struct {
117	Writes            uint32
118	Blocks            uint32
119	NoInternalBuffers uint32
120	Force             uint32
121	ForceSleep        uint32
122}
123
124// ReadWriteStats contains statistics regarding the number of read and write
125// system calls for XFS filesystems.
126type ReadWriteStats struct {
127	Write uint32
128	Read  uint32
129}
130
131// AttributeOperationStats contains statistics regarding manipulation of
132// XFS extended file attributes.
133type AttributeOperationStats struct {
134	Get    uint32
135	Set    uint32
136	Remove uint32
137	List   uint32
138}
139
140// InodeClusteringStats contains statistics regarding XFS inode clustering
141// operations.
142type InodeClusteringStats struct {
143	Iflush     uint32
144	Flush      uint32
145	FlushInode uint32
146}
147
148// VnodeStats contains statistics regarding XFS vnode operations.
149type VnodeStats struct {
150	Active   uint32
151	Allocate uint32
152	Get      uint32
153	Hold     uint32
154	Release  uint32
155	Reclaim  uint32
156	Remove   uint32
157	Free     uint32
158}
159
160// BufferStats contains statistics regarding XFS read/write I/O buffers.
161type BufferStats struct {
162	Get             uint32
163	Create          uint32
164	GetLocked       uint32
165	GetLockedWaited uint32
166	BusyLocked      uint32
167	MissLocked      uint32
168	PageRetries     uint32
169	PageFound       uint32
170	GetRead         uint32
171}
172
173// ExtendedPrecisionStats contains high precision counters used to track the
174// total number of bytes read, written, or flushed, during XFS operations.
175type ExtendedPrecisionStats struct {
176	FlushBytes uint64
177	WriteBytes uint64
178	ReadBytes  uint64
179}
180
181// PushAilStats contains statistics on tail-pushing operations.
182type PushAilStats struct {
183	TryLogspace   uint32
184	SleepLogspace uint32
185	Pushes        uint32
186	Success       uint32
187	PushBuf       uint32
188	Pinned        uint32
189	Locked        uint32
190	Flushing      uint32
191	Restarts      uint32
192	Flush         uint32
193}
194
195// QuotaManagerStats contain statistics regarding quota processing.
196type QuotaManagerStats struct {
197	Reclaims      uint32
198	ReclaimMisses uint32
199	DquoteDups    uint32
200	CacheMisses   uint32
201	CacheHits     uint32
202	Wants         uint32
203	ShakeReclaims uint32
204	InactReclaims uint32
205	Unused        uint32
206}
207
208// XstratStats contains statistics regarding bytes processed by the XFS daemon.
209type XstratStats struct {
210	Quick uint32
211	Split uint32
212}
213
214// DebugStats indicate if XFS debugging is enabled.
215type DebugStats struct {
216	Enabled uint32
217}
218
219// BtreeAllocBlocks2Stats contains statistics on B-Tree v2 allocations.
220type BtreeAllocBlocks2Stats struct {
221	Lookup    uint32
222	Compare   uint32
223	Insrec    uint32
224	Delrec    uint32
225	NewRoot   uint32
226	KillRoot  uint32
227	Increment uint32
228	Decrement uint32
229	Lshift    uint32
230	Rshift    uint32
231	Split     uint32
232	Join      uint32
233	Alloc     uint32
234	Free      uint32
235	Moves     uint32
236}
237
238// BtreeAllocContig2Stats contain statistics on B-tree v2 free-space-by-size record operations.
239type BtreeAllocContig2Stats struct {
240	Lookup    uint32
241	Compare   uint32
242	Insrec    uint32
243	Delrec    uint32
244	NewRoot   uint32
245	KillRoot  uint32
246	Increment uint32
247	Decrement uint32
248	Lshift    uint32
249	Rshift    uint32
250	Split     uint32
251	Join      uint32
252	Alloc     uint32
253	Free      uint32
254	Moves     uint32
255}
256
257// BtreeBlockMap2Stats contain statistics on B-tree v2 block map operations.
258type BtreeBlockMap2Stats struct {
259	Lookup    uint32
260	Compare   uint32
261	Insrec    uint32
262	Delrec    uint32
263	NewRoot   uint32
264	KillRoot  uint32
265	Increment uint32
266	Decrement uint32
267	Lshift    uint32
268	Rshift    uint32
269	Split     uint32
270	Join      uint32
271	Alloc     uint32
272	Free      uint32
273	Moves     uint32
274}
275
276// BtreeInode2Stats contain statistics on B-tree v2 inode allocations.
277type BtreeInode2Stats struct {
278	Lookup    uint32
279	Compare   uint32
280	Insrec    uint32
281	Delrec    uint32
282	NewRoot   uint32
283	KillRoot  uint32
284	Increment uint32
285	Decrement uint32
286	Lshift    uint32
287	Rshift    uint32
288	Split     uint32
289	Join      uint32
290	Alloc     uint32
291	Free      uint32
292	Moves     uint32
293}
294
295// FS represents the pseudo-filesystems proc and sys, which provides an interface to
296// kernel data structures.
297type FS struct {
298	proc *fs.FS
299	sys  *fs.FS
300}
301
302// NewDefaultFS returns a new XFS handle using the default proc and sys mountPoints.
303// It will error if either of the mounts point can't be read.
304func NewDefaultFS() (FS, error) {
305	return NewFS(fs.DefaultProcMountPoint, fs.DefaultSysMountPoint)
306}
307
308// NewFS returns a new XFS handle using the given proc and sys mountPoints. It will error
309// if either of the mounts point can't be read.
310func NewFS(procMountPoint string, sysMountPoint string) (FS, error) {
311	if strings.TrimSpace(procMountPoint) == "" {
312		procMountPoint = fs.DefaultProcMountPoint
313	}
314	procfs, err := fs.NewFS(procMountPoint)
315	if err != nil {
316		return FS{}, err
317	}
318	if strings.TrimSpace(sysMountPoint) == "" {
319		sysMountPoint = fs.DefaultSysMountPoint
320	}
321	sysfs, err := fs.NewFS(sysMountPoint)
322	if err != nil {
323		return FS{}, err
324	}
325	return FS{&procfs, &sysfs}, nil
326}
327
328// ProcStat retrieves XFS filesystem runtime statistics
329// from proc/fs/xfs/stat given the profs mount point.
330func (fs FS) ProcStat() (*Stats, error) {
331	f, err := os.Open(fs.proc.Path("fs/xfs/stat"))
332	if err != nil {
333		return nil, err
334	}
335	defer f.Close()
336
337	return ParseStats(f)
338}
339
340// SysStats retrieves XFS filesystem runtime statistics for each mounted XFS
341// filesystem.  Only available on kernel 4.4+.  On older kernels, an empty
342// slice of *xfs.Stats will be returned.
343func (fs FS) SysStats() ([]*Stats, error) {
344	matches, err := filepath.Glob(fs.sys.Path("fs/xfs/*/stats/stats"))
345	if err != nil {
346		return nil, err
347	}
348
349	stats := make([]*Stats, 0, len(matches))
350	for _, m := range matches {
351		f, err := os.Open(m)
352		if err != nil {
353			return nil, err
354		}
355
356		// "*" used in glob above indicates the name of the filesystem.
357		name := filepath.Base(filepath.Dir(filepath.Dir(m)))
358
359		// File must be closed after parsing, regardless of success or
360		// failure.  Defer is not used because of the loop.
361		s, err := ParseStats(f)
362		_ = f.Close()
363		if err != nil {
364			return nil, err
365		}
366
367		s.Name = name
368		stats = append(stats, s)
369	}
370
371	return stats, nil
372}
373