-
Notifications
You must be signed in to change notification settings - Fork 4k
libbpf-tools/klockstat: Support nested mutex_trylock #5461
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -103,7 +103,9 @@ static const char *lock_ksym_names[] = { | |||||||||||||||||||
| "mutex_lock_interruptible_nested", | ||||||||||||||||||||
| "mutex_lock_killable", | ||||||||||||||||||||
| "mutex_lock_killable_nested", | ||||||||||||||||||||
| "_mutex_lock_killable", | ||||||||||||||||||||
| "mutex_trylock", | ||||||||||||||||||||
| "_mutex_trylock_nest_lock", | ||||||||||||||||||||
| "down_read", | ||||||||||||||||||||
| "down_read_nested", | ||||||||||||||||||||
| "down_read_interruptible", | ||||||||||||||||||||
|
|
@@ -775,8 +777,6 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va | |||||||||||||||||||
|
|
||||||||||||||||||||
| static void enable_fentry(struct klockstat_bpf *obj) | ||||||||||||||||||||
| { | ||||||||||||||||||||
| bool debug_lock; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_exit, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_trylock, false); | ||||||||||||||||||||
|
|
@@ -804,22 +804,6 @@ static void enable_fentry(struct klockstat_bpf *obj) | |||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write_killable_exit, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_up_write, false); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_exit_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_interruptible_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_interruptible_exit_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_killable_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_killable_exit_nested, false); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_read_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_read_exit_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_read_killable_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_read_killable_exit_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write_exit_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write_killable_nested, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write_killable_exit_nested, false); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_rtnetlink_rcv_msg, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_rtnetlink_rcv_msg_exit, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_netlink_dump, false); | ||||||||||||||||||||
|
|
@@ -828,8 +812,7 @@ static void enable_fentry(struct klockstat_bpf *obj) | |||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_sock_do_ioctl_exit, false); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /* CONFIG_DEBUG_LOCK_ALLOC is on */ | ||||||||||||||||||||
| debug_lock = fentry_can_attach("mutex_lock_nested", NULL); | ||||||||||||||||||||
| if (!debug_lock) | ||||||||||||||||||||
| if (!fentry_can_attach("mutex_lock_nested", NULL)) | ||||||||||||||||||||
| return; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.mutex_lock, 0, | ||||||||||||||||||||
|
|
@@ -857,10 +840,24 @@ static void enable_fentry(struct klockstat_bpf *obj) | |||||||||||||||||||
| "down_write_nested"); | ||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.down_write_exit, 0, | ||||||||||||||||||||
| "down_write_nested"); | ||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.down_write_killable, 0, | ||||||||||||||||||||
| "down_write_killable_nested"); | ||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.down_write_killable_exit, 0, | ||||||||||||||||||||
| "down_write_killable_nested"); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /* Since v6.16 mutex_lock_killable nested variant is implemented differently */ | ||||||||||||||||||||
| if (fentry_can_attach("_mutex_lock_killable", NULL)) { | ||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.mutex_lock_killable, 0, | ||||||||||||||||||||
| "_mutex_lock_killable"); | ||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.mutex_lock_killable_exit, 0, | ||||||||||||||||||||
| "_mutex_lock_killable"); | ||||||||||||||||||||
| } else { | ||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.down_write_killable, 0, | ||||||||||||||||||||
| "down_write_killable_nested"); | ||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.down_write_killable_exit, 0, | ||||||||||||||||||||
| "down_write_killable_nested"); | ||||||||||||||||||||
|
Comment on lines
+850
to
+854
|
||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /* Since v6.16 mutex_trylock also have a nested variant */ | ||||||||||||||||||||
| if (fentry_can_attach("_mutex_trylock_nest_lock", NULL)) | ||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.mutex_trylock_exit, 0, | ||||||||||||||||||||
| "_mutex_trylock_nest_lock"); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| static void enable_kprobes(struct klockstat_bpf *obj) | ||||||||||||||||||||
|
|
@@ -897,39 +894,52 @@ static void enable_kprobes(struct klockstat_bpf *obj) | |||||||||||||||||||
| bpf_program__set_autoload(obj->progs.sock_do_ioctl_exit, false); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /* CONFIG_DEBUG_LOCK_ALLOC is on */ | ||||||||||||||||||||
| if (kprobe_exists("mutex_lock_nested")) { | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_exit, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_interruptible, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_interruptible_exit, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_killable, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_killable_exit, false); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_read, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_read_exit, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_read_killable, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_read_killable_exit, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write_exit, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write_killable, false); | ||||||||||||||||||||
| bpf_program__set_autoload(obj->progs.kprobe_down_write_killable_exit, false); | ||||||||||||||||||||
| if (!kprobe_exists("mutex_lock_nested")) | ||||||||||||||||||||
| return; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.mutex_lock, 0, | ||||||||||||||||||||
|
||||||||||||||||||||
| bpf_program__set_attach_target(obj->progs.mutex_lock, 0, | |
| bpf_program__set_attach_target(obj->progs.kprobe_mutex_lock, 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes indeed, that's a typo. Will fix.
Copilot
AI
Mar 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In enable_kprobes(), when _mutex_lock_killable exists you’re calling bpf_program__set_attach_target() on the fentry mutex_lock_killable programs, but those were set to autoload=false at the top of enable_kprobes(). This means kprobe_mutex_lock_killable(_exit) will still attach to the old symbol and miss nested killable locks on newer kernels. Please retarget the kprobe mutex_lock_killable entry/exit programs to _mutex_lock_killable instead.
| bpf_program__set_attach_target(obj->progs.mutex_lock_killable, 0, | |
| "_mutex_lock_killable"); | |
| bpf_program__set_attach_target(obj->progs.mutex_lock_killable_exit, 0, | |
| bpf_program__set_attach_target(obj->progs.kprobe_mutex_lock_killable, 0, | |
| "_mutex_lock_killable"); | |
| bpf_program__set_attach_target(obj->progs.kprobe_mutex_lock_killable_exit, 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Obviously some sloppy copy and paste business on my part. My bad! Will fix.
Copilot
AI
Mar 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In enable_kprobes(), retargeting down_write_killable(_exit) to down_write_killable_nested is currently inside the else branch of the _mutex_lock_killable check. down_write_killable_nested selection shouldn’t depend on whether _mutex_lock_killable exists; on kernels where _mutex_lock_killable exists, down_write_killable(_exit) will remain attached to non-nested symbols. Please move the down_write_killable(_exit) retargeting out of this conditional (or duplicate it in both branches).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as above. Same fix.
Copilot
AI
Mar 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In enable_kprobes(), the nested mutex_trylock handling is retargeting obj->progs.mutex_trylock_exit (fexit program) even though enable_kprobes() disables autoload for that program. It also retargets only the exit side; for kprobe/kretprobe pairs you need both entry and exit attached to the same target to keep the per-thread lock map consistent. Please retarget kprobe_mutex_trylock and kprobe_mutex_trylock_exit to _mutex_trylock_nest_lock when present.
| if (kprobe_exists("_mutex_trylock_nest_lock")) | |
| bpf_program__set_attach_target(obj->progs.mutex_trylock_exit, 0, | |
| "_mutex_trylock_nest_lock"); | |
| if (kprobe_exists("_mutex_trylock_nest_lock")) { | |
| bpf_program__set_attach_target(obj->progs.kprobe_mutex_trylock, 0, | |
| "_mutex_trylock_nest_lock"); | |
| bpf_program__set_attach_target(obj->progs.kprobe_mutex_trylock_exit, 0, | |
| "_mutex_trylock_nest_lock"); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. the *_trylock mutexes only have an exit version in the fentry case, not the kprobe one. Will fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_mutex_lock_killable handling is inside DEBUG-only section.
This function exists in all kernels >= 6.16 (not debug-specific) ?
Line 849 may also need to be adjusted depending on line 877.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see it in /proc/kallsyms on a non-debug kernel and both definitions of _mutex_lock_killable(), in mutex.c and rtmutex_api.c are inside a #ifdef CONFIG_DEBUG_LOCK_ALLOC section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. I'll update the pull request soon with your suggestion.