1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
package main
import (
"fmt"
"path/filepath"
"syscall"
)
const sysCloseRange = 436
// closeBasic opens multiple files and closes them.
func closeBasic() error {
dir, cleanup, err := makeTempDir("close-basic")
if err != nil {
return err
}
defer cleanup()
var fds []int
for i := range 3 {
path := filepath.Join(dir, fmt.Sprintf("closefile-%d.txt", i))
fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644)
if err != nil {
return fmt.Errorf("open %d: %w", i, err)
}
fds = append(fds, fd)
}
for _, fd := range fds {
if err := syscall.Close(fd); err != nil {
return fmt.Errorf("close fd %d: %w", fd, err)
}
}
return nil
}
// closeRange opens multiple files and closes a range of them via close_range(2).
func closeRange() error {
dir, cleanup, err := makeTempDir("close-range")
if err != nil {
return err
}
defer cleanup()
var fds []int
for i := range 3 {
path := filepath.Join(dir, fmt.Sprintf("closerangefile-%d.txt", i))
fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644)
if err != nil {
return fmt.Errorf("open %d: %w", i, err)
}
fds = append(fds, fd)
}
if fds[2]-fds[0] != 2 {
return fmt.Errorf("fds not contiguous: %v", fds)
}
first := uintptr(fds[0])
last := uintptr(fds[len(fds)-1])
_, _, errno := syscall.Syscall(sysCloseRange, first, last, 0)
if errno != 0 {
return fmt.Errorf("close_range: %w", errno)
}
return nil
}
// closeRangeBounded opens a contiguous block of low fds plus one higher fd,
// then closes only the low block via close_range(first, last, 0) where last is
// strictly below the higher fd. It writes to the higher fd afterwards to prove
// it stayed open. This exercises close_range's upper-bound handling end to end:
// ior must keep the higher fd tracked rather than evicting everything >= first.
func closeRangeBounded() error {
dir, cleanup, err := makeTempDir("close-range-bounded")
if err != nil {
return err
}
defer cleanup()
var lowFds []int
for i := range 3 {
path := filepath.Join(dir, fmt.Sprintf("closerangelow-%d.txt", i))
fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644)
if err != nil {
return fmt.Errorf("open low %d: %w", i, err)
}
lowFds = append(lowFds, fd)
}
highPath := filepath.Join(dir, "closerangehigh.txt")
highFd, err := syscall.Open(highPath, syscall.O_RDWR|syscall.O_CREAT, 0o644)
if err != nil {
return fmt.Errorf("open high: %w", err)
}
defer syscall.Close(highFd)
if highFd <= lowFds[len(lowFds)-1] {
return fmt.Errorf("high fd %d not above low fds %v", highFd, lowFds)
}
first := uintptr(lowFds[0])
last := uintptr(lowFds[len(lowFds)-1])
if _, _, errno := syscall.Syscall(sysCloseRange, first, last, 0); errno != 0 {
return fmt.Errorf("close_range: %w", errno)
}
// highFd is above last, so it must still be open and usable.
if _, err := syscall.Write(highFd, []byte("still-open")); err != nil {
return fmt.Errorf("write high fd: %w", err)
}
return nil
}
// closeInvalidFd attempts to close a very high fd number that is not open.
// The close fails with EBADF, but ior should capture the enter_close tracepoint
// because arguments are read on syscall entry before the kernel returns an error.
func closeInvalidFd() error {
err := syscall.Close(99999)
if err == nil {
return fmt.Errorf("expected close of invalid fd to fail")
}
return nil
}
// closeDoubleClose opens a file, closes it normally, then closes the same fd again.
// The second close fails with EBADF, but ior should capture both enter_close
// tracepoints because arguments are read on syscall entry.
func closeDoubleClose() error {
dir, cleanup, err := makeTempDir("close-double-close")
if err != nil {
return err
}
defer cleanup()
path := filepath.Join(dir, "doubleclosefile.txt")
fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644)
if err != nil {
return fmt.Errorf("open: %w", err)
}
if err := syscall.Close(fd); err != nil {
return fmt.Errorf("first close: %w", err)
}
err = syscall.Close(fd)
if err == nil {
return fmt.Errorf("expected second close of same fd to fail")
}
return nil
}
// closeRangeEmpty calls close_range(2) with a range of very high fd numbers
// (9000–9999) where no fds are open. The syscall succeeds (empty range is valid),
// and ior should capture the enter_close_range tracepoint.
func closeRangeEmpty() error {
// Retry a few times to reduce event-loss flakiness under heavy test load.
for i := 0; i < 5; i++ {
_, _, errno := syscall.Syscall(sysCloseRange, 9000, 9999, 0)
if errno != 0 {
return fmt.Errorf("close_range: %w", errno)
}
}
return nil
}
|