Skip to content

Commit 80824fa

Browse files
bobrikdiscordianfish
authored andcommitted
Check whether FS is a real procfs where it matters
For some behaviors there is no substitution for real `/proc`. One example is `stat()` for `/proc/<pid>/fd` returning the number of open files for `procfs`. The field has a different meaning on regular filesystems and we need to check for it in tests. Work around this by carrying the fact that `FS` is real in the `FS` struct itself, so that it can be checked where it matters. The realness is determined once per `FS` creation by doing `statfs()` and checking for the `PROC_SUPER_MAGIC` match in the returned fs type. Signed-off-by: Ivan Babrou <[email protected]>
1 parent d9f81a9 commit 80824fa

File tree

5 files changed

+43
-22
lines changed

5 files changed

+43
-22
lines changed

fs.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,16 @@
1414
package procfs
1515

1616
import (
17+
"syscall"
18+
1719
"github.com/prometheus/procfs/internal/fs"
1820
)
1921

2022
// FS represents the pseudo-filesystem sys, which provides an interface to
2123
// kernel data structures.
2224
type FS struct {
2325
proc fs.FS
26+
real bool
2427
}
2528

2629
// DefaultMountPoint is the common mount point of the proc filesystem.
@@ -39,5 +42,23 @@ func NewFS(mountPoint string) (FS, error) {
3942
if err != nil {
4043
return FS{}, err
4144
}
42-
return FS{fs}, nil
45+
46+
real, err := isRealProc(mountPoint)
47+
if err != nil {
48+
return FS{}, err
49+
}
50+
51+
return FS{fs, real}, nil
52+
}
53+
54+
// isRealProc determines whether supplied mountpoint is really a proc filesystem.
55+
func isRealProc(mountPoint string) (bool, error) {
56+
stat := syscall.Statfs_t{}
57+
err := syscall.Statfs(mountPoint, &stat)
58+
if err != nil {
59+
return false, err
60+
}
61+
62+
// 0x9fa0 is PROC_SUPER_MAGIC: https://elixir.bootlin.com/linux/v6.1/source/include/uapi/linux/magic.h#L87
63+
return stat.Type == 0x9fa0, nil
4364
}

proc.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"strconv"
2222
"strings"
2323

24-
"github.com/prometheus/procfs/internal/fs"
2524
"github.com/prometheus/procfs/internal/util"
2625
)
2726

@@ -30,7 +29,7 @@ type Proc struct {
3029
// The process ID.
3130
PID int
3231

33-
fs fs.FS
32+
fs FS
3433
}
3534

3635
// Procs represents a list of Proc structs.
@@ -92,7 +91,7 @@ func (fs FS) Proc(pid int) (Proc, error) {
9291
if _, err := os.Stat(fs.proc.Path(strconv.Itoa(pid))); err != nil {
9392
return Proc{}, err
9493
}
95-
return Proc{PID: pid, fs: fs.proc}, nil
94+
return Proc{PID: pid, fs: fs}, nil
9695
}
9796

9897
// AllProcs returns a list of all currently available processes.
@@ -114,7 +113,7 @@ func (fs FS) AllProcs() (Procs, error) {
114113
if err != nil {
115114
continue
116115
}
117-
p = append(p, Proc{PID: int(pid), fs: fs.proc})
116+
p = append(p, Proc{PID: int(pid), fs: fs})
118117
}
119118

120119
return p, nil
@@ -238,14 +237,16 @@ func (p Proc) FileDescriptorTargets() ([]string, error) {
238237
// a process.
239238
func (p Proc) FileDescriptorsLen() (int, error) {
240239
// Use fast path if available (Linux v6.2): https://github.com/torvalds/linux/commit/f1f1f2569901
241-
stat, err := os.Stat(p.path("fd"))
242-
if err != nil {
243-
return 0, err
244-
}
240+
if p.fs.real {
241+
stat, err := os.Stat(p.path("fd"))
242+
if err != nil {
243+
return 0, err
244+
}
245245

246-
size := stat.Size()
247-
if size > 0 {
248-
return int(size), nil
246+
size := stat.Size()
247+
if size > 0 {
248+
return int(size), nil
249+
}
249250
}
250251

251252
fds, err := p.fileDescriptors()
@@ -296,7 +297,7 @@ func (p Proc) fileDescriptors() ([]string, error) {
296297
}
297298

298299
func (p Proc) path(pa ...string) string {
299-
return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...)
300+
return p.fs.proc.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...)
300301
}
301302

302303
// FileDescriptorsInfo retrieves information about all file descriptors of

proc_stat.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"fmt"
1919
"os"
2020

21-
"github.com/prometheus/procfs/internal/fs"
2221
"github.com/prometheus/procfs/internal/util"
2322
)
2423

@@ -112,7 +111,7 @@ type ProcStat struct {
112111
// Aggregated block I/O delays, measured in clock ticks (centiseconds).
113112
DelayAcctBlkIOTicks uint64
114113

115-
proc fs.FS
114+
proc FS
116115
}
117116

118117
// NewStat returns the current status information of the process.
@@ -210,8 +209,7 @@ func (s ProcStat) ResidentMemory() int {
210209

211210
// StartTime returns the unix timestamp of the process in seconds.
212211
func (s ProcStat) StartTime() (float64, error) {
213-
fs := FS{proc: s.proc}
214-
stat, err := fs.Stat()
212+
stat, err := s.proc.Stat()
215213
if err != nil {
216214
return 0, err
217215
}

thread.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ func (fs FS) AllThreads(pid int) (Procs, error) {
5454
if err != nil {
5555
continue
5656
}
57-
t = append(t, Proc{PID: int(tid), fs: fsi.FS(taskPath)})
57+
58+
t = append(t, Proc{PID: int(tid), fs: FS{fsi.FS(taskPath), fs.real}})
5859
}
5960

6061
return t, nil
@@ -66,13 +67,13 @@ func (fs FS) Thread(pid, tid int) (Proc, error) {
6667
if _, err := os.Stat(taskPath); err != nil {
6768
return Proc{}, err
6869
}
69-
return Proc{PID: tid, fs: fsi.FS(taskPath)}, nil
70+
return Proc{PID: tid, fs: FS{fsi.FS(taskPath), fs.real}}, nil
7071
}
7172

7273
// Thread returns a process for a given TID of Proc.
7374
func (proc Proc) Thread(tid int) (Proc, error) {
74-
tfs := fsi.FS(proc.path("task"))
75-
if _, err := os.Stat(tfs.Path(strconv.Itoa(tid))); err != nil {
75+
tfs := FS{fsi.FS(proc.path("task")), proc.fs.real}
76+
if _, err := os.Stat(tfs.proc.Path(strconv.Itoa(tid))); err != nil {
7677
return Proc{}, err
7778
}
7879
return Proc{PID: tid, fs: tfs}, nil

thread_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestAllThreads(t *testing.T) {
3737
t.Errorf("want TID %d, have %d", wantTID, haveTID)
3838
}
3939
wantFS := fixFS.proc.Path(strconv.Itoa(testPID), "task")
40-
haveFS := string(threads[i].fs)
40+
haveFS := string(threads[i].fs.proc)
4141
if wantFS != haveFS {
4242
t.Errorf("want fs %q, have %q", wantFS, haveFS)
4343
}

0 commit comments

Comments
 (0)