Skip to content

nfs4: answer retransmissions of sequenced nfsv4.0 requests with the cached response - #180

Open
ylangisc wants to merge 1 commit into
dCache:masterfrom
iterate-ch:nfs4-seqid-replay
Open

ylangisc wants to merge 1 commit into
dCache:masterfrom
iterate-ch:nfs4-seqid-replay

Conversation

@ylangisc

Copy link
Copy Markdown
Contributor

Motivation:
For every nfsv4.0 open-owner and lock-owner the server must keep the last
sequence id together with the response of the last request, and answer a
retransmission of that request with the cached response (rfc7530 9.1.7).
The server validates the sequence id but consumes it immediately, before
the operation is executed, and treats every retransmission as
NFS4ERR_BAD_SEQID. Clients retransmit with an unchanged sequence id after
a lost or timed out reply and, notably, when the server answers with
NFS4ERR_DELAY: the macOS client resends the identical request from the
RPC layer with a new xid (so a transport level duplicate request cache
does not recognize it), and the Linux client behaves alike. A server
answering NFS4ERR_DELAY after having consumed the sequence id, e.g.
because the virtual file system delays a reply while a backend operation
is pending, therefore rejects the retry with NFS4ERR_BAD_SEQID. As
neither side advances its sequence id on that error and it does not
trigger client state recovery, the owner remains out of sync for good and
every subsequent OPEN, CLOSE or LOCK of that owner fails.

Modification:
Move the consumption of the sequence id behind the execution of the
operation. StateOwner validates the sequence id up front and detects
retransmissions, the operation executes, and the sequence id is consumed
together with the response, or with the recorded failure, unless the
request failed with one of the errors that do not consume a sequence id
per rfc7530 9.1.7, or with NFS4ERR_DELAY, which clients retry with an
unchanged sequence id. A retransmission is answered with the cached
response or recorded failure without executing the operation again.
OPEN, OPEN_CONFIRM, OPEN_DOWNGRADE, CLOSE, LOCK and LOCKU follow this
pattern through a shared SequencedRequest helper; LOCK with a new lock
owner checks both sequence values and answers the request as a
retransmission when either of them matches a previous request, as
required by rfc7530 9.1.9, and consumes both the open-owner and the
lock-owner sequence id, mirroring the client. NFS4Client#getOrCreateOwner now only creates the
owner, validation and consumption happen in the operation. Minor
versions with sessions are unaffected. A retransmission of a successful
CLOSE is out of scope, as the state referenced by the retransmitted
request is already disposed; detecting it would require retaining
recently closed state ids.

Result:
Retransmissions of sequenced nfsv4.0 requests are answered with the
cached response of the original request, and NFS4ERR_DELAY no longer
consumes a sequence id, keeping owners in sync with retrying clients.
New tests cover replay detection, replay of failures and the
NFS4ERR_DELAY retry at both the StateOwner and the compound level.

Fixes: #179
Target: master

…ached response

Motivation:
For every nfsv4.0 open-owner and lock-owner the server must keep the last
sequence id together with the response of the last request, and answer a
retransmission of that request with the cached response (rfc7530 9.1.7).
The server validates the sequence id but consumes it immediately, before
the operation is executed, and treats every retransmission as
NFS4ERR_BAD_SEQID. Clients retransmit with an unchanged sequence id after
a lost or timed out reply and, notably, when the server answers with
NFS4ERR_DELAY: the macOS client resends the identical request from the
RPC layer with a new xid (so a transport level duplicate request cache
does not recognize it), and the Linux client behaves alike. A server
answering NFS4ERR_DELAY after having consumed the sequence id, e.g.
because the virtual file system delays a reply while a backend operation
is pending, therefore rejects the retry with NFS4ERR_BAD_SEQID. As
neither side advances its sequence id on that error and it does not
trigger client state recovery, the owner remains out of sync for good and
every subsequent OPEN, CLOSE or LOCK of that owner fails.

Modification:
Move the consumption of the sequence id behind the execution of the
operation. StateOwner validates the sequence id up front and detects
retransmissions, the operation executes, and the sequence id is consumed
together with the response, or with the recorded failure, unless the
request failed with one of the errors that do not consume a sequence id
per rfc7530 9.1.7, or with NFS4ERR_DELAY, which clients retry with an
unchanged sequence id. A retransmission is answered with the cached
response or recorded failure without executing the operation again.
OPEN, OPEN_CONFIRM, OPEN_DOWNGRADE, CLOSE, LOCK and LOCKU follow this
pattern through a shared SequencedRequest helper; LOCK with a new lock
owner checks both sequence values and answers the request as a
retransmission when either of them matches a previous request, as
required by rfc7530 9.1.9, and consumes both the open-owner and the
lock-owner sequence id, mirroring the client. NFS4Client#getOrCreateOwner now only creates the
owner, validation and consumption happen in the operation. Minor
versions with sessions are unaffected. A retransmission of a successful
CLOSE is out of scope, as the state referenced by the retransmitted
request is already disposed; detecting it would require retaining
recently closed state ids.

