Merge tag 'probes-v7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull probes fixes from Masami Hiramatsu:
 "fprobe bug fixes:

   - Prevent re-registration

     Add an earlier check to reject re-registering an already active
     fprobe before its state is modified during the initialization phase

   - Robustness in failure paths:
      - Ensure fprobes are correctly removed from all internal tables
        and properly RCU-freed during registration failure
      - Make unregister_fprobe() proceed with unregistration even if
        temporary memory allocation fails

   - RCU safety in module unloading

     Avoid a potential "sleep in RCU" warning by removing a kcalloc()
     call in the module notifier path. This also tries to remove
     fprobe_hash_node even if memory allocation fails.

   - Type-aware unregistration

     Fix a bug where unregistering an fprobe did not account for
     different types (entry-only vs entry-exit) at the same address,
     which previously left "junk" entries in the underlying
     ftrace/fgraph ops

   - Unregistration of empty ftrace_ops

     Avoid unneeded performance overhead due to making registered
     ftrace_ops empty - which means 'trace all functions'. This counts
     remaining entries and unregister ftrace_ops when it becomes empty.

  Two new selftests to check above fixes:

   - Module Unloading Test:

     Specifically verifies that fprobe events on a module are correctly
     cleaned up and do not trigger 'trace-all' behavior when the module
     is removed.

   - Multiple Fprobe Events Test:

     Ensure that having multiple fprobes on the same function correctly
     manages the ftrace hash map during removal"

* tag 'probes-v7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  selftests/ftrace: Add a testcase for multiple fprobe events
  selftests/ftrace: Add a testcase for fprobe events on module
  tracing/fprobe: Fix to unregister ftrace_ops if it is empty on module unloading
  tracing/fprobe: Check the same type fprobe on table as the unregistered one
  tracing/fprobe: Avoid kcalloc() in rcu_read_lock section
  tracing/fprobe: Remove fprobe from hash in failure path
  tracing/fprobe: Unregister fprobe even if memory allocation fails
  tracing/fprobe: Reject registration of a registered fprobe before init
This commit is contained in:
Linus Torvalds
2026-04-21 19:05:09 -07:00
3 changed files with 471 additions and 167 deletions

View File

@@ -0,0 +1,87 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove fprobe events on module
# requires: dynamic_events "f[:[<group>/][<event>]] <func-name>[%return] [<args>]":README enabled_functions
rmmod trace-events-sample ||:
if ! modprobe trace-events-sample ; then
echo "No trace-events sample module - please make CONFIG_SAMPLE_TRACE_EVENTS=m"
exit_unresolved;
fi
trap "lsmod | grep -q trace_events_sample && rmmod trace-events-sample" EXIT
echo 0 > events/enable
echo > dynamic_events
FUNC1='foo_bar*'
FUNC2='vfs_read'
:;: "Add an event on the test module" ;:
echo "f:test1 $FUNC1" >> dynamic_events
echo 1 > events/fprobes/test1/enable
:;: "Ensure it is enabled" ;:
funcs=`cat enabled_functions | wc -l`
test $funcs -ne 0
:;: "Check the enabled_functions is cleared on unloading" ;:
rmmod trace-events-sample
funcs=`cat enabled_functions | wc -l`
test $funcs -eq 0
:;: "Check it is kept clean" ;:
modprobe trace-events-sample
echo 1 > events/fprobes/test1/enable || echo "OK"
funcs=`cat enabled_functions | wc -l`
test $funcs -eq 0
:;: "Add another event not on the test module" ;:
echo "f:test2 $FUNC2" >> dynamic_events
echo 1 > events/fprobes/test2/enable
:;: "Ensure it is enabled" ;:
ofuncs=`cat enabled_functions | wc -l`
test $ofuncs -ne 0
:;: "Disable and remove the first event"
echo 0 > events/fprobes/test1/enable
echo "-:fprobes/test1" >> dynamic_events
funcs=`cat enabled_functions | wc -l`
test $ofuncs -eq $funcs
:;: "Disable and remove other events" ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
funcs=`cat enabled_functions | wc -l`
test $funcs -eq 0
rmmod trace-events-sample
:;: "Add events on kernel and test module" ;:
modprobe trace-events-sample
echo "f:test1 $FUNC1" >> dynamic_events
echo 1 > events/fprobes/test1/enable
echo "f:test2 $FUNC2" >> dynamic_events
echo 1 > events/fprobes/test2/enable
ofuncs=`cat enabled_functions | wc -l`
test $ofuncs -ne 0
:;: "Unload module (ftrace entry should be removed)" ;:
rmmod trace-events-sample
funcs=`cat enabled_functions | wc -l`
test $funcs -ne 0
test $ofuncs -ne $funcs
:;: "Disable and remove core-kernel fprobe event" ;:
echo 0 > events/fprobes/test2/enable
echo "-:fprobes/test2" >> dynamic_events
:;: "Ensure ftrace is disabled." ;:
funcs=`cat enabled_functions | wc -l`
test $funcs -eq 0
echo 0 > events/fprobes/enable
echo > dynamic_events
trap "" EXIT
clear_trace

View File

@@ -0,0 +1,69 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Generic dynamic event - add/remove multiple fprobe events on the same function
# requires: dynamic_events "f[:[<group>/][<event>]] <func-name>[%return] [<args>]":README enabled_functions
echo 0 > events/enable
echo > dynamic_events
PLACE=vfs_read
PLACE2=vfs_open
:;: 'Ensure no other ftrace user' ;:
test `cat enabled_functions | wc -l` -eq 0 || exit_unresolved
:;: 'Test case 1: leave entry event' ;:
:;: 'Add entry and exit events on the same place' ;:
echo "f:event1 ${PLACE}" >> dynamic_events
echo "f:event2 ${PLACE}%return" >> dynamic_events
:;: 'Enable both of them' ;:
echo 1 > events/fprobes/enable
test `cat enabled_functions | wc -l` -eq 1
:;: 'Disable and remove exit event' ;:
echo 0 > events/fprobes/event2/enable
echo -:event2 >> dynamic_events
:;: 'Disable and remove all events' ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
:;: 'Add another event' ;:
echo "f:event3 ${PLACE2}%return" > dynamic_events
echo 1 > events/fprobes/enable
test `cat enabled_functions | wc -l` -eq 1
:;: 'No other ftrace user' ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
test `cat enabled_functions | wc -l` -eq 0
:;: 'Test case 2: leave exit event' ;:
:;: 'Add entry and exit events on the same place' ;:
echo "f:event1 ${PLACE}" >> dynamic_events
echo "f:event2 ${PLACE}%return" >> dynamic_events
:;: 'Enable both of them' ;:
echo 1 > events/fprobes/enable
test `cat enabled_functions | wc -l` -eq 1
:;: 'Disable and remove entry event' ;:
echo 0 > events/fprobes/event1/enable
echo -:event1 >> dynamic_events
:;: 'Disable and remove all events' ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
:;: 'Add another event' ;:
echo "f:event3 ${PLACE2}" > dynamic_events
echo 1 > events/fprobes/enable
test `cat enabled_functions | wc -l` -eq 1
:;: 'No other ftrace user' ;:
echo 0 > events/fprobes/enable
echo > dynamic_events
test `cat enabled_functions | wc -l` -eq 0
clear_trace