Netdev List
 help / color / mirror / Atom feed
* [PATCH] sunrpc: fix lost wakeups when stopping service threads
@ 2026-10-30 13:06 Kal Cutter Conley
  2026-10-30 21:43 ` Chuck Lever
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Kal Cutter Conley @ 2026-10-30 13:06 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
	NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman
  Cc: Kal Cutter Conley, linux-nfs, netdev, linux-kernel

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();
+
 	rcu_read_lock();
 	ln = READ_ONCE(pool->sp_idle_threads.first);
 	if (ln) {

base-commit: b803428098f6fcd584db9f0499217b80e465bb34
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] sunrpc: fix lost wakeups when stopping service threads
  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
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Chuck Lever @ 2026-10-30 21:43 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker, Jeff Layton, NeilBrown,
	Olga Kornievskaia, Dai Ngo, Tom Talpey, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kal Cutter Conley
  Cc: linux-nfs, netdev, linux-kernel

On Fri, 30 Oct 2026 14:06:28 +0100, 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]
> 
> [...]

Applied to nfsd-testing, thanks!

[1/1] sunrpc: fix lost wakeups when stopping service threads
      commit: 7073ba6c3383159deb5c1fd47b5b91a68bbcfd04

--
Chuck Lever


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] sunrpc: fix lost wakeups when stopping service threads
  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 14:01   ` Chuck Lever
  2026-11-02 22:53 ` [PATCH v2] " Kal Cutter Conley
  2026-11-03 12:19 ` [PATCH v3] " Kal Cutter Conley
  3 siblings, 1 reply; 8+ messages in thread
From: NeilBrown @ 2026-10-30 22:45 UTC (permalink / raw)
  To: Kal Cutter Conley
  Cc: Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
	Olga Kornievskaia, Dai Ngo, Tom Talpey, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kal Cutter Conley, linux-nfs, netdev, linux-kernel

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().

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
> 
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] sunrpc: fix lost wakeups when stopping service threads
  2026-10-30 22:45 ` NeilBrown
@ 2026-10-31 14:01   ` Chuck Lever
  0 siblings, 0 replies; 8+ messages in thread
From: Chuck Lever @ 2026-10-31 14:01 UTC (permalink / raw)
  To: NeilBrown, Kal Cutter Conley
  Cc: Trond Myklebust, Anna Schumaker, Jeff Layton, Olga Kornievskaia,
	Dai Ngo, Tom Talpey, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, linux-nfs, netdev,
	linux-kernel



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)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2] sunrpc: fix lost wakeups when stopping service threads
  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-11-02 22:53 ` Kal Cutter Conley
  2026-11-03  0:06   ` NeilBrown
  2026-11-03 11:38   ` Jeff Layton
  2026-11-03 12:19 ` [PATCH v3] " Kal Cutter Conley
  3 siblings, 2 replies; 8+ messages in thread
From: Kal Cutter Conley @ 2026-11-02 22:53 UTC (permalink / raw)
  To: Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
	NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman
  Cc: Kal Cutter Conley, linux-nfs, netdev, linux-kernel

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.

Use smp_mb__after_atomic() after the flag updates in
svc_stop_kthreads() and svc_wake_up() to 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>
---
Changes in v2:
- Move the barrier into svc_stop_kthreads() and svc_wake_up(), using
  smp_mb__after_atomic(). This avoids adding a redundant barrier on the
  transport enqueue path.

v1: https://lore.kernel.org/r/20261030130629.103716-1-kalcutterc@nvidia.com

 net/sunrpc/svc.c      | 7 +++++++
 net/sunrpc/svc_xprt.c | 5 +++++
 2 files changed, 12 insertions(+)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index af8d87c1de83..76232774646c 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"
@@ -784,6 +786,11 @@ svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
 	do {
 		set_bit(SP_VICTIM_REMAINS, &pool->sp_flags);
 		set_bit(SP_NEED_VICTIM, &pool->sp_flags);
+		/*
+		 * Order flag updates before the idle list and task state checks.
+		 * Pairs with the barriers in svc_thread_wait_for_work().
+		 */
+		smp_mb__after_atomic();
 		svc_pool_wake_idle_thread(pool);
 		wait_on_bit(&pool->sp_flags, SP_VICTIM_REMAINS, TASK_IDLE);
 		nrservs++;
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 076c624fe675..868e3da57b6c 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -632,6 +632,11 @@ void svc_wake_up(struct svc_serv *serv)
 	struct svc_pool *pool = &serv->sv_pools[0];
 
 	set_bit(SP_TASK_PENDING, &pool->sp_flags);
+	/*
+	 * Order flag updates before the idle list and task state checks.
+	 * Pairs with the barriers in svc_thread_wait_for_work().
+	 */
+	smp_mb__after_atomic();
 	svc_pool_wake_idle_thread(pool);
 }
 EXPORT_SYMBOL_GPL(svc_wake_up);

