From: "Chuck Lever" <cel@kernel.org>
To: NeilBrown <neil@brown.name>, "Kal Cutter Conley" <kalcutterc@nvidia.com>
Cc: "Trond Myklebust" <trondmy@kernel.org>,
"Anna Schumaker" <anna@kernel.org>,
"Jeff Layton" <jlayton@kernel.org>,
"Olga Kornievskaia" <okorniev@redhat.com>,
"Dai Ngo" <Dai.Ngo@oracle.com>, "Tom Talpey" <tom@talpey.com>,
"David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@kernel.org>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Simon Horman" <horms@kernel.org>,
linux-nfs@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] sunrpc: fix lost wakeups when stopping service threads
Date: Sat, 31 Oct 2026 10:01:15 -0400 [thread overview]
Message-ID: <44664d64-3694-49d1-ad17-ca70221ed327@app.fastmail.com> (raw)
In-Reply-To: <179340033904.269288.4611945330659974906@noble.neil.brown.name>
On Fri, Oct 30, 2026, at 6:45 PM, 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.
> 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().
Kal's patch as written adds an mfence-class instruction to every transport
enqueue (a common case) for no ordering benefit. So let's go with Neil's
proposed solution. Kal, can you send a v2?
--
Chuck Lever (Come to NFS bake-a-thon! https://nfsv4bat.org)
prev parent reply other threads:[~2026-10-31 14:01 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 13:06 Kal Cutter Conley
2026-10-30 21:43 ` Chuck Lever
2026-10-30 22:45 ` NeilBrown
2026-10-31 0:46 ` Hillf Danton
2026-10-31 14:01 ` Chuck Lever [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=44664d64-3694-49d1-ad17-ca70221ed327@app.fastmail.com \
--to=cel@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=anna@kernel.org \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=jlayton@kernel.org \
--cc=kalcutterc@nvidia.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=netdev@vger.kernel.org \
--cc=okorniev@redhat.com \
--cc=pabeni@redhat.com \
--cc=tom@talpey.com \
--cc=trondmy@kernel.org \
/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
all inboxes | Powered by JetHome®