aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2023-10-22 01:33:33 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2023-11-21 23:57:43 +0000
commit55671098064f715ae106225513a7241bd6aa46b0 (patch)
tree6aaa84f5eee418defa6e5ec3951a34901efa926e
parent4e583d78b77ce6a3c05b79d82e4ccf2a3a390d8d (diff)
downloadsrc-55671098064f715ae106225513a7241bd6aa46b0.tar.gz
src-55671098064f715ae106225513a7241bd6aa46b0.zip
nfscl: Handle a Getattr failure with NFSERR_DELAY following Open
During testing at a recent IETF NFSv4 Bakeathon, a non-FreeBSD server was rebooted. After the reboot, the FreeBSD client sent an Open/Claim_previous with a Getattr after the Open in the same compound. The Open/Claim_previous was done to recover the Open and a Delegation for for a file. The Open succeeded, but the Getattr after the Open failed with NFSERR_DELAY. This resulted in the FreeBSD client retrying the entire RPC over and over again, until the server's recovery grace period ended. Since the Open succeeded, there was no need to retry the entire RPC. This patch modifies the NFSv4 client side recovery Open/Claim_previous RPC reply handling to deal with this case. With this patch, the Getattr reply of NFSERR_DELAY is ignored and the successful Open reply is processed. This bug will not normally affect users, since this non-FreeBSD server is not widely used (it may not even have shipped to any customers). (cherry picked from commit 14bbf4fe5abb20f1126168e66b03127ae920f78e)
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 5a16a28bd83e..207a51c4aece 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -609,7 +609,8 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
if (error)
return (error);
NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
- if (!nd->nd_repstat) {
+ if (nd->nd_repstat == 0 || (nd->nd_repstat == NFSERR_DELAY &&
+ reclaim != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0)) {
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
6 * NFSX_UNSIGNED);
op->nfso_stateid.seqid = *tl++;
@@ -681,16 +682,29 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
goto nfsmout;
}
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
- error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
- NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
- NULL, NULL, NULL, p, cred);
- if (error)
- goto nfsmout;
+ /* If the 2nd element == NFS_OK, the Getattr succeeded. */
+ if (*++tl == 0) {
+ KASSERT(nd->nd_repstat == 0,
+ ("nfsrpc_openrpc: Getattr repstat"));
+ error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
+ NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
+ NULL, NULL, NULL, p, cred);
+ if (error)
+ goto nfsmout;
+ }
if (ndp != NULL) {
- ndp->nfsdl_change = nfsva.na_filerev;
- ndp->nfsdl_modtime = nfsva.na_mtime;
- ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
+ if (reclaim != 0 && dp != NULL) {
+ ndp->nfsdl_change = dp->nfsdl_change;
+ ndp->nfsdl_modtime = dp->nfsdl_modtime;
+ ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
+ } else if (nd->nd_repstat == 0) {
+ ndp->nfsdl_change = nfsva.na_filerev;
+ ndp->nfsdl_modtime = nfsva.na_mtime;
+ ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
+ } else
+ ndp->nfsdl_flags |= NFSCLDL_RECALL;
}
+ nd->nd_repstat = 0;
if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
do {
ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,