All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
To: Puranjay Mohan <puranjay12@gmail.com>
Cc: "Lai Jiangshan" <jiangshanlai@gmail.com>,
	"Paul E. McKenney" <paulmck@kernel.org>,
	"Josh Triplett" <josh@joshtriplett.org>,
	"Onur Özkan" <work@onurozkan.dev>,
	"Frederic Weisbecker" <frederic@kernel.org>,
	"Neeraj Upadhyay" <neeraj.upadhyay@kernel.org>,
	"Joel Fernandes" <joelagnelf@nvidia.com>,
	"Boqun Feng" <boqun@kernel.org>,
	"Uladzislau Rezki" <urezki@gmail.com>,
	"Davidlohr Bueso" <dave@stgolabs.net>,
	"Andrii Nakryiko" <andrii@kernel.org>,
	"Eduard Zingerman" <eddyz87@gmail.com>,
	"Alexei Starovoitov" <ast@kernel.org>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"Kumar Kartikeya Dwivedi" <memxor@gmail.com>,
	"Steven Rostedt" <rostedt@goodmis.org>,
	"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
	Zqiang <qiang.zhang@linux.dev>,
	"Martin KaFai Lau" <martin.lau@linux.dev>,
	"Song Liu" <song@kernel.org>,
	"Yonghong Song" <yonghong.song@linux.dev>,
	"Jiri Olsa" <jolsa@kernel.org>,
	"Emil Tsalapatis" <emil@etsalapatis.com>,
	"Matt Fleming" <mfleming@cloudflare.com>,
	"Harry Yoo (Oracle)" <harry@kernel.org>,
	linux-kernel@vger.kernel.org, rcu@vger.kernel.org,
	bpf@vger.kernel.org, linux-rt-devel@lists.linux.dev
Subject: Re: [PATCH v4 1/6] rcu: Make call_rcu() safe to call from any context
Date: Wed, 2 Sep 2026 10:26:57 +0200	[thread overview]
Message-ID: <20260902082657.yPEhNFlo@linutronix.de> (raw)
In-Reply-To: <CANk7y0hbwXL7nBDgjTgrneBejEgGrsZnc02RztG-aSBEEvAcwQ@mail.gmail.com>

On 2026-09-01 14:53:56 [+0200], Puranjay Mohan wrote:
> On Wed, Aug 26, 2026 at 3:46 PM Sebastian Andrzej Siewior
> > > +/*
> > > + * Defer whenever interrupts are disabled, since a callback-list operation may
> > > + * be in flight on this CPU.  Not before the scheduler is up: irq_work is not
> > > + * usable that early, and rcu_init() itself calls call_rcu().
> > > + */
> > > +static inline bool should_rcu_defer(void)
> > > +{
> > > +     return IS_ENABLED(CONFIG_RCU_DEFER) && irqs_disabled() &&
> > > +            rcu_scheduler_active != RCU_SCHEDULER_INACTIVE;
> > > +}
> >
> > Why does the description say that the defer part is for usage from NMI
> > and the test here has irqs_disabled() instead of in_nmi()?
> 
> We defer for both irq disabled sections, hard irq, and in_nmi() and
> checking for irqs_disabled() covers all three.

But it is wrong to talk about NMI and do this for other reasons not
mentioning why this was needed/ made sense.
Can this be fixed?
Also what is the reasoning for doing it from any IRQ disabled region?

