summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2016-12-19 22:28:28 +0000
committerrmacklem <rmacklem@FreeBSD.org>2016-12-19 22:28:28 +0000
commit03b964e76b5da3858a8c1df0515ffb6b5c35c6d1 (patch)
tree051bd6327825cb1fdf4bd7d58aadd8453b7a3c13
parent78e82b9267ade8ed8fdcf5bbf68107dea2abc352 (diff)
downloadFreeBSD-src-03b964e76b5da3858a8c1df0515ffb6b5c35c6d1.zip
FreeBSD-src-03b964e76b5da3858a8c1df0515ffb6b5c35c6d1.tar.gz
MFC: r309566
Fix the NFSv4.1 server for Open reclaim after a reboot. The NFSv4.1 server failed to update the nfs-stablerestart file for a client when the client was issued its first Open. As such, recovery of Opens after a server reboot failed with NFSERR_NOGRACE. This patch fixes this. It also changes the code so that it malloc()'s the 1024 byte array instead of allocating it on the kernel stack for both NFSv4.0 and NFSv4.1. Note that this bug only affected NFSv4.1 and only when clients attempted to reclaim Opens after a server reboot.
-rw-r--r--sys/fs/nfsserver/nfs_nfsdstate.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c
index 02ceaaa..e28bc23 100644
--- a/sys/fs/nfsserver/nfs_nfsdstate.c
+++ b/sys/fs/nfsserver/nfs_nfsdstate.c
@@ -2498,6 +2498,8 @@ nfsrv_openctrl(struct nfsrv_descript *nd, vnode_t vp,
struct nfsclient *clp;
int error = 0, haslock = 0, ret, delegate = 1, writedeleg = 1;
int readonly = 0, cbret = 1, getfhret = 0;
+ int gotstate = 0, len = 0;
+ u_char *clidp = NULL;
if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS)
readonly = 1;
@@ -2516,6 +2518,7 @@ nfsrv_openctrl(struct nfsrv_descript *nd, vnode_t vp,
goto out;
}
+ clidp = malloc(NFSV4_OPAQUELIMIT, M_TEMP, M_WAITOK);
tryagain:
MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile),
M_NFSDLOCKFILE, M_WAITOK);
@@ -3178,6 +3181,16 @@ tryagain:
nfsrv_openpluslock++;
nfsrv_delegatecnt++;
}
+ /*
+ * Since NFSv4.1 never does an OpenConfirm, the first
+ * open state will be acquired here.
+ */
+ if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) {
+ clp->lc_flags |= LCL_STAMPEDSTABLE;
+ len = clp->lc_idlen;
+ NFSBCOPY(clp->lc_id, clidp, len);
+ gotstate = 1;
+ }
} else {
*rflagsp |= NFSV4OPEN_RESULTCONFIRM;
new_stp->ls_flags = NFSLCK_NEEDSCONFIRM;
@@ -3214,7 +3227,17 @@ tryagain:
if (new_deleg)
FREE((caddr_t)new_deleg, M_NFSDSTATE);
+ /*
+ * If the NFSv4.1 client just acquired its first open, write a timestamp
+ * to the stable storage file.
+ */
+ if (gotstate != 0) {
+ nfsrv_writestable(clidp, len, NFSNST_NEWSTATE, p);
+ nfsrv_backupstable();
+ }
+
out:
+ free(clidp, M_TEMP);
NFSEXITCODE2(error, nd);
return (error);
}
@@ -3231,7 +3254,7 @@ nfsrv_openupdate(vnode_t vp, struct nfsstate *new_stp, nfsquad_t clientid,
struct nfslockfile *lfp;
u_int32_t bits;
int error = 0, gotstate = 0, len = 0;
- u_char client[NFSV4_OPAQUELIMIT];
+ u_char *clidp = NULL;
/*
* Check for restart conditions (client and server).
@@ -3241,6 +3264,7 @@ nfsrv_openupdate(vnode_t vp, struct nfsstate *new_stp, nfsquad_t clientid,
if (error)
goto out;
+ clidp = malloc(NFSV4_OPAQUELIMIT, M_TEMP, M_WAITOK);
NFSLOCKSTATE();
/*
* Get the open structure via clientid and stateid.
@@ -3319,7 +3343,7 @@ nfsrv_openupdate(vnode_t vp, struct nfsstate *new_stp, nfsquad_t clientid,
if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) {
clp->lc_flags |= LCL_STAMPEDSTABLE;
len = clp->lc_idlen;
- NFSBCOPY(clp->lc_id, client, len);
+ NFSBCOPY(clp->lc_id, clidp, len);
gotstate = 1;
}
NFSUNLOCKSTATE();
@@ -3366,11 +3390,12 @@ nfsrv_openupdate(vnode_t vp, struct nfsstate *new_stp, nfsquad_t clientid,
* to the stable storage file.
*/
if (gotstate != 0) {
- nfsrv_writestable(client, len, NFSNST_NEWSTATE, p);
+ nfsrv_writestable(clidp, len, NFSNST_NEWSTATE, p);
nfsrv_backupstable();
}
out:
+ free(clidp, M_TEMP);
NFSEXITCODE2(error, nd);
return (error);
}
OpenPOWER on IntegriCloud