aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2021-04-08 21:04:22 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2021-04-27 23:08:47 +0000
commit84800ef64b9f8b75466c9622b9c105b227a5e2d3 (patch)
tree4882199d4d940e2b69de73d66855c8a057fdb6dc
parent550fcd830db7e8d644795e5fc9bd83ef4604a1c1 (diff)
downloadsrc-84800ef64b9f8b75466c9622b9c105b227a5e2d3.tar.gz
src-84800ef64b9f8b75466c9622b9c105b227a5e2d3.zip
nfsd: fix replies from session cache for retried RPCs
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. The FreeBSD server failed to reply using the cached reply in the session slot when an RPC was retried on the session slot, as indicated by same slot sequence#. This patch fixes this. It should also fix a similar failure for NFSv4.0 mounts, when the sequence# in the open/lock_owner requires a reply be done from an entry locked into the DRC. This fix affects the fairly rare case where a NFSv4 client retries a non-idempotent RPC, such as a lock operation. Note that retries only occur after the client has needed to create a new TCP connection. (cherry picked from commit 05a39c2c1c18cd0c4382a4f58e0952d3f77e7dfa)
-rw-r--r--sys/fs/nfsserver/nfs_nfsdkrpc.c7
-rw-r--r--sys/fs/nfsserver/nfs_nfsdsubs.c2
2 files changed, 8 insertions, 1 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdkrpc.c b/sys/fs/nfsserver/nfs_nfsdkrpc.c
index e1d82b33eb81..f77af2779847 100644
--- a/sys/fs/nfsserver/nfs_nfsdkrpc.c
+++ b/sys/fs/nfsserver/nfs_nfsdkrpc.c
@@ -388,8 +388,13 @@ nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, SVCXPRT *xprt,
m = NULL;
if ((nd->nd_flag & ND_HASSEQUENCE) != 0)
nfsrv_cache_session(nd, &m);
- if (nd->nd_repstat == NFSERR_REPLYFROMCACHE)
+ if (nd->nd_repstat == NFSERR_REPLYFROMCACHE) {
nd->nd_repstat = 0;
+ if (m != NULL) {
+ m_freem(nd->nd_mreq);
+ nd->nd_mreq = m;
+ }
+ }
cacherep = RC_REPLY;
} else {
if (nd->nd_repstat == NFSERR_DONTREPLY)
diff --git a/sys/fs/nfsserver/nfs_nfsdsubs.c b/sys/fs/nfsserver/nfs_nfsdsubs.c
index 382ed291c38b..0080f26ea643 100644
--- a/sys/fs/nfsserver/nfs_nfsdsubs.c
+++ b/sys/fs/nfsserver/nfs_nfsdsubs.c
@@ -1506,6 +1506,8 @@ nfsd_errmap(struct nfsrv_descript *nd)
else if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
nd->nd_repstat == NFSERR_OPILLEGAL)
return (txdr_unsigned(nd->nd_repstat));
+ else if (nd->nd_repstat == NFSERR_REPLYFROMCACHE)
+ return (txdr_unsigned(NFSERR_IO));
else if ((nd->nd_flag & ND_NFSV41) != 0) {
if (nd->nd_repstat == EOPNOTSUPP)
nd->nd_repstat = NFSERR_NOTSUPP;