base-commit: 2d3259f652bb0f1d137ccabecac6763da05064ec
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] sunrpc: fix lost wakeups when stopping service threads
  2026-11-02 22:53 ` [PATCH v2] " Kal Cutter Conley
@ 2026-11-03  0:06   ` NeilBrown
  2026-11-03 11:38   ` Jeff Layton
  1 sibling, 0 replies; 8+ messages in thread
From: NeilBrown @ 2026-11-03  0:06 UTC (permalink / raw)
  To: Kal Cutter Conley
  Cc: Trond Myklebust, Anna Schumaker, Chuck Lever, Jeff Layton,
	Olga Kornievskaia, Dai Ngo, Tom Talpey, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kal Cutter Conley, linux-nfs, netdev, linux-kernel

On Tue, 03 Nov 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.
> 
> Use smp_mb__after_atomic() after the flag updates in
> svc_stop_kthreads() and svc_wake_up() to 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>
> ---
> Changes in v2:
> - Move the barrier into svc_stop_kthreads() and svc_wake_up(), using
>   smp_mb__after_atomic(). This avoids adding a redundant barrier on the
>   transport enqueue path.
> 
> v1: https://lore.kernel.org/r/20261030130629.103716-1-kalcutterc@nvidia.com
> 
>  net/sunrpc/svc.c      | 7 +++++++
>  net/sunrpc/svc_xprt.c | 5 +++++
>  2 files changed, 12 insertions(+)
> 
> diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
> index af8d87c1de83..76232774646c 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>

I doubt this include is really needed, but I'm not sure that matters.

> +
>  #include <trace/events/sunrpc.h>
>  
>  #include "fail.h"
> @@ -784,6 +786,11 @@ svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
>  	do {
>  		set_bit(SP_VICTIM_REMAINS, &pool->sp_flags);
>  		set_bit(SP_NEED_VICTIM, &pool->sp_flags);
> +		/*
> +		 * Order flag updates before the idle list and task state checks.
> +		 * Pairs with the barriers in svc_thread_wait_for_work().
> +		 */
> +		smp_mb__after_atomic();
>  		svc_pool_wake_idle_thread(pool);
>  		wait_on_bit(&pool->sp_flags, SP_VICTIM_REMAINS, TASK_IDLE);
>  		nrservs++;
> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> index 076c624fe675..868e3da57b6c 100644
> --- a/net/sunrpc/svc_xprt.c
> +++ b/net/sunrpc/svc_xprt.c
> @@ -632,6 +632,11 @@ void svc_wake_up(struct svc_serv *serv)
>  	struct svc_pool *pool = &serv->sv_pools[0];
>  
>  	set_bit(SP_TASK_PENDING, &pool->sp_flags);
> +	/*
> +	 * Order flag updates before the idle list and task state checks.
> +	 * Pairs with the barriers in svc_thread_wait_for_work().
> +	 */
> +	smp_mb__after_atomic();
>  	svc_pool_wake_idle_thread(pool);

Reviewed-by: NeilBrown <neil@brown.name>

Thanks,
NeilBrown

>  }
>  EXPORT_SYMBOL_GPL(svc_wake_up);
> 
> base-commit: 2d3259f652bb0f1d137ccabecac6763da05064ec
> -- 
> 2.53.0
> 
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] sunrpc: fix lost wakeups when stopping service threads
  2026-11-02 22:53 ` [PATCH v2] " Kal Cutter Conley
  2026-11-03  0:06   ` NeilBrown
@ 2026-11-03 11:38   ` Jeff Layton
  1 sibling, 0 replies; 8+ messages in thread
From: Jeff Layton @ 2026-11-03 11:38 UTC (permalink / raw)
  To: Kal Cutter Conley, Trond Myklebust, Anna Schumaker, Chuck Lever,
	NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman
  Cc: linux-nfs, netdev, linux-kernel

On Mon, 2026-11-02 at 23:53 +0100, 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.
> 
> Use smp_mb__after_atomic() after the flag updates in
> svc_stop_kthreads() and svc_wake_up() to 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>
> ---
> Changes in v2:
> - Move the barrier into svc_stop_kthreads() and svc_wake_up(), using
>   smp_mb__after_atomic(). This avoids adding a redundant barrier on the
>   transport enqueue path.
> 
> v1: https://lore.kernel.org/r/20261030130629.103716-1-kalcutterc@nvidia.com
> 
>  net/sunrpc/svc.c      | 7 +++++++
>  net/sunrpc/svc_xprt.c | 5 +++++
>  2 files changed, 12 insertions(+)
> 
> diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
> index af8d87c1de83..76232774646c 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>
> +

