Re: [PATCH 7/9] srcu: Detect duplicate callback enqueue at registration
From: Paul E. McKenney
Date: Fri Oct 23 2026 - 15:31:28 EST
On Fri, Oct 23, 2026 at 06:18:39PM +0800, Kunwu Chan wrote:
> Move the duplicate-callback check from srcu_do_enqueue() to
> __call_srcu() entry so that detected duplicate registrations
> are rejected before they reach the deferred-list enqueue path.
> Report the callback address, function symbol, and object
> information, rate-limited to the first three occurrences.
>
> Signed-off-by: Kunwu Chan <chentao@xxxxxxxxxx>
Getting the stackof the call_srcu() once double-enqueue is detected
would be a very good thing!
One question below.
> ---
> kernel/rcu/srcutree.c | 20 ++++++++++++++------
> 1 file changed, 14 insertions(+), 6 deletions(-)
>
> diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
> index 1993ddbdb828..3838d9fdf532 100644
> --- a/kernel/rcu/srcutree.c
> +++ b/kernel/rcu/srcutree.c
> @@ -27,6 +27,7 @@
> #include <linux/smp.h>
> #include <linux/delay.h>
> #include <linux/module.h>
> +#include <linux/mm.h>
> #include <linux/slab.h>
> #include <linux/srcu.h>
>
> @@ -1511,12 +1512,6 @@ static unsigned long srcu_gp_start_if_needed(struct srcu_struct *ssp,
> static void srcu_do_enqueue(struct srcu_struct *ssp, struct rcu_head *rhp,
> rcu_callback_t func, bool do_norm)
> {
> - if (debug_rcu_head_queue(rhp)) {
> - /* Probable double call_srcu(), so leak the callback. */
> - WRITE_ONCE(rhp->func, srcu_leak_callback);
> - WARN_ONCE(1, "call_srcu(): Leaked duplicate callback\n");
> - return;
> - }
> rhp->func = func;
> (void)srcu_gp_start_if_needed(ssp, rhp, do_norm);
> }
> @@ -1529,6 +1524,8 @@ static void srcu_do_enqueue(struct srcu_struct *ssp, struct rcu_head *rhp,
> static void __call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp,
> rcu_callback_t func, bool do_norm)
> {
> + static atomic_t doublefrees;
> +
> /* Misaligned rcu_head! */
> WARN_ON_ONCE((unsigned long)rhp & (sizeof(void *) - 1));
>
> @@ -1539,6 +1536,16 @@ static void __call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp,
> if (WARN_ON_ONCE(ssp->srcu_reader_flavor == SRCU_READ_FLAVOR_ATOMIC))
> return; // Leak the callback rather than corrupt SRCU state.
>
> + if (debug_rcu_head_queue(rhp)) {
> + if (atomic_inc_return(&doublefrees) < 4) {
Why this hard-coded 4? Why not 3 or 5? Should this be adjustable via
Kconfig or kernel boot parameter? Or, alternatively, should the below
pr_err() instead be pr_err_ratelimited()?
> + pr_err("%s(): Duplicate call_srcu() CB %p->%pS()\n",
> + __func__, rhp, rhp->func);
> + mem_dump_obj(rhp);
Does any of this automatically dump out the stack that was recorded
in earlier patches in this series?
> + }
> + WRITE_ONCE(rhp->func, srcu_leak_callback);
> + return;
> + }
> +
> /* Record the caller: the irq_work's stack says nothing about it. */
> kasan_record_aux_stack(rhp);
>
> @@ -1554,6 +1561,7 @@ static void __call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp,
> if (READ_ONCE(sndp->draining) && !in_nmi()) {
> WARN_ONCE(IS_ENABLED(CONFIG_PROVE_RCU),
> "call_srcu() re-entered during callback drain; leaking callback\n");
> + debug_rcu_head_unqueue(rhp);
> return;
> }
> sdp = this_cpu_ptr(ssp->sda);
> --
> 2.43.0
>