Skip to content

Commit 3630581

Browse files
tools/{biolatency,biosnoop,biotop}: use TRACEPOINT_PROBE() for tracepoints (#5366)
When support for block_io_* tracepoint was added, it used attach_tracepoint() since it was closer to the existing code that attached to kprobes. However, that meant we have to rely on a local prototype of the args structure and the tool can be broken by a change of the tracepoints format, which is what happens with kernel commit aa6ff4eb7c10d ("block: Add ioprio to block_rq tracepoint") which added a new argument to block tracepoints. Replace attach_tracepoint() by TRACEPOINT_PROBE() so we don't have to deal with the tracepoint format changes. Signed-off-by: Jerome Marchand <[email protected]>
1 parent c8ad35a commit 3630581

File tree

3 files changed

+141
-128
lines changed

3 files changed

+141
-128
lines changed

tools/biolatency.py

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,6 @@
8787
u64 count;
8888
} ext_val_t;
8989
90-
struct tp_args {
91-
u64 __unused__;
92-
dev_t dev;
93-
sector_t sector;
94-
unsigned int nr_sector;
95-
unsigned int bytes;
96-
char rwbs[8];
97-
char comm[16];
98-
char cmd[];
99-
};
100-
10190
struct start_key {
10291
dev_t dev;
10392
u32 _pad;
@@ -134,16 +123,6 @@
134123
return __trace_req_start(key);
135124
}
136125
137-
int trace_req_start_tp(struct tp_args *args)
138-
{
139-
struct start_key key = {
140-
.dev = args->dev,
141-
.sector = args->sector
142-
};
143-
144-
return __trace_req_start(key);
145-
}
146-
147126
// output
148127
static int __trace_req_done(struct start_key key)
149128
{
@@ -176,8 +155,22 @@
176155
177156
return __trace_req_done(key);
178157
}
158+
"""
159+
160+
tp_start_text = """
161+
TRACEPOINT_PROBE(block, START_TP)
162+
{
163+
struct start_key key = {
164+
.dev = args->dev,
165+
.sector = args->sector
166+
};
167+
168+
return __trace_req_start(key);
169+
}
170+
"""
179171

180-
int trace_req_done_tp(struct tp_args *args)
172+
tp_done_text = """
173+
TRACEPOINT_PROBE(block, DONE_TP)
181174
{
182175
struct start_key key = {
183176
.dev = args->dev,
@@ -266,41 +259,54 @@
266259
if args.ebpf:
267260
exit()
268261

269-
# load BPF program
270-
b = BPF(text=bpf_text)
262+
# Which kprobe/tracepoint to attach to.
263+
# We can attach to two IO start kprobes but only one of the other types.
264+
kprobe_start = set()
265+
tp_start = None
266+
kprobe_done = None
267+
tp_done = None
268+
271269
if args.queued:
272-
if BPF.tracepoint_exists("block", "block_io_start"):
273-
b.attach_tracepoint(tp="block:block_io_start", fn_name="trace_req_start_tp")
274-
elif BPF.get_kprobe_functions(b'__blk_account_io_start'):
275-
b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_req_start")
270+
if BPF.get_kprobe_functions(b'__blk_account_io_start'):
271+
kprobe_start.add("__blk_account_io_start")
276272
elif BPF.get_kprobe_functions(b'blk_account_io_start'):
277-
b.attach_kprobe(event="blk_account_io_start", fn_name="trace_req_start")
273+
kprobe_start.add("blk_account_io_start")
274+
elif BPF.tracepoint_exists("block", "block_io_start"):
275+
tp_start = "block_io_start"
278276
elif BPF.tracepoint_exists("block", "block_bio_queue"):
279-
b.attach_tracepoint(tp="block:block_bio_queue", fn_name="trace_req_start_tp")
280-
else:
281-
if args.flags:
282-
# Some flags are accessible in the rwbs field (RAHEAD, SYNC and META)
283-
# but other aren't. Disable the -F option for tracepoint for now.
284-
print("ERROR: blk_account_io_start probe not available. Can't use -F.")
285-
exit()
277+
tp_start = "block_bio_queue"
278+
286279
else:
287280
if BPF.get_kprobe_functions(b'blk_start_request'):
288-
b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
289-
b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
281+
kprobe_start.add("blk_start_request")
282+
kprobe_start.add("blk_mq_start_request")
290283

291-
if BPF.tracepoint_exists("block", "block_io_done"):
292-
b.attach_tracepoint(tp="block:block_io_done", fn_name="trace_req_done_tp")
293-
elif BPF.get_kprobe_functions(b'__blk_account_io_done'):
294-
b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_done")
284+
if BPF.get_kprobe_functions(b'__blk_account_io_done'):
285+
kprobe_done = "__blk_account_io_done"
295286
elif BPF.get_kprobe_functions(b'blk_account_io_done'):
296-
b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_done")
287+
kprobe_done = "blk_account_io_done"
288+
elif BPF.tracepoint_exists("block", "block_io_done"):
289+
tp_done = "block_io_done"
297290
elif BPF.tracepoint_exists("block", "block_rq_complete"):
298-
b.attach_tracepoint(tp="block:block_rq_complete", fn_name="trace_req_done_tp")
299-
else:
300-
if args.flags:
301-
print("ERROR: blk_account_io_done probe not available. Can't use -F.")
302-
exit()
291+
tp_done = "block_rq_complete"
292+
293+
if args.flags and (tp_start or tp_done):
294+
# Some flags are accessible in the rwbs field (RAHEAD, SYNC and META)
295+
# but other aren't. Disable the -F option for tracepoint for now.
296+
print("ERROR: blk_account_io_start/done probes not available. Can't use -F.")
297+
exit()
298+
299+
if tp_start:
300+
bpf_text += tp_start_text.replace("START_TP", tp_start)
301+
if tp_done:
302+
bpf_text += tp_done_text.replace("DONE_TP", tp_done)
303303

304+
# load BPF program
305+
b = BPF(text=bpf_text)
306+
for i in kprobe_start:
307+
b.attach_kprobe(event=i, fn_name="trace_req_start")
308+
if kprobe_done:
309+
b.attach_kprobe(event=kprobe_done, fn_name="trace_req_done")
304310

305311
if not args.json:
306312
print("Tracing block device I/O... Hit Ctrl-C to end.")

tools/biosnoop.py

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,6 @@
6565
char name[TASK_COMM_LEN];
6666
};
6767
68-
struct tp_args {
69-
u64 __unused__;
70-
dev_t dev;
71-
sector_t sector;
72-
unsigned int nr_sector;
73-
unsigned int bytes;
74-
char rwbs[8];
75-
char comm[16];
76-
char cmd[];
77-
};
78-
7968
struct hash_key {
8069
dev_t dev;
8170
u32 rwflag;
@@ -182,17 +171,6 @@
182171
return __trace_pid_start(key);
183172
}
184173
185-
int trace_pid_start_tp(struct tp_args *args)
186-
{
187-
struct hash_key key = {
188-
.dev = args->dev,
189-
.rwflag = get_rwflag_tp(args->rwbs),
190-
.sector = args->sector
191-
};
192-
193-
return __trace_pid_start(key);
194-
}
195-
196174
// time block I/O
197175
int trace_req_start(struct pt_regs *ctx, struct request *req)
198176
{
@@ -284,8 +262,23 @@
284262
285263
return __trace_req_completion(ctx, key);
286264
}
265+
"""
287266

288-
int trace_req_completion_tp(struct tp_args *args)
267+
tp_start_text = """
268+
TRACEPOINT_PROBE(block, block_io_start)
269+
{
270+
struct hash_key key = {
271+
.dev = args->dev,
272+
.rwflag = get_rwflag_tp(args->rwbs),
273+
.sector = args->sector
274+
};
275+
276+
return __trace_pid_start(key);
277+
}
278+
"""
279+
280+
tp_done_text = """
281+
TRACEPOINT_PROBE(block, block_io_done)
289282
{
290283
struct hash_key key = {
291284
.dev = args->dev,
@@ -296,6 +289,7 @@
296289
return __trace_req_completion(args, key);
297290
}
298291
"""
292+
299293
if args.queue:
300294
bpf_text = bpf_text.replace('##QUEUE##', '1')
301295
else:
@@ -329,31 +323,41 @@
329323
if args.ebpf:
330324
exit()
331325

332-
# initialize BPF
333-
b = BPF(text=bpf_text)
334326
if BPF.tracepoint_exists("block", "block_io_start"):
335-
b.attach_tracepoint(tp="block:block_io_start", fn_name="trace_pid_start_tp")
336-
elif BPF.get_kprobe_functions(b'__blk_account_io_start'):
337-
b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start")
338-
elif BPF.get_kprobe_functions(b'blk_account_io_start'):
339-
b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start")
327+
bpf_text += tp_start_text
328+
tp_start = True
329+
else:
330+
tp_start = False
331+
332+
if BPF.tracepoint_exists("block", "block_io_done"):
333+
bpf_text += tp_done_text
334+
tp_done = True
340335
else:
341-
print("ERROR: No found any block io start probe/tp.")
342-
exit()
336+
tp_done = False
337+
338+
# initialize BPF
339+
b = BPF(text=bpf_text)
340+
if not tp_start:
341+
if BPF.get_kprobe_functions(b'__blk_account_io_start'):
342+
b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start")
343+
elif BPF.get_kprobe_functions(b'blk_account_io_start'):
344+
b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start")
345+
else:
346+
print("ERROR: No found any block io start probe/tp.")
347+
exit()
343348

344349
if BPF.get_kprobe_functions(b'blk_start_request'):
345350
b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
346351
b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
347352

348-
if BPF.tracepoint_exists("block", "block_io_done"):
349-
b.attach_tracepoint(tp="block:block_io_done", fn_name="trace_req_completion_tp")
350-
elif BPF.get_kprobe_functions(b'__blk_account_io_done'):
351-
b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion")
352-
elif BPF.get_kprobe_functions(b'blk_account_io_done'):
353-
b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion")
354-
else:
355-
print("ERROR: No found any block io done probe/tp.")
356-
exit()
353+
if not tp_done:
354+
if BPF.get_kprobe_functions(b'__blk_account_io_done'):
355+
b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion")
356+
elif BPF.get_kprobe_functions(b'blk_account_io_done'):
357+
b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion")
358+
else:
359+
print("ERROR: No found any block io done probe/tp.")
360+
exit()
357361

358362

359363
# header

tools/biotop.py

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,6 @@
9090
u32 io;
9191
};
9292
93-
struct tp_args {
94-
u64 __unused__;
95-
dev_t dev;
96-
sector_t sector;
97-
unsigned int nr_sector;
98-
unsigned int bytes;
99-
char rwbs[8];
100-
char comm[16];
101-
char cmd[];
102-
};
103-
10493
struct hash_key {
10594
dev_t dev;
10695
u32 _pad;
@@ -143,16 +132,6 @@
143132
return __trace_pid_start(key);
144133
}
145134
146-
int trace_pid_start_tp(struct tp_args *args)
147-
{
148-
struct hash_key key = {
149-
.dev = args->dev,
150-
.sector = args->sector
151-
};
152-
153-
return __trace_pid_start(key);
154-
}
155-
156135
// time block I/O
157136
int trace_req_start(struct pt_regs *ctx, struct request *req)
158137
{
@@ -246,8 +225,22 @@
246225
247226
return __trace_req_completion(key);
248227
}
228+
"""
229+
230+
tp_start_text = """
231+
TRACEPOINT_PROBE(block, block_io_start)
232+
{
233+
struct hash_key key = {
234+
.dev = args->dev,
235+
.sector = args->sector
236+
};
237+
238+
return __trace_pid_start(key);
239+
}
240+
"""
249241

250-
int trace_req_completion_tp(struct tp_args *args)
242+
tp_done_text = """
243+
TRACEPOINT_PROBE(block, block_io_done)
251244
{
252245
struct hash_key key = {
253246
.dev = args->dev,
@@ -272,30 +265,40 @@
272265
else:
273266
bpf_text = bpf_text.replace('FILTER_PID', '0')
274267

275-
b = BPF(text=bpf_text)
276268
if BPF.tracepoint_exists("block", "block_io_start"):
277-
b.attach_tracepoint(tp="block:block_io_start", fn_name="trace_pid_start_tp")
278-
elif BPF.get_kprobe_functions(b'__blk_account_io_start'):
279-
b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start")
280-
elif BPF.get_kprobe_functions(b'blk_account_io_start'):
281-
b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start")
269+
bpf_text += tp_start_text
270+
tp_start = True
282271
else:
283-
print("ERROR: No found any block io start probe/tp.")
284-
exit()
272+
tp_start = False
273+
274+
if BPF.tracepoint_exists("block", "block_io_done"):
275+
bpf_text += tp_done_text
276+
tp_done = True
277+
else:
278+
tp_done = False
279+
280+
b = BPF(text=bpf_text)
281+
if not tp_start:
282+
if BPF.get_kprobe_functions(b'__blk_account_io_start'):
283+
b.attach_kprobe(event="__blk_account_io_start", fn_name="trace_pid_start")
284+
elif BPF.get_kprobe_functions(b'blk_account_io_start'):
285+
b.attach_kprobe(event="blk_account_io_start", fn_name="trace_pid_start")
286+
else:
287+
print("ERROR: No found any block io start probe/tp.")
288+
exit()
285289

286290
if BPF.get_kprobe_functions(b'blk_start_request'):
287291
b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
288292
b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
289293

290-
if BPF.tracepoint_exists("block", "block_io_done"):
291-
b.attach_tracepoint(tp="block:block_io_done", fn_name="trace_req_completion_tp")
292-
elif BPF.get_kprobe_functions(b'__blk_account_io_done'):
293-
b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion")
294-
elif BPF.get_kprobe_functions(b'blk_account_io_done'):
295-
b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion")
296-
else:
297-
print("ERROR: No found any block io done probe/tp.")
298-
exit()
294+
if not tp_done:
295+
if BPF.get_kprobe_functions(b'__blk_account_io_done'):
296+
b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_completion")
297+
elif BPF.get_kprobe_functions(b'blk_account_io_done'):
298+
b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_completion")
299+
else:
300+
print("ERROR: No found any block io done probe/tp.")
301+
exit()
299302

300303
# check whether hash table batch ops is supported
301304
htab_batch_ops = True if BPF.kernel_struct_has_field(b'bpf_map_ops',

0 commit comments

Comments
 (0)