mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 15:22:21 -04:00
nfsd: clear CALLBACK_RUNNING on failed delegation recall queue
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: 1054e8ffc5 ("nfsd: prevent callback tasks running concurrently")
Cc: stable@vger.kernel.org
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260526-cb_recall_any_callback_running_stuck-v1-2-310011a028f3@kernel.org
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
@@ -5631,8 +5631,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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called from break_lease() with flc_lock held. */
|
||||
|
||||
Reference in New Issue
Block a user