From: Chuck Lever <cel@kernel.org>
To: Anna Schumaker <anna@kernel.org>,
Trond Myklebust <trond.myklebust@hammerspace.com>
Cc: <linux-nfs@vger.kernel.org>
Subject: [PATCH] NFS: Return a delegation the client fails to record
Date: Wed, 17 Jun 2026 08:52:57 -0400 [thread overview]
Message-ID: <20260617125257.1293452-1-cel@kernel.org> (raw)
When an NFS server grants a delegation in an OPEN reply,
nfs_inode_set_delegation() records it on the client. However, three
of its error flows return without sending DELEGRETURN.
A delegation can be relinquished only by DELEGRETURN (RFC 8881
Section 20.2.4), so dropping one silently leaves the server believing
the client still holds it. If the server happens to recall that
delegation, the client answers CB_RECALL with NFS4ERR_BADHANDLE
because it has no record of the stateid. The server revokes the
delegation and moves it onto its cl_revoked list, because the client
never sends the FREE_STATEID that would drain it. Every subsequent
SEQUENCE reply then carries SEQ4_STATUS_RECALLABLE_STATE_REVOKED,
and the client's state manager loops issuing TEST_STATEID across its
delegations without ever clearing the condition.
The window is easy to reach now that a server offers a write
delegation on any write OPEN: a delegation recalled for one opener
races a re-open that the server answers with a fresh write
delegation.
Instead of dropping it, hand the delegation back during these error
flows.
Fixes: ade04647dd56 ("NFSv4: Ensure we honour NFS_DELEGATION_RETURNING in nfs_inode_set_delegation()")
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfs/delegation.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 122fb3f14ffb..cb579f8c55ce 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -440,11 +440,14 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation, *old_delegation;
struct nfs_delegation *freeme = NULL;
+ bool orphaned = false;
int status = 0;
delegation = kmalloc_obj(*delegation, GFP_KERNEL_ACCOUNT);
- if (delegation == NULL)
+ if (delegation == NULL) {
+ nfs4_proc_delegreturn(inode, cred, stateid, NULL, 0);
return -ENOMEM;
+ }
nfs4_stateid_copy(&delegation->stateid, stateid);
refcount_set(&delegation->refcount, 1);
delegation->type = type;
@@ -493,11 +496,15 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
goto out;
}
if (test_and_set_bit(NFS_DELEGATION_RETURNING,
- &old_delegation->flags))
+ &old_delegation->flags)) {
+ orphaned = true;
goto out;
+ }
}
- if (!nfs_detach_delegations_locked(nfsi, old_delegation, clp))
+ if (!nfs_detach_delegations_locked(nfsi, old_delegation, clp)) {
+ orphaned = true;
goto out;
+ }
freeme = old_delegation;
add_new:
/*
@@ -532,8 +539,11 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
nfs_update_delegated_mtime(inode);
out:
spin_unlock(&clp->cl_lock);
- if (delegation != NULL)
+ if (delegation != NULL) {
+ if (orphaned)
+ nfs_do_return_delegation(inode, delegation, 0);
__nfs_free_delegation(delegation);
+ }
if (freeme != NULL) {
nfs_do_return_delegation(inode, freeme, 0);
nfs_mark_delegation_revoked(server, freeme);
--
2.54.0
reply other threads:[~2026-06-17 12:52 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260617125257.1293452-1-cel@kernel.org \
--to=cel@kernel.org \
--cc=anna@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=trond.myklebust@hammerspace.com \
/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