Skip to content

Commit 92e32ff

Browse files
authored
examples/tracing/bitehist.py: Fix kprobe attaching failure (#5223)
Fix the same issue as the commit cccb26e fixed for disksnoop.py previously. blk_account_io_done became inline function since kernel v5.16 and blk_account_io_done has been taken off since v6.4. With this change, only when the code runs on a legacy kernel these *_io_done functions will be attached, otherwise it goes for blk_mq_end_request. The tutorial lessons for both bitehist.py and disksnoop.py are updated accordingly. Signed-off-by: Wei <[email protected]>
1 parent 62178b9 commit 92e32ff

File tree

2 files changed

+23
-3
lines changed

2 files changed

+23
-3
lines changed

docs/tutorial_bcc_python_developer.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,15 @@ void trace_completion(struct pt_regs *ctx, struct request *req) {
227227
if BPF.get_kprobe_functions(b'blk_start_request'):
228228
b.attach_kprobe(event="blk_start_request", fn_name="trace_start")
229229
b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_start")
230+
230231
if BPF.get_kprobe_functions(b'__blk_account_io_done'):
232+
# __blk_account_io_done is available before kernel v6.4.
231233
b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_completion")
232-
else:
234+
elif BPF.get_kprobe_functions(b'blk_account_io_done'):
235+
# blk_account_io_done is traceable (not inline) before v5.16.
233236
b.attach_kprobe(event="blk_account_io_done", fn_name="trace_completion")
237+
else:
238+
b.attach_kprobe(event="blk_mq_end_request", fn_name="trace_completion")
234239
[...]
235240
```
236241

@@ -240,6 +245,7 @@ Things to learn:
240245
1. ```trace_start(struct pt_regs *ctx, struct request *req)```: This function will later be attached to kprobes. The arguments to kprobe functions are ```struct pt_regs *ctx```, for registers and BPF context, and then the actual arguments to the function. We'll attach this to blk_start_request(), where the first argument is ```struct request *```.
241246
1. ```start.update(&req, &ts)```: We're using the pointer to the request struct as a key in our hash. What? This is commonplace in tracing. Pointers to structs turn out to be great keys, as they are unique: two structs can't have the same pointer address. (Just be careful about when it gets free'd and reused.) So what we're really doing is tagging the request struct, which describes the disk I/O, with our own timestamp, so that we can time it. There's two common keys used for storing timestamps: pointers to structs, and, thread IDs (for timing function entry to return).
242247
1. ```req->__data_len```: We're dereferencing members of ```struct request```. See its definition in the kernel source for what members are there. bcc actually rewrites these expressions to be a series of ```bpf_probe_read_kernel()``` calls. Sometimes bcc can't handle a complex dereference, and you need to call ```bpf_probe_read_kernel()``` directly.
248+
1. ```if BPF.get_kprobe_functions(b'__blk_account_io_done'):...```: Different functions are attached here depending on kernel versions. Legacy functions ```__blk_account_io_done``` and ```blk_account_io_done``` are not available on newer kernels, so instead, we use ```blk_mq_end_request``` as a workaround.
243249

244250
This is a pretty interesting program, and if you can understand all the code, you'll understand many important basics. We're still using the bpf_trace_printk() hack, so let's fix that next.
245251

@@ -368,6 +374,15 @@ int kprobe__blk_account_io_done(struct pt_regs *ctx, struct request *req)
368374
}
369375
""")
370376

377+
if BPF.get_kprobe_functions(b'__blk_account_io_done'):
378+
# __blk_account_io_done is available before kernel v6.4.
379+
b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_done")
380+
elif BPF.get_kprobe_functions(b'blk_account_io_done'):
381+
# blk_account_io_done is traceable (not inline) before v5.16.
382+
b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_done")
383+
else:
384+
b.attach_kprobe(event="blk_mq_end_request", fn_name="trace_req_done")
385+
371386
# header
372387
print("Tracing... Hit Ctrl-C to end.")
373388

examples/tracing/bitehist.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/python
1+
#!/usr/bin/python3
22
#
33
# bitehist.py Block I/O size histogram.
44
# For Linux, uses BCC, eBPF. Embedded C.
@@ -12,6 +12,7 @@
1212
#
1313
# 15-Aug-2015 Brendan Gregg Created this.
1414
# 03-Feb-2019 Xiaozhou Liu added linear histogram.
15+
# 02-Mar-2025 Wei Use blk_mq_end_request for newer kernel.
1516

1617
from __future__ import print_function
1718
from bcc import BPF
@@ -34,9 +35,13 @@
3435
""")
3536

3637
if BPF.get_kprobe_functions(b'__blk_account_io_done'):
38+
# __blk_account_io_done is available before kernel v6.4.
3739
b.attach_kprobe(event="__blk_account_io_done", fn_name="trace_req_done")
38-
else:
40+
elif BPF.get_kprobe_functions(b'blk_account_io_done'):
41+
# blk_account_io_done is traceable (not inline) before v5.16.
3942
b.attach_kprobe(event="blk_account_io_done", fn_name="trace_req_done")
43+
else:
44+
b.attach_kprobe(event="blk_mq_end_request", fn_name="trace_req_done")
4045

4146
# header
4247
print("Tracing... Hit Ctrl-C to end.")

0 commit comments

Comments
 (0)