From: "Paul E. McKenney" <paulmck@kernel.org>
To: Josef Bacik <josef@toxicpanda.com>
Cc: Frederic Weisbecker <frederic@kernel.org>,
Neeraj Upadhyay <neeraj.upadhyay@kernel.org>,
Joel Fernandes <joelagnelf@nvidia.com>,
Boqun Feng <boqun@kernel.org>, Thomas Gleixner <tglx@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Steven Rostedt <rostedt@goodmis.org>,
Masami Hiramatsu <mhiramat@kernel.org>,
Mark Rutland <mark.rutland@arm.com>, Jiri Olsa <jolsa@kernel.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
x86@kernel.org, Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Puranjay Mohan <puranjay@kernel.org>,
Xu Kuohai <xukuohai@huaweicloud.com>,
Andy Lutomirski <luto@kernel.org>,
Josh Triplett <josh@joshtriplett.org>,
Uladzislau Rezki <urezki@gmail.com>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
Lai Jiangshan <jiangshanlai@gmail.com>,
Zqiang <qiang.zhang@linux.dev>, Juergen Gross <jgross@suse.com>,
Luis Chamberlain <mcgrof@kernel.org>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
linux-kernel@vger.kernel.org, rcu@vger.kernel.org,
linux-trace-kernel@vger.kernel.org, bpf@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
xen-devel@lists.xenproject.org
Subject: Re: [PATCH RFC v2 01/15] rcu-tasks: Add per-task trampoline nesting count
Date: Fri, 11 Sep 2026 10:23:16 -0700 [thread overview]
Message-ID: <90c2dfbe-e796-4125-b178-e854b40f68cd@paulmck-laptop> (raw)
In-Reply-To: <20260911-b4-rcu-tasks-preempt-qs-v2-1-eaaa61ed2da4@toxicpanda.com>
On Fri, Sep 11, 2026 at 02:08:39PM +0000, Josef Bacik wrote:
> Tasks RCU exists so that ftrace, BPF and kprobes can free trampoline
> text once no task can still be executing in it. Today the only way a
> task tells Tasks RCU "I am not in a trampoline" is a voluntary context
> switch, so a preempted task is always assumed to be inside one.
>
> Add task_struct::rcu_tramp_nesting so that trampolines can say so
> directly: a trampoline increments it before calling out and decrements
> it before returning, and while it is non-zero the task must not be
> treated as Tasks-RCU quiescent. Provide rcu_tasks_trampoline_enter()
> and rcu_tasks_trampoline_exit() for C users, report the count in the
> Tasks RCU stall output, and, under CONFIG_PROVE_RCU, assert that it is
> zero on every return to userspace since no task can legitimately reach
> userspace with a trampoline on its stack.
>
> Only current ever writes the count and every nested user (interrupts
> running their own trampolines) is balanced, so plain accesses suffice.
>
> The callbacks reached from static trampolines (return_to_handler, the
> rethook and kretprobe trampolines) are covered by the preempt_disable()
> in the ftrace recursion protection rather than by the count; note that
> dependency in trace_recursion.h so it is not lost if the
> preempt_disable() is ever removed from there.
>
> Nothing increments the count and nothing consults it for quiescent-state
> decisions yet; both come in later patches.
>
> Assisted-by: LLM
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Please see below for a line-saving nit.
Thanx, Paul
> ---
> include/linux/irq-entry-common.h | 2 ++
> include/linux/rcupdate.h | 37 +++++++++++++++++++++++++++++++++++++
> include/linux/sched.h | 1 +
> include/linux/trace_recursion.h | 11 +++++++++++
> kernel/fork.c | 1 +
> kernel/rcu/tasks.h | 3 ++-
> 6 files changed, 54 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/irq-entry-common.h b/include/linux/irq-entry-common.h
> index 0bb6c03481fa..8da571622000 100644
> --- a/include/linux/irq-entry-common.h
> +++ b/include/linux/irq-entry-common.h
> @@ -5,6 +5,7 @@
> #include <linux/context_tracking.h>
> #include <linux/hrtimer_rearm.h>
> #include <linux/kmsan.h>
> +#include <linux/rcupdate.h>
> #include <linux/rseq_entry.h>
> #include <linux/static_call_types.h>
> #include <linux/syscalls.h>
> @@ -214,6 +215,7 @@ static __always_inline void __exit_to_user_mode_validate(void)
> {
> /* Ensure that kernel state is sane for a return to userspace */
> kmap_assert_nomap();
> + rcu_tasks_trampoline_assert_none();
> lockdep_assert_irqs_disabled();
> lockdep_sys_exit();
> }
> diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
> index 44c07a66edff..b5c666c82479 100644
> --- a/include/linux/rcupdate.h
> +++ b/include/linux/rcupdate.h
> @@ -180,6 +180,37 @@ static inline void rcu_nocb_flush_deferred_wakeup(void) { }
> #ifdef CONFIG_TASKS_RCU_GENERIC
>
> # ifdef CONFIG_TASKS_RCU
> +
> +/*
> + * Trampoline nesting: dynamically allocated text (ftrace trampolines, BPF
> + * trampoline images, kprobe optinsn slots) that relies on Tasks RCU for its
> + * lifetime brackets itself with an increment/decrement of
> + * current->rcu_tramp_nesting. While the count is non-zero the task is inside,
> + * or was called from, such text and an involuntary context switch must not be
> + * treated as a Tasks RCU quiescent state.
> + *
> + * Only current writes the count and only current (or an interrupt on the same
> + * CPU) reads it, so plain accesses suffice.
> + */
> +static __always_inline void rcu_tasks_trampoline_enter(void)
> +{
> + current->rcu_tramp_nesting++;
> + barrier();
> +}
> +
> +static __always_inline void rcu_tasks_trampoline_exit(void)
> +{
> + barrier();
> + current->rcu_tramp_nesting--;
> +}
> +
> +/* A task must never reach userspace with a trampoline on its stack. */
> +static __always_inline void rcu_tasks_trampoline_assert_none(void)
> +{
> + if (IS_ENABLED(CONFIG_PROVE_RCU))
> + WARN_ON_ONCE(current->rcu_tramp_nesting);
Save a line as follows?
WARN_ON_ONCE(IS_ENABLED(CONFIG_PROVE_RCU) && current->rcu_tramp_nesting);
> +}
> +
> # define rcu_tasks_classic_qs(t, preempt) \
> do { \
> if (!(preempt) && READ_ONCE((t)->rcu_tasks_holdout)) \
> @@ -192,6 +223,9 @@ void rcu_tasks_torture_stats_print(char *tt, char *tf);
> # define rcu_tasks_classic_qs(t, preempt) do { } while (0)
> # define call_rcu_tasks call_rcu
> # define synchronize_rcu_tasks synchronize_rcu
> +static inline void rcu_tasks_trampoline_enter(void) { }
> +static inline void rcu_tasks_trampoline_exit(void) { }
> +static inline void rcu_tasks_trampoline_assert_none(void) { }
> # endif
>
> #define rcu_tasks_qs(t, preempt) rcu_tasks_classic_qs((t), (preempt))
> @@ -208,6 +242,9 @@ void exit_tasks_rcu_finish(void);
> #define rcu_tasks_classic_qs(t, preempt) do { } while (0)
> #define rcu_tasks_qs(t, preempt) do { } while (0)
> #define rcu_note_voluntary_context_switch(t) do { } while (0)
> +static inline void rcu_tasks_trampoline_enter(void) { }
> +static inline void rcu_tasks_trampoline_exit(void) { }
> +static inline void rcu_tasks_trampoline_assert_none(void) { }
> #define call_rcu_tasks call_rcu
> #define synchronize_rcu_tasks synchronize_rcu
> static inline void exit_tasks_rcu_start(void) { }
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 8b3d47a325cc..d2e7b1b3c9d2 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -956,6 +956,7 @@ struct task_struct {
> unsigned long rcu_tasks_nvcsw;
> u8 rcu_tasks_holdout;
> u8 rcu_tasks_idx;
> + int rcu_tramp_nesting;
> int rcu_tasks_idle_cpu;
> struct list_head rcu_tasks_holdout_list;
> int rcu_tasks_exit_cpu;
> diff --git a/include/linux/trace_recursion.h b/include/linux/trace_recursion.h
> index e6ca052b2a85..2da23a52ca4a 100644
> --- a/include/linux/trace_recursion.h
> +++ b/include/linux/trace_recursion.h
> @@ -153,6 +153,17 @@ static __always_inline int trace_test_and_set_recursion(unsigned long ip, unsign
> current->trace_recursion = val;
> barrier();
>
> + /*
> + * Callbacks reached from static trampoline text (return_to_handler,
> + * the rethook and kretprobe trampolines) do not maintain
> + * current->rcu_tramp_nesting themselves; they rely on this
> + * preempt_disable() to keep the task from being preempted, and thus
> + * from reporting a Tasks RCU quiescent state, while an ftrace_ops or
> + * its data is in use. If the preempt_disable() is ever removed from
> + * the recursion protection, this must rcu_tasks_trampoline_enter()
> + * here and rcu_tasks_trampoline_exit() in trace_clear_recursion()
> + * instead. See CONFIG_RCU_TASKS_PREEMPT_QS.
> + */
> preempt_disable_notrace();
>
> return bit;
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 416758c8a3d4..cfe3a8e53fbd 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -1869,6 +1869,7 @@ static inline void rcu_copy_process(struct task_struct *p)
> #endif /* #ifdef CONFIG_PREEMPT_RCU */
> #ifdef CONFIG_TASKS_RCU
> p->rcu_tasks_holdout = false;
> + p->rcu_tramp_nesting = 0;
> INIT_LIST_HEAD(&p->rcu_tasks_holdout_list);
> p->rcu_tasks_idle_cpu = -1;
> INIT_LIST_HEAD(&p->rcu_tasks_exit_list);
> diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
> index 627295396cd9..1662ba18bf34 100644
> --- a/kernel/rcu/tasks.h
> +++ b/kernel/rcu/tasks.h
> @@ -1113,10 +1113,11 @@ static void check_holdout_task(struct task_struct *t,
> *firstreport = false;
> }
> cpu = task_cpu(t);
> - pr_alert("%p: %c%c nvcsw: %lu/%lu holdout: %d idle_cpu: %d/%d\n",
> + pr_alert("%p: %c%c nvcsw: %lu/%lu holdout: %d tramp_nesting: %d idle_cpu: %d/%d\n",
> t, ".I"[is_idle_task(t)],
> "N."[cpu < 0 || !tick_nohz_full_cpu(cpu)],
> t->rcu_tasks_nvcsw, t->nvcsw, t->rcu_tasks_holdout,
> + data_race(t->rcu_tramp_nesting),
> data_race(t->rcu_tasks_idle_cpu), cpu);
> sched_show_task(t);
> }
>
> --
> 2.55.0
>
next prev parent reply other threads:[~2026-09-11 17:23 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 14:08 [PATCH RFC v2 00/15] rcu-tasks: let preemption outside trampolines be a quiescent state Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 01/15] rcu-tasks: Add per-task trampoline nesting count Josef Bacik
2026-09-11 17:23 ` Paul E. McKenney [this message]
2026-09-11 14:08 ` [PATCH RFC v2 02/15] entry: Pass pt_regs to irqentry_exit_cond_resched() Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 03/15] rcu-tasks: Hold trampoline nesting across irq-exit preemption in trampoline text Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 04/15] kprobes: Let Tasks RCU recognise tasks preempted in an optprobe jump window Josef Bacik
2026-09-11 14:26 ` sashiko-bot
2026-09-11 17:27 ` Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 05/15] ftrace: Mark modules hosting direct-call trampolines for Tasks RCU Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 06/15] x86/ftrace: Maintain Tasks RCU trampoline nesting in ftrace_caller Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 07/15] x86/kprobes: Maintain Tasks RCU trampoline nesting in the optprobe template Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 08/15] bpf, x86: Maintain Tasks RCU trampoline nesting in the BPF trampoline Josef Bacik
2026-09-12 3:27 ` Alexei Starovoitov
2026-09-12 5:10 ` Paul E. McKenney
2026-09-12 17:18 ` Alexei Starovoitov
2026-09-12 18:03 ` Paul E. McKenney
2026-09-12 19:40 ` Alexei Starovoitov
2026-09-12 22:28 ` Paul E. McKenney
2026-09-12 23:59 ` Alexei Starovoitov
2026-09-13 3:07 ` Paul E. McKenney
2026-09-12 21:14 ` David Laight
2026-09-12 22:31 ` Paul E. McKenney
2026-09-13 11:28 ` David Laight
2026-09-13 18:20 ` Paul E. McKenney
2026-09-11 14:08 ` [PATCH RFC v2 09/15] arm64: ftrace: Maintain Tasks RCU trampoline nesting in ftrace_caller Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 10/15] bpf, arm64: Maintain Tasks RCU trampoline nesting in the BPF trampoline Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 11/15] samples: ftrace: Maintain Tasks RCU trampoline nesting in direct-call trampolines Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 12/15] rcutorture: Bracket Tasks RCU readers with trampoline nesting Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 13/15] rcu-tasks: Treat preemption outside trampolines as a quiescent state Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 14/15] rcu-tasks: Retire switched-out tasks with no trampoline nesting at scan time Josef Bacik
2026-09-11 14:08 ` [PATCH RFC v2 15/15] rcu-tasks: Kick running holdouts through the scheduler Josef Bacik
2026-09-11 18:46 ` Paul E. McKenney
2026-09-13 7:13 ` [PATCH RFC v2 00/15] rcu-tasks: let preemption outside trampolines be a quiescent state Yafang Shao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=90c2dfbe-e796-4125-b178-e854b40f68cd@paulmck-laptop \
--to=paulmck@kernel.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=boqun@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=catalin.marinas@arm.com \
--cc=daniel@iogearbox.net \
--cc=frederic@kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=jgross@suse.com \
--cc=jiangshanlai@gmail.com \
--cc=joelagnelf@nvidia.com \
--cc=jolsa@kernel.org \
--cc=josef@toxicpanda.com \
--cc=josh@joshtriplett.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mark.rutland@arm.com \
--cc=mathieu.desnoyers@efficios.com \
--cc=mcgrof@kernel.org \
--cc=mhiramat@kernel.org \
--cc=neeraj.upadhyay@kernel.org \
--cc=peterz@infradead.org \
--cc=puranjay@kernel.org \
--cc=qiang.zhang@linux.dev \
--cc=rcu@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=tglx@kernel.org \
--cc=urezki@gmail.com \
--cc=will@kernel.org \
--cc=x86@kernel.org \
--cc=xen-devel@lists.xenproject.org \
--cc=xukuohai@huaweicloud.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox