aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2021-04-05 01:15:54 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2021-04-19 00:41:07 +0000
commit1efbf1a24cfbfb659712ebb29c92b8589485faff (patch)
treedc63486c2f19b0155c437fc2bc71450feff87517
parentb2b7ad916cb78dd01dd9ebf8ce569182159bf5f7 (diff)
downloadsrc-1efbf1a24cfbfb659712ebb29c92b8589485faff.tar.gz
src-1efbf1a24cfbfb659712ebb29c92b8589485faff.zip
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)
-rw-r--r--sys/fs/nfs/nfsrvstate.h2
-rw-r--r--sys/fs/nfsserver/nfs_nfsdstate.c20
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 09b637c14e52..5aafebf0dd77 100644
--- a/sys/fs/nfsserver/nfs_nfsdstate.c
+++ b/sys/fs/nfsserver/nfs_nfsdstate.c
@@ -3071,6 +3071,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);
@@ -3192,6 +3193,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,
@@ -3262,6 +3264,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);
@@ -3340,6 +3343,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,
@@ -5252,7 +5256,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
@@ -5267,11 +5272,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