git: 14fc640c2e97 - stable/12 - nfsd: fix replies from session cache for multiple retries

Rick Macklem rmacklem at FreeBSD.org
Sat Apr 24 22:56:46 UTC 2021


The branch stable/12 has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=14fc640c2e97885a82a7651b5ef912710e283d13

commit 14fc640c2e97885a82a7651b5ef912710e283d13
Author:     Rick Macklem <rmacklem at FreeBSD.org>
AuthorDate: 2021-04-10 22:50:25 +0000
Commit:     Rick Macklem <rmacklem at FreeBSD.org>
CommitDate: 2021-04-24 22:52:21 +0000

    nfsd: fix replies from session cache for multiple retries
    
    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.
    
    Commit 05a39c2c1c18 fixed replying with the cached reply in
    in the session slot if same session slot sequence#.
    However, the code uses the reply and, as such,
    will fail for a subsequent retry of the RPC.
    A subsequent retry would be an extremely rare event,
    but this patch fixes this, so long as m_copym(..M_NOWAIT)
    does not fail, which should also be a rare event.
    
    This fix affects the exceedingly rare case where a NFSv4
    client retries a non-idempotent RPC, such as a lock
    operation, multiple times.  Note that retries only occur
    after the client has needed to create a new TCP connection,
    with a new TCP connection for each retry.
    
    PR:     254816
    
    (cherry picked from commit 22cefe3d8378f58adcdbb2c7589b9f30c2a38315)
---
 sys/fs/nfs/nfs_commonsubs.c | 34 ++++++++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 9c6bee466272..d004fbb1bc51 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -4561,6 +4561,7 @@ int
 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
 {
+	struct mbuf *m;
 	int error;
 
 	error = 0;
@@ -4574,8 +4575,14 @@ nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
 			error = NFSERR_DELAY;
 		else if (slots[slotid].nfssl_reply != NULL) {
 			if (reply != NULL) {
-				*reply = slots[slotid].nfssl_reply;
-				slots[slotid].nfssl_reply = NULL;
+				m = m_copym(slots[slotid].nfssl_reply, 0,
+				    M_COPYALL, M_NOWAIT);
+				if (m != NULL)
+					*reply = m;
+				else {
+					*reply = slots[slotid].nfssl_reply;
+					slots[slotid].nfssl_reply = NULL;
+				}
 			}
 			slots[slotid].nfssl_inprog = 1;
 			error = NFSERR_REPLYFROMCACHE;
@@ -4602,10 +4609,29 @@ void
 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
    struct mbuf **rep)
 {
+	struct mbuf *m;
 
 	if (repstat == NFSERR_REPLYFROMCACHE) {
-		*rep = slots[slotid].nfssl_reply;
-		slots[slotid].nfssl_reply = NULL;
+		if (slots[slotid].nfssl_reply != NULL) {
+			/*
+			 * We cannot sleep here, but copy will usually
+			 * succeed.
+			 */
+			m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
+			    M_NOWAIT);
+			if (m != NULL)
+				*rep = m;
+			else {
+				/*
+				 * Multiple retries would be extremely rare,
+				 * so using the cached reply will likely
+				 * be ok.
+				 */
+				*rep = slots[slotid].nfssl_reply;
+				slots[slotid].nfssl_reply = NULL;
+			}
+		} else
+			*rep = NULL;
 	} else {
 		if (slots[slotid].nfssl_reply != NULL)
 			m_freem(slots[slotid].nfssl_reply);


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