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}
53
54// ExtentAllocationStats contains statistics regarding XFS extent allocations.
55type ExtentAllocationStats struct {
56	ExtentsAllocated uint32
57	BlocksAllocated  uint32
58	ExtentsFreed     uint32
59	BlocksFreed      uint32
60}
61
62// BTreeStats contains statistics regarding an XFS internal B-tree.
63type BTreeStats struct {
64	Lookups         uint32
65	Compares        uint32
66	RecordsInserted uint32
67	RecordsDeleted  uint32
68}
69
70// BlockMappingStats contains statistics regarding XFS block maps.
71type BlockMappingStats struct {
72	Reads                uint32
73	Writes               uint32
74	Unmaps               uint32
75	ExtentListInsertions uint32
76	ExtentListDeletions  uint32
77	ExtentListLookups    uint32
78	ExtentListCompares   uint32
79}
80
81// DirectoryOperationStats contains statistics regarding XFS directory entries.
82type DirectoryOperationStats struct {
83	Lookups  uint32
84	Creates  uint32
85	Removes  uint32
86	Getdents uint32
87}
88
89// TransactionStats contains statistics regarding XFS metadata transactions.
90type TransactionStats struct {
91	Sync  uint32
92	Async uint32
93	Empty uint32
94}
95
96// InodeOperationStats contains statistics regarding XFS inode operations.
97type InodeOperationStats struct {
98	Attempts        uint32
99	Found           uint32
100	Recycle         uint32
101	Missed          uint32
102	Duplicate       uint32
103	Reclaims        uint32
104	AttributeChange uint32
105}
106
107// LogOperationStats contains statistics regarding the XFS log buffer.
108type LogOperationStats struct {
109	Writes            uint32
110	Blocks            uint32
111	NoInternalBuffers uint32
112	Force             uint32
113	ForceSleep        uint32
114}
115
116// ReadWriteStats contains statistics regarding the number of read and write
117// system calls for XFS filesystems.
118type ReadWriteStats struct {
119	Read  uint32
120	Write uint32
121}
122
123// AttributeOperationStats contains statistics regarding manipulation of
124// XFS extended file attributes.
125type AttributeOperationStats struct {
126	Get    uint32
127	Set    uint32
128	Remove uint32
129	List   uint32
130}
131
132// InodeClusteringStats contains statistics regarding XFS inode clustering
133// operations.
134type InodeClusteringStats struct {
135	Iflush     uint32
136	Flush      uint32
137	FlushInode uint32
138}
139
140// VnodeStats contains statistics regarding XFS vnode operations.
141type VnodeStats struct {
142	Active   uint32
143	Allocate uint32
144	Get      uint32
145	Hold     uint32
146	Release  uint32
147	Reclaim  uint32
148	Remove   uint32
149	Free     uint32
150}
151
152// BufferStats contains statistics regarding XFS read/write I/O buffers.
153type BufferStats struct {
154	Get             uint32
155	Create          uint32
156	GetLocked       uint32
157	GetLockedWaited uint32
158	BusyLocked      uint32
159	MissLocked      uint32
160	PageRetries     uint32
161	PageFound       uint32
162	GetRead         uint32
163}
164
165// ExtendedPrecisionStats contains high precision counters used to track the
166// total number of bytes read, written, or flushed, during XFS operations.
167type ExtendedPrecisionStats struct {
168	FlushBytes uint64
169	WriteBytes uint64
170	ReadBytes  uint64
171}
172
173// FS represents the pseudo-filesystems proc and sys, which provides an interface to
174// kernel data structures.
175type FS struct {
176	proc *fs.FS
177	sys  *fs.FS
178}
179
180// NewDefaultFS returns a new XFS handle using the default proc and sys mountPoints.
181// It will error if either of the mounts point can't be read.
182func NewDefaultFS() (FS, error) {
183	return NewFS(fs.DefaultProcMountPoint, fs.DefaultSysMountPoint)
184}
185
186// NewFS returns a new XFS handle using the given proc and sys mountPoints. It will error
187// if either of the mounts point can't be read.
188func NewFS(procMountPoint string, sysMountPoint string) (FS, error) {
189	if strings.TrimSpace(procMountPoint) == "" {
190		procMountPoint = fs.DefaultProcMountPoint
191	}
192	procfs, err := fs.NewFS(procMountPoint)
193	if err != nil {
194		return FS{}, err
195	}
196	if strings.TrimSpace(sysMountPoint) == "" {
197		sysMountPoint = fs.DefaultSysMountPoint
198	}
199	sysfs, err := fs.NewFS(sysMountPoint)
200	if err != nil {
201		return FS{}, err
202	}
203	return FS{&procfs, &sysfs}, nil
204}
205
206// ProcStat retrieves XFS filesystem runtime statistics
207// from proc/fs/xfs/stat given the profs mount point.
208func (fs FS) ProcStat() (*Stats, error) {
209	f, err := os.Open(fs.proc.Path("fs/xfs/stat"))
210	if err != nil {
211		return nil, err
212	}
213	defer f.Close()
214
215	return ParseStats(f)
216}
217
218// SysStats retrieves XFS filesystem runtime statistics for each mounted XFS
219// filesystem.  Only available on kernel 4.4+.  On older kernels, an empty
220// slice of *xfs.Stats will be returned.
221func (fs FS) SysStats() ([]*Stats, error) {
222	matches, err := filepath.Glob(fs.sys.Path("fs/xfs/*/stats/stats"))
223	if err != nil {
224		return nil, err
225	}
226
227	stats := make([]*Stats, 0, len(matches))
228	for _, m := range matches {
229		f, err := os.Open(m)
230		if err != nil {
231			return nil, err
232		}
233
234		// "*" used in glob above indicates the name of the filesystem.
235		name := filepath.Base(filepath.Dir(filepath.Dir(m)))
236
237		// File must be closed after parsing, regardless of success or
238		// failure.  Defer is not used because of the loop.
239		s, err := ParseStats(f)
240		_ = f.Close()
241		if err != nil {
242			return nil, err
243		}
244
245		s.Name = name
246		stats = append(stats, s)
247	}
248
249	return stats, nil
250}
251