> >
> > > +
> > >  enum rcutorture_type {
> > >       RCU_FLAVOR,
> > >       RCU_TASKS_FLAVOR,
> > > diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> > > index 21b6ce1dffb63..3bf3a250f9de8 100644
> > > --- a/kernel/rcu/tree.c
> > > +++ b/kernel/rcu/tree.c
> > > @@ -3206,6 +3204,103 @@ __call_rcu_common(struct rcu_head *head, rcu_callback_t func, bool lazy_in)
> > >       local_irq_restore(flags);
> > >  }
> > >
> > > +/*
> > > + * Re-issue deferred callbacks straight to the enqueue so they cannot defer
> > > + * again.  ->defer_lock serializes the drainers: this CPU's irq_work,
> > > + * rcu_defer_flush() and rcutree_migrate_callbacks().
> > > + */
> > > +static void __rcu_defer_drain(struct rcu_data *rdp)
> > > +{
> > > +     struct llist_node *node, *next;
> > > +     unsigned long flags;
> > > +
> > > +     if (!IS_ENABLED(CONFIG_RCU_DEFER))
> > > +             return;
> > > +
> > > +     raw_spin_lock_irqsave(&rdp->defer_lock, flags);
> > > +     llist_for_each_safe(node, next, llist_del_all(&rdp->defer_head)) {
> > > +             struct rcu_head *head = (struct rcu_head *)node;
> >
> > Why do you need the lock. This is still not clear to me despite the
> > comment. You can do llist_del_all() towards another list and then feed
> > it into rcu_do_enqueue() one by one. And you use the LAZY part.
> 
> Because rcu_barrier() can call this for each cpu and at the same time
> rcu_defer_drain() can call it too, so this would cause a race where
> the irq work can remove the callbacks (llist_del_all) and before it
> can enqueue them, rcu_barrier will see that the list is already empty
> and will not wait for these callbacks. We want the llist_del_all() and
> rcu_do_enqueue() to happen atomically so rcu_barrier() can work
> correctly.

So you collect a bunch of callbacks and spent time re-arranging
everything with irqs off.
What is wrong with keeping it in the llist and consuming it like the
regular rcu_segcblist?

> >
> > > +
> > > +             /* Bounds a node self-linked by a double call_rcu(). */
> > > +             head->next = NULL;
> > > +             rcu_do_enqueue(head, head->func, false);
> > > +     }
> > > +     raw_spin_unlock_irqrestore(&rdp->defer_lock, flags);
> > > +}
> > …
> > > @@ -4231,6 +4330,9 @@ rcu_boot_init_percpu_data(int cpu)
> > >       rdp->rcu_onl_gp_state = RCU_GP_CLEANED;
> > >       rdp->last_sched_clock = jiffies;
> > >       rdp->cpu = cpu;
> > > +     init_llist_head(&rdp->defer_head);
> > > +     raw_spin_lock_init(&rdp->defer_lock);
> > > +     rdp->defer_work = IRQ_WORK_INIT_HARD(rcu_defer_drain);
> >
> > Why is this IRQ_WORK_INIT_HARD() instead, say, IRQ_WORK_INIT_LAZY()? Is
> > there a requirement that the RCU callback needs to complete asap and not
> > be delayed to the next tick? This would give kind of the LAZY part.
> >
> 
> In discussions with Paul, we concluded that we need HARD because in
> low memory situations delaying rcu callbacks can be problematic. Given
> that we are already deferring the callbacks, it would be nice to have
> them enqueued asap. But if there are downsides to this we may change
> it later.

It does not look like you defer them for long at all. Every callback
enqueued in an IRQ-off region will be immediately re-enqueued to the
regular list the moment interrupts are enabled again. 
Except on architectures which don't implement irq-work interrupts where
it will be delayed to the next HZ tick. And the next HZ tick does not
sound like a long time either.

> > >       rcu_boot_init_nocb_percpu_data(rdp);
> > >  }
> > >

Sebastian

  reply	other threads:[~2026-09-02  8:27 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-10 12:27 [PATCH v4 0/6] rcu,srcu: Make call_rcu()/call_srcu() safe from any context Puranjay Mohan
2026-08-10 12:27 ` [PATCH v4 1/6] rcu: Make call_rcu() safe to call " Puranjay Mohan
2026-08-10 12:43   ` sashiko-bot
2026-08-10 12:48     ` Puranjay Mohan
2026-08-26 14:46   ` Sebastian Andrzej Siewior
2026-09-01 12:53     ` Puranjay Mohan
2026-09-02  8:26       ` Sebastian Andrzej Siewior [this message]
2026-09-02 14:14         ` Puranjay Mohan
2026-08-10 12:27 ` [PATCH v4 2/6] rcu: Make Tiny " Puranjay Mohan
2026-08-10 12:42   ` sashiko-bot
2026-08-10 12:45     ` Puranjay Mohan
2026-08-10 12:27 ` [PATCH v4 3/6] srcu: Make call_srcu() " Puranjay Mohan
2026-08-10 12:27 ` [PATCH v4 4/6] srcu: Make Tiny " Puranjay Mohan
2026-08-10 12:27 ` [PATCH v4 5/6] rcutorture: Exercise ->call() from NMI context Puranjay Mohan
2026-08-10 12:27 ` [PATCH v4 6/6] selftests/bpf: Add a call_srcu() re-entry reproducer Puranjay Mohan
2026-08-12  0:10 ` [PATCH v4 0/6] rcu,srcu: Make call_rcu()/call_srcu() safe from any context Paul E. McKenney

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=20260902082657.yPEhNFlo@linutronix.de \
    --to=bigeasy@linutronix.de \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=boqun@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=dave@stgolabs.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=frederic@kernel.org \
    --cc=harry@kernel.org \
    --cc=jiangshanlai@gmail.com \
    --cc=joelagnelf@nvidia.com \
    --cc=jolsa@kernel.org \
    --cc=josh@joshtriplett.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=martin.lau@linux.dev \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=memxor@gmail.com \
    --cc=mfleming@cloudflare.com \
    --cc=neeraj.upadhyay@kernel.org \
    --cc=paulmck@kernel.org \
    --cc=puranjay12@gmail.com \
    --cc=qiang.zhang@linux.dev \
    --cc=rcu@vger.kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=song@kernel.org \
    --cc=urezki@gmail.com \
    --cc=work@onurozkan.dev \
    --cc=yonghong.song@linux.dev \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.