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
164
165
166
|
package integrationtests
import (
"strings"
"testing"
)
const mqPayloadLen = uint64(14)
var ipcDescriptorTraceArgs = []string{"-trace-syscalls", "pipe,pipe2,eventfd,eventfd2,close"}
var inotifyTraceArgs = []string{"-trace-syscalls", "inotify_init1,inotify_add_watch,inotify_rm_watch,close"}
func TestPipeBasic(t *testing.T) {
result, _ := runScenarioResultWithIorArgs(t, "pipe-basic", []ExpectedEvent{
{Tracepoint: "enter_pipe", MinCount: 1},
{Tracepoint: "enter_close", MinCount: 2},
}, ipcDescriptorTraceArgs)
assertTracepointPathPrefix(t, result, "enter_pipe", "pipe:")
if got := totalTracepointPathCount(result, "enter_close", "pipe:"); got < 2 {
t.Fatalf("enter_close records with tracked pipe descriptor prefix = %d, want >= 2", got)
}
}
func TestPipe2Basic(t *testing.T) {
result, _ := runScenarioResultWithIorArgs(t, "pipe2-basic", []ExpectedEvent{
{Tracepoint: "enter_pipe2", MinCount: 1},
{Tracepoint: "enter_close", MinCount: 2},
}, ipcDescriptorTraceArgs)
assertTracepointPathPrefix(t, result, "enter_pipe2", "pipe:")
if got := totalTracepointPathCount(result, "enter_close", "pipe:"); got < 2 {
t.Fatalf("enter_close records with tracked pipe2 descriptor prefix = %d, want >= 2", got)
}
}
func TestEventfdBasic(t *testing.T) {
result, _ := runScenarioResultWithIorArgs(t, "eventfd-basic", []ExpectedEvent{
{Tracepoint: "enter_eventfd", MinCount: 1},
{Tracepoint: "enter_close", MinCount: 1},
}, ipcDescriptorTraceArgs)
assertTracepointPathPrefix(t, result, "enter_eventfd", "eventfd:")
assertTracepointPathPrefix(t, result, "enter_close", "eventfd:")
}
func TestEventfd2Basic(t *testing.T) {
result, _ := runScenarioResultWithIorArgs(t, "eventfd2-basic", []ExpectedEvent{
{Tracepoint: "enter_eventfd2", MinCount: 1},
{Tracepoint: "enter_close", MinCount: 1},
}, ipcDescriptorTraceArgs)
assertTracepointPathPrefix(t, result, "enter_eventfd2", "eventfd:")
assertTracepointPathPrefix(t, result, "enter_close", "eventfd:")
}
func TestFdFromAirEventfdUsers(t *testing.T) {
enableParallelIfRequested(t)
h := newTestHarness(t)
result, pid, err := h.RunWithIorArgs("fd-from-air-eventfd-users", defaultDuration, []string{
"-trace-families", "IPC",
})
if err != nil {
t.Fatalf("run scenario fd-from-air-eventfd-users: %v", err)
}
AssertNoUnexpectedPID(t, result, pid)
AssertNoUnexpectedComm(t, result, "ioworkload")
AssertEventsPresent(t, result, []ExpectedEvent{
{Tracepoint: "enter_memfd_create", MinCount: 1},
{Tracepoint: "enter_memfd_secret", MinCount: 1},
{Tracepoint: "enter_userfaultfd", MinCount: 1},
{Tracepoint: "enter_signalfd", MinCount: 1},
{Tracepoint: "enter_signalfd4", MinCount: 1},
{Tracepoint: "enter_timerfd_create", MinCount: 1},
// The timerfd is armed and read back while still open, so
// timerfd_settime/gettime fire against the existing descriptor.
{Tracepoint: "enter_timerfd_settime", MinCount: 1},
{Tracepoint: "enter_timerfd_gettime", MinCount: 1},
})
assertTracepointPathPrefix(t, result, "enter_memfd_create", "memfd:")
assertTracepointPathPrefix(t, result, "enter_timerfd_create", "timerfd:")
// timerfd_settime/gettime take the timerfd as arg0 (kind=fd@arg0). The
// "timerfd:" path prefix proves the enter handlers captured that fd via
// fd_event rather than emitting a null event, locking in the 6ac9fa4 fix.
assertTracepointPathPrefix(t, result, "enter_timerfd_settime", "timerfd:")
assertTracepointPathPrefix(t, result, "enter_timerfd_gettime", "timerfd:")
}
// TestInotifyBasic asserts end-to-end tracing of the inotify IPC family.
// The inotify-basic scenario issues inotify_init1(IN_CLOEXEC) ->
// inotify_add_watch(fd, file, IN_CREATE|IN_DELETE|IN_MODIFY) ->
// inotify_rm_watch(fd, wd) -> close(fd). We assert all three inotify enter
// tracepoints fire at least once, with positive durations and the hermetic
// PID/comm guards already applied by runScenarioResultWithIorArgs. The
// inotify_init1 instance fd resolves to the "inotifyfd:" path label, and the
// close on that same fd carries the same label.
func TestInotifyBasic(t *testing.T) {
result, _ := runScenarioResultWithIorArgs(t, "inotify-basic", []ExpectedEvent{
{Tracepoint: "enter_inotify_init1", MinCount: 1},
{Tracepoint: "enter_inotify_add_watch", MinCount: 1},
{Tracepoint: "enter_inotify_rm_watch", MinCount: 1},
{Tracepoint: "enter_close", MinCount: 1},
}, inotifyTraceArgs)
// inotify_init1 returns a registered fd labelled inotifyfd:, and the
// subsequent close of that fd resolves to the same tracked label.
assertTracepointPathPrefix(t, result, "enter_inotify_init1", "inotifyfd:")
assertTracepointPathPrefix(t, result, "enter_close", "inotifyfd:")
// inotify_add_watch / inotify_rm_watch capture the inotify instance fd
// (kind=fd@arg0), so they too resolve to the tracked inotifyfd: label.
assertTracepointPathPrefix(t, result, "enter_inotify_add_watch", "inotifyfd:")
assertTracepointPathPrefix(t, result, "enter_inotify_rm_watch", "inotifyfd:")
assertEventDurationPositive(t, result, ExpectedEvent{Tracepoint: "enter_inotify_init1", Comm: "ioworkload"})
assertEventDurationPositive(t, result, ExpectedEvent{Tracepoint: "enter_inotify_add_watch", Comm: "ioworkload"})
assertEventDurationPositive(t, result, ExpectedEvent{Tracepoint: "enter_inotify_rm_watch", Comm: "ioworkload"})
}
func TestPosixMqBasic(t *testing.T) {
enableParallelIfRequested(t)
h := newTestHarness(t)
result, pid, err := h.Run("mq-posix-basic", defaultDuration)
if err != nil {
errText := err.Error()
if strings.Contains(errText, "mq_open: permission denied") ||
strings.Contains(errText, "mq_open: operation not permitted") ||
strings.Contains(errText, "mq_open: function not implemented") {
t.Skipf("mq syscalls unavailable in this environment: %v", err)
}
t.Fatalf("run scenario mq-posix-basic: %v", err)
}
AssertNoUnexpectedPID(t, result, pid)
AssertNoUnexpectedComm(t, result, "ioworkload")
AssertEventsPresent(t, result, []ExpectedEvent{
{Tracepoint: "enter_mq_open", MinCount: 1},
{Tracepoint: "enter_mq_unlink", MinCount: 1},
{Tracepoint: "enter_mq_timedsend", MinCount: 1},
{Tracepoint: "enter_mq_timedreceive", MinCount: 1},
{Tracepoint: "enter_mq_notify", MinCount: 1},
{Tracepoint: "enter_mq_getsetattr", MinCount: 1},
{Tracepoint: "enter_close", MinCount: 1},
})
assertTracepointPathPrefix(t, result, "enter_mq_open", "/ior-mq-")
assertTracepointPathPrefix(t, result, "enter_mq_unlink", "/ior-mq-")
assertTracepointPathPrefix(t, result, "enter_mq_timedsend", "/ior-mq-")
assertTracepointPathPrefix(t, result, "enter_mq_timedreceive", "/ior-mq-")
assertTracepointPathPrefix(t, result, "enter_mq_notify", "/ior-mq-")
assertTracepointPathPrefix(t, result, "enter_mq_getsetattr", "/ior-mq-")
assertTracepointPathPrefix(t, result, "enter_close", "/ior-mq-")
sendExp := ExpectedEvent{Tracepoint: "enter_mq_timedsend", Comm: "ioworkload", PathContains: "/ior-mq-"}
recvExp := ExpectedEvent{Tracepoint: "enter_mq_timedreceive", Comm: "ioworkload", PathContains: "/ior-mq-"}
// mq_timedsend returns 0 on success (a status, not a byte count), so it is
// UNCLASSIFIED and must NOT be attributed any write bytes. Only
// mq_timedreceive returns a real received byte count (ReadClassified).
assertEventBytesEqual(t, result, sendExp, 0)
assertEventBytesAtLeast(t, result, recvExp, mqPayloadLen)
assertEventDurationPositive(t, result, sendExp)
assertEventDurationPositive(t, result, recvExp)
}
|