All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hillf Danton <hdanton@sina.com>
To: NeilBrown <neilb@ownmail.net>
Cc: "Kal Cutter Conley" <kalcutterc@nvidia.com>,
	"Chuck Lever" <cel@kernel.org>,
	linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] sunrpc: fix lost wakeups when stopping service threads
Date: Sat, 31 Oct 2026 08:46:56 +0800	[thread overview]
Message-ID: <20261031004657.251-1-hdanton@sina.com> (raw)
In-Reply-To: <179340033904.269288.4611945330659974906@noble.neil.brown.name>

On Sat, 31 Oct 2026 09:45:39 +1100 NeilBrown wrote:
> On Sat, 31 Oct 2026, Kal Cutter Conley wrote:
> > Stopping NFS can leave rpc.nfsd 0 in an uninterruptible wait with
> > this stack:
> > 
> >   svc_stop_kthreads [sunrpc]
> >   svc_set_num_threads [sunrpc]
> >   nfsd_svc [nfsd]
> >   write_threads [nfsd]
> >   nfsctl_transaction_write [nfsd]
> > 
> > SP_NEED_VICTIM and SP_VICTIM_REMAINS remain set while all remaining
> > nfsd threads sleep in svc_recv() and none has RQ_VICTIM set.
> > 
> > The stop request is published with unordered set_bit() operations.
> > svc_pool_wake_idle_thread() checks the idle list and task state before
> > calling wake_up_process(). If it sees an empty list or TASK_RUNNING,
> > it skips the wakeup and its memory barrier. The requester can therefore
> > miss a sleeping worker while that worker misses the stop request.
> > 
> > Order work publication before both lockless checks, even when no
> > wakeup occurs. Pair with set_current_state() and llist_add() in
> > svc_thread_wait_for_work(), so the worker observes the pending work or
> > the requester observes the idle worker and wakes it.
> > 
> > Fixes: 60749cbe3d8a ("sunrpc: change sp_nrthreads from atomic_t to unsigned int.")
> > Signed-off-by: Kal Cutter Conley <kalcutterc@nvidia.com>
> > ---
> >  net/sunrpc/svc.c | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
> > index af8d87c1de83..f3cc63acc5e1 100644
> > --- a/net/sunrpc/svc.c
> > +++ b/net/sunrpc/svc.c
> > @@ -29,6 +29,8 @@
> >  #include <linux/sunrpc/clnt.h>
> >  #include <linux/sunrpc/bc_xprt.h>
> >  
> > +#include <asm/barrier.h>
> > +
> >  #include <trace/events/sunrpc.h>
> >  
> >  #include "fail.h"
> > @@ -693,6 +695,13 @@ void svc_pool_wake_idle_thread(struct svc_pool *pool)
> >  	struct svc_rqst	*rqstp;
> >  	struct llist_node *ln;
> >  
> > +	/*
> > +	 * Order work publication before the idle-list and task-state checks,
> > +	 * even when wake_up_process() is skipped. Pairs with the barriers in
> > +	 * set_current_state() and llist_add() in svc_thread_wait_for_work().
> > +	 */
> > +	smp_mb();
> > +
> 
> I don't like this.  Stand-alone barriers are, I think, harder to read
> than barriers combined with operations, like smp_load_acquire() or
> similar.  And this one seems quite detached from anything.
> 
> If I understand correctly, the possible race is between
> svc_thread_wait_for_work which includes:
> 
> 		llist_add(&rqstp->rq_idle, &pool->sp_idle_threads);
> 		if (likely(svc_thread_should_sleep(rqstp)))
> 
> and svc_stop_kthread which includes:
> 
> 		set_bit(SP_NEED_VICTIM, &pool->sp_flags);
> 		svc_pool_wake_idle_thread(pool);
> 
> The first sets ->sp_idle_threads.first and then checks SP_NEED_VICTIM
> and the second sets SP_NEED_VICTIM and then checks
> ->sp_idle_threads.first.
> 
> So we need barriers to ensure the values are seen is the expected order.
> Have I missed anything?
> 
> llist_add() always calls try_cmpxchg() which is fully ordered, so no
> extra barriers are needed there.
> 
> There is no barrier between the set_bit)( and the READ_ONCE() in
> svc_pool_wake_idle_thread(), so you added one.  I agree that is correct
> and solves the problem.
> But it is only this call to svc_pool_wake_idle_thread() that needs a
> barrier, not all calls.  So I would prefer the barrier went in
> svc_stop_kthreads().   Do you have a reason for not including it there?
> 
> We do need a full memory barrier - a "release" on the set_bit and an
> "acquire" on the test of ->sp_idle_threads.first
> 
> I would be happy with smp_load_acquire(->sp_idle_theads_first) in
> svc_pool_wake_idle_thread().  I'm not sure it is needed though.
> 
> I would like set_bit_release(SP_NEED_VICTIM) in svc_stop_kthreads()
> but we don't have that.

It is on the way [11].

[11] Subject: [PATCH 1/2] asm-generic/bitops: Add set_bit_release()
https://lore.kernel.org/lkml/20261021095512.1345191-3-phasta@kernel.org/

> We could do
>    atomic_long_fetch_or_release(BIT(SP_NEED_VICTIM), (atomic_long_t*)&pool->sp_flags)
> but that is ugly.
> 
> So I think the best solution is
> 
> 		set_bit(SP_NEED_VICTIM, &pool->sp_flags);
> 		/* Order SP_NEED_VICTIM before testing sp_idle_threads,
>                  * matching svc_thread_wait_for_work() which orders
>                  * setting sp_idle_threads before testing the bit
> 		 */
> +               smp_mb__after_atomic();
> 		svc_pool_wake_idle_thread(pool);
> 
> We probably need the same in svc_wake_up() after the set_bit().
> 
> Does this make the barriers easier to understand?
> 
> Thoughts?
> 
> Thanks,
> NeilBrown
> 
> 
> >  	rcu_read_lock();
> >  	ln = READ_ONCE(pool->sp_idle_threads.first);
> >  	if (ln) {
> > 
> > base-commit: b803428098f6fcd584db9f0499217b80e465bb34
> > -- 
> > 2.53.0

      reply	other threads:[~2026-10-31  0:47 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-30 13:06 [PATCH] sunrpc: fix lost wakeups when stopping service threads Kal Cutter Conley
2026-10-30 21:43 ` Chuck Lever
2026-10-30 22:45 ` NeilBrown
2026-10-31  0:46   ` Hillf Danton [this message]

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=20261031004657.251-1-hdanton@sina.com \
    --to=hdanton@sina.com \
    --cc=cel@kernel.org \
    --cc=kalcutterc@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neilb@ownmail.net \
    /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.