Result:
Retransmissions of sequenced nfsv4.0 requests are answered with the
cached response of the original request, and NFS4ERR_DELAY no longer
consumes a sequence id, keeping owners in sync with retrying clients.
New tests cover replay detection, replay of failures and the
NFS4ERR_DELAY retry at both the StateOwner and the compound level.

Fixes: dCache#179
Target: master

Signed-off-by: Yves Langisch <yla@iterate.ch>
@kofemann

Copy link
Copy Markdown
Member

@ylangisc thanks for the contribution. While I am going through your changes, I have a question. Why are you not using v4.1, as the latest macOS clients already support it?

apple-oss-distributions/NFS@d9a0e2d

@ylangisc

Copy link
Copy Markdown
Contributor Author

@ylangisc thanks for the contribution. While I am going through your changes, I have a question. Why are you not using v4.1, as the latest macOS clients already support it?

apple-oss-distributions/NFS@d9a0e2d

macOS Tahoe is the first version supporting v4.1 but we still have plenty of users using older macOS versions. We try to mount with v4.1 and fallback to v4.0 if it's not supported.

@kofemann

Copy link
Copy Markdown
Member

I am still trying to understand the changes, the pynfs tests looks more happy with our changes:

--- result-short-without-fix.txt	2026-09-23 17:37:14.057706709 +0200
+++ result-short-with-fix.txt	2026-09-23 17:36:57.902320708 +0200
@@ -1,13 +1,13 @@
 RPLY8    st_replay.testUnlockWait                                 : FAILURE
-RPLY7    st_replay.testUnlock                                     : FAILURE
-RPLY3    st_replay.testReplayState2                               : FAILURE
-RPLY2    st_replay.testReplayState1                               : FAILURE
+RPLY7    st_replay.testUnlock                                     : PASS
+RPLY3    st_replay.testReplayState2                               : PASS
+RPLY2    st_replay.testReplayState1                               : PASS
 RPLY4    st_replay.testReplayNonState                             : PASS
 RPLY13   st_replay.testOpenConfirmFail                            : PASS
-RPLY12   st_replay.testOpenConfirm                                : FAILURE
-RPLY1    st_replay.testOpen                                       : FAILURE
+RPLY12   st_replay.testOpenConfirm                                : PASS
+RPLY1    st_replay.testOpen                                       : PASS
 RPLY14   st_replay.testMkdirReplay                                : FAILURE
-RPLY6    st_replay.testLockDenied                                 : FAILURE
+RPLY6    st_replay.testLockDenied                                 : PASS
 RPLY5    st_replay.testLock                                       : FAILURE
 RPLY10   st_replay.testCloseWait                                  : FAILURE
 RPLY11   st_replay.testCloseFail                                  : PASS
@@ -30,7 +30,7 @@
 WRT14    st_write.testLargeWrite                                  : PASS
 WRT13    st_write.testDoubleWrite                                 : PASS
 WRT6d    st_write.testDir                                         : PASS
-WRT18    st_write.testChangeGranularityWrite                      : PASS
+WRT18    st_write.testChangeGranularityWrite                      : FAILURE
 VF5a     st_verify.testWriteOnlyLink                              : PASS
 VF5r     st_verify.testWriteOnlyFile                              : PASS
 VF5d     st_verify.testWriteOnlyDir                               : PASS
@@ -198,7 +198,7 @@
 OPEN29   st_open.testUpgrades                                     : PASS
 OPEN15   st_open.testUnsupportedAttributes                        : FAILURE
 OPEN18   st_open.testShareConflict1                               : PASS
-OPEN30   st_open.testReplay                                       : FAILURE
+OPEN30   st_open.testReplay                                       : PASS
 OPEN6    st_open.testOpenVaporFile                                : PASS
 OPEN5    st_open.testOpenFile                                     : PASS
 MKFILE   st_open.testOpen                                         : PASS
@@ -414,4 +414,4 @@
 ACC2d    st_access.testAllDir                                     : FAILURE
 **************************************************
 Command line asked for 422 of 689 tests
-Of those: 8 Skipped, 61 Failed, 4 Warned, 349 Passed
+Of those: 8 Skipped, 55 Failed, 4 Warned, 355 Passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NFSv4.0: retransmissions of sequenced requests are rejected with NFS4ERR_BAD_SEQID instead of replied with the cached response (rfc7530 9.1.7)

2 participants