[PATCH 0/9] NFSD: Do not revoke a delegation the client never recorded
Chuck Lever <[email protected]> Sun, 02 Aug 2026 13:04:27 -0400
| Newsgroups | gmane.linux.kernel.stable,gmane.linux.nfs |
|---|---|
| Message-ID | <20260802-nfsd-deleg-destroy-badhandle-v1-0-323aa7196055@kernel.org> |
A nightly backup on my home directory server ran into this. NFSD had granted a write delegation during the day, and the client lost that delegation to the bug that "NFS: Return a delegation the client fails to record" addresses: https://lore.kernel.org/r/[email protected] When NFSD recalled that delegation, the client had no record of the stateid and answered CB_RECALL with NFS4ERR_BAD_STATEID. NFSD added the delegation to cl_revoked, where only a FREE_STATEID drains it. That FREE_STATEID never arrives, so every later SEQUENCE reply carries SEQ4_STATUS_RECALLABLE_STATE_REVOKED. The client's state manager loops issuing TEST_STATEID but never finds the missing state. A delegation whose recall the client rejects is now destroyed rather than revoked (patch 8). RFC 8881 Section 20.2.4 mandates that the NFS server complete the delegation recall in this case rather than marking the state as revoked. There are some complications, of course. CB_RECALL can outrun the reply that granted the delegation; a rejection proves nothing until the client has seen that grant. RFC 8881 Section 2.10.6.3 makes retirement of the slot that carried the grant that proof. NFSD retries the CB_RECALL until the slot retires and revokes in the old way when the retries lapse. The series also makes CB_RECALL the second consumer of referring call lists. The CB_RECALL send buffer budget has to be correct before a referring call list can ride in it. Unfortunately NFSD's original referring call lists implementation got some of the XDR sizes wrong. --- Chuck Lever (9): NFSD: Budget the CB_SEQUENCE opcode and referring call array count NFSD: Budget the CB_RECALL truncate field NFSD: Budget the CB_LAYOUTRECALL recall stateid NFSD: Budget the CB_OFFLOAD opcode NFSD: Budget the CB_NOTIFY_LOCK opcode NFSD: Budget the CB_RECALL_ANY opcode NFSD: Correct locking documentation for delegation sc_status NFSD: Destroy a recalled delegation the client does not hold NFSD: Send referring calls with CB_RECALL fs/nfsd/nfs4callback.c | 7 +- fs/nfsd/nfs4state.c | 228 ++++++++++++++++++++++++++++++++++++++++++------- fs/nfsd/state.h | 24 ++++-- fs/nfsd/xdr4cb.h | 20 +++-- 4 files changed, 231 insertions(+), 48 deletions(-) --- base-commit: 106c31f3d72c56fce98bb2f0e8b3de1a0024228d change-id: 20260802-nfsd-deleg-destroy-badhandle-333a720dc332 Best regards, -- Chuck Lever <[email protected]>