Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Apr 2021 00:39:53 GMT
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: ccd08b9293ca - stable/13 - nfsd: make the server repeat CB_RECALL every couple of seconds
Message-ID:  <202104190039.13J0dr3a005839@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by rmacklem:

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

commit ccd08b9293cac51b3c4dcb5e0d261cb7aac0ffef
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2021-04-05 01:15:54 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2021-04-19 00:36:26 +0000

    nfsd: make the server repeat CB_RECALL every couple of seconds
    
    Commit 01ae8969a9ee stopped the NFSv4.1/4.2 server from implicitly
    binding the back channel to a new TCP connection so that it
    conforms to RFC5661, for NFSv4.1/4.2. An effect of this
    for the Linux NFS client is that it will do a
    BindConnectionToSession when it sees NFSV4SEQ_CBPATHDOWN
    set in a sequence reply. This will fix the back channel, but the
    first attempt at a callback like CB_RECALL will already have
    failed. Without this patch, a CB_RECALL will not be retried
    and that can result in a 5 minute delay until the delegation
    times out.
    
    This patch modifies the code so that it will retry the
    CB_RECALL every couple of seconds, often avoiding the
    5 minute delay.
    
    This is not critical for correct behaviour, but avoids
    the 5 minute delay for the case where the Linux client
    re-binds the back channel via BindConnectionToSession.
    
    (cherry picked from commit 7a606f280a3e174dcdd12736b7b976903809eb9c)
---
 sys/fs/nfs/nfsrvstate.h          |  2 ++
 sys/fs/nfsserver/nfs_nfsdstate.c | 20 ++++++++++++++------
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/sys/fs/nfs/nfsrvstate.h b/sys/fs/nfs/nfsrvstate.h
index 2d60e8e8141f..427d5b132281 100644
--- a/sys/fs/nfs/nfsrvstate.h
+++ b/sys/fs/nfs/nfsrvstate.h
@@ -220,6 +220,7 @@ struct nfsstate {
 			time_t		expiry;
 			time_t		limit;
 			u_int64_t	compref;
+			time_t		last;
 		} deleg;
 	} ls_un;
 	struct nfslockfile	*ls_lfp;	/* Back pointer */
@@ -238,6 +239,7 @@ struct nfsstate {
 #define	ls_delegtime		ls_un.deleg.expiry
 #define	ls_delegtimelimit	ls_un.deleg.limit
 #define	ls_compref		ls_un.deleg.compref
+#define	ls_lastrecall		ls_un.deleg.last
 
 /*
  * Nfs lock structure.
diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c
index 1cf0dcee99e9..fa7bb3ba9f56 100644
--- a/sys/fs/nfsserver/nfs_nfsdstate.c
+++ b/sys/fs/nfsserver/nfs_nfsdstate.c
@@ -3070,6 +3070,7 @@ tryagain:
 		new_deleg->ls_clp = clp;
 		new_deleg->ls_filerev = filerev;
 		new_deleg->ls_compref = nd->nd_compref;
+		new_deleg->ls_lastrecall = 0;
 		LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file);
 		LIST_INSERT_HEAD(NFSSTATEHASH(clp,
 		    new_deleg->ls_stateid), new_deleg, ls_hash);
@@ -3191,6 +3192,7 @@ tryagain:
 			new_deleg->ls_clp = clp;
 			new_deleg->ls_filerev = filerev;
 			new_deleg->ls_compref = nd->nd_compref;
+			new_deleg->ls_lastrecall = 0;
 			nfsrv_writedelegcnt++;
 			LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file);
 			LIST_INSERT_HEAD(NFSSTATEHASH(clp,
@@ -3261,6 +3263,7 @@ tryagain:
 			new_deleg->ls_clp = clp;
 			new_deleg->ls_filerev = filerev;
 			new_deleg->ls_compref = nd->nd_compref;
+			new_deleg->ls_lastrecall = 0;
 			LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file);
 			LIST_INSERT_HEAD(NFSSTATEHASH(clp,
 			    new_deleg->ls_stateid), new_deleg, ls_hash);
@@ -3339,6 +3342,7 @@ tryagain:
 				new_deleg->ls_clp = clp;
 				new_deleg->ls_filerev = filerev;
 				new_deleg->ls_compref = nd->nd_compref;
+				new_deleg->ls_lastrecall = 0;
 				LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg,
 				    ls_file);
 				LIST_INSERT_HEAD(NFSSTATEHASH(clp,
@@ -5265,7 +5269,8 @@ nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, NFSPROC_T *p,
 	 * - check to see if the delegation has expired
 	 *   - if so, get the v4root lock and then expire it
 	 */
-	if (!(stp->ls_flags & NFSLCK_DELEGRECALL)) {
+	if ((stp->ls_flags & NFSLCK_DELEGRECALL) == 0 || stp->ls_lastrecall <
+	    time_uptime) {
 		/*
 		 * - do a recall callback, since not yet done
 		 * For now, never allow truncate to be set. To use
@@ -5280,11 +5285,14 @@ nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, NFSPROC_T *p,
 		 * will be extended when ops are done on the delegation
 		 * stateid, up to the timelimit.)
 		 */
-		stp->ls_delegtime = NFSD_MONOSEC + (2 * nfsrv_lease) +
-		    NFSRV_LEASEDELTA;
-		stp->ls_delegtimelimit = NFSD_MONOSEC + (6 * nfsrv_lease) +
-		    NFSRV_LEASEDELTA;
-		stp->ls_flags |= NFSLCK_DELEGRECALL;
+		if ((stp->ls_flags & NFSLCK_DELEGRECALL) == 0) {
+			stp->ls_delegtime = NFSD_MONOSEC + (2 * nfsrv_lease) +
+			    NFSRV_LEASEDELTA;
+			stp->ls_delegtimelimit = NFSD_MONOSEC + (6 *
+			    nfsrv_lease) + NFSRV_LEASEDELTA;
+			stp->ls_flags |= NFSLCK_DELEGRECALL;
+		}
+		stp->ls_lastrecall = time_uptime + 1;
 
 		/*
 		 * Loop NFSRV_CBRETRYCNT times while the CBRecall replies



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202104190039.13J0dr3a005839>