Re: [PATCH 7/9] srcu: Detect duplicate callback enqueue at registration
From: Paul E. McKenney
Date: Fri Oct 23 2026 - 15:38:59 EST
On Fri, Oct 23, 2026 at 12:30:57PM -0700, Paul E. McKenney wrote:
> 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?
As in shouldn't there be a kasan_print_aux_stacks() in there somewhere?
I did not see an call from mem_dump_obj(), but I could easily have
missed it.
Thanx, Paul
> > + }
> > + 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
> >