As Neil said, this is probably not needed.

>  #include <trace/events/sunrpc.h>
>  
>  #include "fail.h"
> @@ -784,6 +786,11 @@ svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
>  	do {
>  		set_bit(SP_VICTIM_REMAINS, &pool->sp_flags);
>  		set_bit(SP_NEED_VICTIM, &pool->sp_flags);
> +		/*
> +		 * Order flag updates before the idle list and task state checks.
> +		 * Pairs with the barriers in svc_thread_wait_for_work().
> +		 */
> +		smp_mb__after_atomic();
>  		svc_pool_wake_idle_thread(pool);
>  		wait_on_bit(&pool->sp_flags, SP_VICTIM_REMAINS, TASK_IDLE);
>  		nrservs++;
> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> index 076c624fe675..868e3da57b6c 100644
> --- a/net/sunrpc/svc_xprt.c
> +++ b/net/sunrpc/svc_xprt.c
> @@ -632,6 +632,11 @@ void svc_wake_up(struct svc_serv *serv)
>  	struct svc_pool *pool = &serv->sv_pools[0];
>  
>  	set_bit(SP_TASK_PENDING, &pool->sp_flags);
> +	/*
> +	 * Order flag updates before the idle list and task state checks.
> +	 * Pairs with the barriers in svc_thread_wait_for_work().
> +	 */
> +	smp_mb__after_atomic();
>  	svc_pool_wake_idle_thread(pool);
>  }
>  EXPORT_SYMBOL_GPL(svc_wake_up);
> 
> base-commit: 2d3259f652bb0f1d137ccabecac6763da05064ec

Reviewed-by: Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3] sunrpc: fix lost wakeups when stopping service threads
  2026-10-30 13:06 [PATCH] sunrpc: fix lost wakeups when stopping service threads Kal Cutter Conley
                   ` (2 preceding siblings ...)
  2026-11-02 22:53 ` [PATCH v2] " Kal Cutter Conley
@ 2026-11-03 12:19 ` Kal Cutter Conley
  3 siblings, 0 replies; 8+ messages in thread
From: Kal Cutter Conley @ 2026-11-03 12:19 UTC (permalink / raw)
  To: Chuck Lever, Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo,
	Tom Talpey, Trond Myklebust, Anna Schumaker, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman
  Cc: Kal Cutter Conley, linux-nfs, netdev, linux-kernel

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.

Use smp_mb__after_atomic() after the flag updates in
svc_stop_kthreads() and svc_wake_up() to 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>
---
Changes in v3:
- Drop the redundant <asm/barrier.h> include from svc.c.

Changes in v2:
- Move the barrier into svc_stop_kthreads() and svc_wake_up(), using
  smp_mb__after_atomic(). This avoids adding a redundant barrier on the
  transport enqueue path.

v1: https://lore.kernel.org/r/20261030130629.103716-1-kalcutterc@nvidia.com

 net/sunrpc/svc.c      | 5 +++++
 net/sunrpc/svc_xprt.c | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index af8d87c1de83..6100603e0a34 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -784,6 +784,11 @@ svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
 	do {
 		set_bit(SP_VICTIM_REMAINS, &pool->sp_flags);
 		set_bit(SP_NEED_VICTIM, &pool->sp_flags);
+		/*
+		 * Order flag updates before the idle list and task state checks.
+		 * Pairs with the barriers in svc_thread_wait_for_work().
+		 */
+		smp_mb__after_atomic();
 		svc_pool_wake_idle_thread(pool);
 		wait_on_bit(&pool->sp_flags, SP_VICTIM_REMAINS, TASK_IDLE);
 		nrservs++;
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 076c624fe675..868e3da57b6c 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -632,6 +632,11 @@ void svc_wake_up(struct svc_serv *serv)
 	struct svc_pool *pool = &serv->sv_pools[0];
 
 	set_bit(SP_TASK_PENDING, &pool->sp_flags);
+	/*
+	 * Order flag updates before the idle list and task state checks.
+	 * Pairs with the barriers in svc_thread_wait_for_work().
+	 */
+	smp_mb__after_atomic();
 	svc_pool_wake_idle_thread(pool);
 }
 EXPORT_SYMBOL_GPL(svc_wake_up);

base-commit: 2d3259f652bb0f1d137ccabecac6763da05064ec
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-11-03 12:22 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 14:01   ` Chuck Lever
2026-11-02 22:53 ` [PATCH v2] " Kal Cutter Conley
2026-11-03  0:06   ` NeilBrown
2026-11-03 11:38   ` Jeff Layton
2026-11-03 12:19 ` [PATCH v3] " Kal Cutter Conley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox