[RFC PATCH 12/12] tracing: Pin recursion state for its complete lifetime
flat view
COOLING6d
From: Karl Mehltretter <hidden>
Date: 2026-10-22 05:18:18
Also in:
linux-arm-kernel, linux-doc, linux-rt-devel, lkml, llvm
Subsystem:
the rest, tracing · Maintainers:
Linus Torvalds, Steven Rostedt, Masami Hiramatsu
trace_test_and_set_recursion() publishes the task recursion bit before it disables preemption. Scheduler tracing can therefore run while acquisition is in progress. Conversely, trace_clear_recursion() enables preemption before clearing the bit, so a reschedule can observe stale recursion state during release. CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING also validates RCU state before the outer preemption disable. rcu_is_watching() drops its internal preemption reference before returning, and the warning path accesses TRACE_RECORD_RECURSION_BIT outside the protected lifetime. Disable preemption before validation and retain that reference until the recursion bit is cleared. Balance both rejection paths. This keeps validation and published recursion state inside one preemption-disabled interval. Keep the transition slot unchanged. It remains necessary for interrupt-entry intervals whose context is not yet reflected in preempt_count(). Use preempt_enable_notrace() because this inline API is also used by modules. The no-reschedule variant is unavailable there. Assisted-by: LLM --- include/linux/trace_recursion.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/include/linux/trace_recursion.h b/include/linux/trace_recursion.h
index e6ca052b2a85a..fd14380751404 100644
--- a/include/linux/trace_recursion.h
+++ b/include/linux/trace_recursion.h@@ -126,11 +126,16 @@ extern void ftrace_record_recursion(unsigned long ip, unsigned long parent_ip); static __always_inline int trace_test_and_set_recursion(unsigned long ip, unsigned long pip, int start) { - unsigned int val = READ_ONCE(current->trace_recursion); + unsigned int val; int bit; - if (trace_warn_on_no_rcu(ip)) + preempt_disable_notrace(); + if (trace_warn_on_no_rcu(ip)) { + preempt_enable_notrace(); return -1; + } + + val = READ_ONCE(current->trace_recursion); bit = trace_get_context_bit() + start; if (unlikely(val & (1 << bit))) {
@@ -145,6 +150,7 @@ static __always_inline int trace_test_and_set_recursion(unsigned long ip, unsign bit = TRACE_CTX_TRANSITION + start; if (val & (1 << bit)) { do_ftrace_record_recursion(ip, pip); + preempt_enable_notrace(); return -1; } }
@@ -153,8 +159,6 @@ static __always_inline int trace_test_and_set_recursion(unsigned long ip, unsign current->trace_recursion = val; barrier(); - preempt_disable_notrace(); - return bit; }
@@ -163,9 +167,9 @@ static __always_inline int trace_test_and_set_recursion(unsigned long ip, unsign */ static __always_inline void trace_clear_recursion(int bit) { - preempt_enable_notrace(); barrier(); trace_recursion_clear(bit); + preempt_enable_notrace(); } /**
--
2.39.5 (Apple Git-154)