[PATCH 2/2] nfsd: clear CALLBACK_RUNNING on failed delegation recall queue

From: Jeff Layton

Date: Tue May 26 2026 - 12:45:33 EST


nfsd_break_one_deleg() sets NFSD4_CALLBACK_RUNNING via test_and_set_bit
at entry to serialize recall work, then calls nfsd4_run_cb() to queue
the recall. When the queue attempt fails the refcount bump is undone,
but the RUNNING bit is left set. The only site that clears the bit is
nfsd41_destroy_cb() (fs/nfsd/nfs4callback.c), which runs from the
workqueue and is therefore unreachable when nothing was queued.

The bit becomes a permanent latch on dp->dl_recall.cb_flags: every
subsequent break_lease() on the same delegation hits the early-return
guard in nfsd_break_one_deleg() and silently skips the recall, so the
delegation is never broken and the conflicting open or lock stalls.

Fix by clearing NFSD4_CALLBACK_RUNNING on the !queued branch alongside
the refcount_dec.

Fixes: 1054e8ffc5c4 ("nfsd: prevent callback tasks running concurrently")
Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
---
fs/nfsd/nfs4state.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 57b99d1e74a6..0b4d7afc42c6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3479,8 +3479,10 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
refcount_inc(&dp->dl_stid.sc_count);
queued = nfsd4_run_cb(&dp->dl_recall);
WARN_ON_ONCE(!queued);
- if (!queued)
+ if (!queued) {
refcount_dec(&dp->dl_stid.sc_count);
+ clear_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags);
+ }
}

static bool

--
2.54.0