git: 9edaceca8165 - main - nfsd: cut the Linux NFSv4.1/4.2 some slack w.r.t. RFC5661

Rick Macklem rmacklem at FreeBSD.org
Sun Apr 11 23:54:42 UTC 2021


The branch main has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=9edaceca8165e2864267547311daf145bb520270

commit 9edaceca8165e2864267547311daf145bb520270
Author:     Rick Macklem <rmacklem at FreeBSD.org>
AuthorDate: 2021-04-11 23:51:25 +0000
Commit:     Rick Macklem <rmacklem at FreeBSD.org>
CommitDate: 2021-04-11 23:51:25 +0000

    nfsd: cut the Linux NFSv4.1/4.2 some slack w.r.t. RFC5661
    
    Recent testing of network partitioning a FreeBSD NFSv4.1
    server from a Linux NFSv4.1 client identified problems
    with both the FreeBSD server and Linux client.
    
    Sometimes, after some Linux NFSv4.1/4.2 clients establish
    a new TCP connection, they will advance the sequence number
    for a session slot by 2 instead of 1.
    RFC5661 specifies that a server should reply
    NFS4ERR_SEQ_MISORDERED for this case.
    This might result in a system call error in the client and
    seems to disable future use of the slot by the client.
    Since advancing the sequence number by 2 seems harmless,
    allow this case if vfs.nfs.linuxseqsesshack is non-zero.
    
    Note that, if the order of RPCs is actually reversed,
    a subsequent RPC with a smaller sequence number value
    for the slot will be received.  This will result in
    a NFS4ERR_SEQ_MISORDERED reply.
    This has not been observed during testing.
    Setting vfs.nfs.linuxseqsesshack to 0 will provide
    RFC5661 compliant behaviour.
    
    This fix affects the fairly rare case where a NFSv4
    Linux client does a TCP reconnect and then apparently
    erroneously increments the sequence number for the
    session slot twice during the reconnect cycle.
    
    PR:     254816
    MFC after:      2 weeks
---
 sys/fs/nfs/nfs_commonsubs.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 4afa4c2d9ab4..d7009b1e0ca4 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -98,6 +98,11 @@ int nfs_maxcopyrange = 10 * 1024 * 1024;
 SYSCTL_INT(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
     &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
 
+static int nfs_allowskip_sessionseq = 1;
+SYSCTL_INT(_vfs_nfs, OID_AUTO, linuxseqsesshack, CTLFLAG_RW,
+    &nfs_allowskip_sessionseq, 0, "Allow client to skip ahead one seq# for"
+    " session slot");
+
 /*
  * This array of structures indicates, for V4:
  * retfh - which of 3 types of calling args are used
@@ -4614,7 +4619,7 @@ nfsmout:
  * Handle an NFSv4.1 Sequence request for the session.
  * If reply != NULL, use it to return the cached reply, as required.
  * The client gets a cached reply via this call for callbacks, however the
- * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
+ * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
  */
 int
 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
@@ -4648,12 +4653,24 @@ nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
 		} else
 			/* No reply cached, so just do it. */
 			slots[slotid].nfssl_inprog = 1;
-	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
+	} else if (slots[slotid].nfssl_seq + 1 == seqid ||
+	    (slots[slotid].nfssl_seq + 2 == seqid &&
+	     nfs_allowskip_sessionseq != 0)) {
+		/*
+		 * Allowing the seqid to be ahead by 2 is technically
+		 * a violation of RFC5661, but it seems harmless to do
+		 * and avoids returning NFSERR_SEQMISORDERED to a
+		 * slightly broken Linux NFSv4.1/4.2 client.
+		 * If the RPCs are really out of order, one with a
+		 * lower seqid will be subsequently received and that
+		 * one will get a NFSERR_SEQMISORDERED reply.
+		 * Can be disabled by setting vfs.nfs.linuxseqsesshack to 0.
+		 */
 		if (slots[slotid].nfssl_reply != NULL)
 			m_freem(slots[slotid].nfssl_reply);
 		slots[slotid].nfssl_reply = NULL;
 		slots[slotid].nfssl_inprog = 1;
-		slots[slotid].nfssl_seq++;
+		slots[slotid].nfssl_seq = seqid;
 	} else
 		error = NFSERR_SEQMISORDERED;
 	return (error);


More information about the dev-commits-src-all mailing list