svn commit: r253435 - projects/nfsv4.1-server/sys/fs/nfsserver
Rick Macklem
rmacklem at FreeBSD.org
Wed Jul 17 23:03:11 UTC 2013
Author: rmacklem
Date: Wed Jul 17 23:03:10 2013
New Revision: 253435
URL: http://svnweb.freebsd.org/changeset/base/253435
Log:
Merge in the NFSv4.1 changes for the NFSv4 state handling code.
Modified:
projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdstate.c
Modified: projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdstate.c Wed Jul 17 19:41:16 2013 (r253434)
+++ projects/nfsv4.1-server/sys/fs/nfsserver/nfs_nfsdstate.c Wed Jul 17 23:03:10 2013 (r253435)
@@ -51,6 +51,7 @@ NFSSTATESPINLOCK;
*/
struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE];
+struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE];
#endif /* !APPLEKEXT */
static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0;
@@ -89,7 +90,8 @@ static void nfsrv_updatelock(struct nfss
static int nfsrv_getipnumber(u_char *cp);
static int nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags,
nfsv4stateid_t *stateidp, int specialid);
-static int nfsrv_checkgrace(u_int32_t flags);
+static int nfsrv_checkgrace(struct nfsrv_descript *nd, struct nfsclient *clp,
+ u_int32_t flags);
static int nfsrv_docallback(struct nfsclient *clp, int procnum,
nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp,
struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p);
@@ -123,6 +125,8 @@ static void nfsrv_locallock_commit(struc
uint64_t first, uint64_t end);
static void nfsrv_locklf(struct nfslockfile *lfp);
static void nfsrv_unlocklf(struct nfslockfile *lfp);
+static struct nfsdsession *nfsrv_findsession(uint8_t *sessionid);
+static int nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid);
/*
* Scan the client list for a match and either return the current one,
@@ -191,6 +195,18 @@ nfsrv_setclient(struct nfsrv_descript *n
}
if (!gotit ||
(clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_ADMINREVOKED))) {
+ if ((nd->nd_flag & ND_NFSV41) != 0 && confirmp->lval[1] != 0) {
+ /*
+ * For NFSv4.1, if confirmp->lval[1] is non-zero, the
+ * client is trying to update a confirmed clientid.
+ */
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_unlock(&nfsv4rootfs_lock, 1);
+ NFSUNLOCKV4ROOTMUTEX();
+ confirmp->lval[1] = 0;
+ error = NFSERR_NOENT;
+ goto out;
+ }
/*
* Get rid of the old one.
*/
@@ -205,7 +221,12 @@ nfsrv_setclient(struct nfsrv_descript *n
* Add it after assigning a client id to it.
*/
new_clp->lc_flags |= LCL_NEEDSCONFIRM;
- confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index;
+ if ((nd->nd_flag & ND_NFSV41) != 0)
+ new_clp->lc_confirm.lval[0] = confirmp->lval[0] =
+ ++confirm_index;
+ else
+ confirmp->qval = new_clp->lc_confirm.qval =
+ ++confirm_index;
clientidp->lval[0] = new_clp->lc_clientid.lval[0] =
(u_int32_t)nfsrvboottime;
clientidp->lval[1] = new_clp->lc_clientid.lval[1] =
@@ -217,6 +238,7 @@ nfsrv_setclient(struct nfsrv_descript *n
LIST_INIT(&new_clp->lc_open);
LIST_INIT(&new_clp->lc_deleg);
LIST_INIT(&new_clp->lc_olddeleg);
+ LIST_INIT(&new_clp->lc_session);
for (i = 0; i < NFSSTATEHASHSIZE; i++)
LIST_INIT(&new_clp->lc_stateid[i]);
LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp,
@@ -289,7 +311,12 @@ nfsrv_setclient(struct nfsrv_descript *n
*/
LIST_REMOVE(clp, lc_hash);
new_clp->lc_flags |= LCL_NEEDSCONFIRM;
- confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index;
+ if ((nd->nd_flag & ND_NFSV41) != 0)
+ new_clp->lc_confirm.lval[0] = confirmp->lval[0] =
+ ++confirm_index;
+ else
+ confirmp->qval = new_clp->lc_confirm.qval =
+ ++confirm_index;
clientidp->lval[0] = new_clp->lc_clientid.lval[0] =
nfsrvboottime;
clientidp->lval[1] = new_clp->lc_clientid.lval[1] =
@@ -342,60 +369,68 @@ nfsrv_setclient(struct nfsrv_descript *n
*new_clpp = NULL;
goto out;
}
- /*
- * id and verifier match, so update the net address info
- * and get rid of any existing callback authentication
- * handle, so a new one will be acquired.
- */
- LIST_REMOVE(clp, lc_hash);
- new_clp->lc_flags |= (LCL_NEEDSCONFIRM | LCL_DONTCLEAN);
- new_clp->lc_expiry = nfsrv_leaseexpiry();
- confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index;
- clientidp->lval[0] = new_clp->lc_clientid.lval[0] =
- clp->lc_clientid.lval[0];
- clientidp->lval[1] = new_clp->lc_clientid.lval[1] =
- clp->lc_clientid.lval[1];
- new_clp->lc_delegtime = clp->lc_delegtime;
- new_clp->lc_stateindex = clp->lc_stateindex;
- new_clp->lc_statemaxindex = clp->lc_statemaxindex;
- new_clp->lc_cbref = 0;
- LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list);
- LIST_FOREACH(tstp, &new_clp->lc_open, ls_list)
- tstp->ls_clp = new_clp;
- LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list);
- LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list)
- tstp->ls_clp = new_clp;
- LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list);
- LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list)
- tstp->ls_clp = new_clp;
- for (i = 0; i < NFSSTATEHASHSIZE; i++) {
- LIST_NEWHEAD(&new_clp->lc_stateid[i], &clp->lc_stateid[i],
- ls_hash);
- LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash)
+
+ /* For NFSv4.1, mark that we found a confirmed clientid. */
+ if ((nd->nd_flag & ND_NFSV41) != 0)
+ confirmp->lval[1] = 1;
+ else {
+ /*
+ * id and verifier match, so update the net address info
+ * and get rid of any existing callback authentication
+ * handle, so a new one will be acquired.
+ */
+ LIST_REMOVE(clp, lc_hash);
+ new_clp->lc_flags |= (LCL_NEEDSCONFIRM | LCL_DONTCLEAN);
+ new_clp->lc_expiry = nfsrv_leaseexpiry();
+ confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index;
+ clientidp->lval[0] = new_clp->lc_clientid.lval[0] =
+ clp->lc_clientid.lval[0];
+ clientidp->lval[1] = new_clp->lc_clientid.lval[1] =
+ clp->lc_clientid.lval[1];
+ new_clp->lc_delegtime = clp->lc_delegtime;
+ new_clp->lc_stateindex = clp->lc_stateindex;
+ new_clp->lc_statemaxindex = clp->lc_statemaxindex;
+ new_clp->lc_cbref = 0;
+ LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list);
+ LIST_FOREACH(tstp, &new_clp->lc_open, ls_list)
tstp->ls_clp = new_clp;
+ LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list);
+ LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list)
+ tstp->ls_clp = new_clp;
+ LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list);
+ LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list)
+ tstp->ls_clp = new_clp;
+ for (i = 0; i < NFSSTATEHASHSIZE; i++) {
+ LIST_NEWHEAD(&new_clp->lc_stateid[i],
+ &clp->lc_stateid[i], ls_hash);
+ LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash)
+ tstp->ls_clp = new_clp;
+ }
+ LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp,
+ lc_hash);
+ newnfsstats.srvclients++;
+ nfsrv_openpluslock++;
+ nfsrv_clients++;
}
- LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp,
- lc_hash);
- newnfsstats.srvclients++;
- nfsrv_openpluslock++;
- nfsrv_clients++;
NFSLOCKV4ROOTMUTEX();
nfsv4_unlock(&nfsv4rootfs_lock, 1);
NFSUNLOCKV4ROOTMUTEX();
- /*
- * Must wait until any outstanding callback on the old clp
- * completes.
- */
- NFSLOCKSTATE();
- while (clp->lc_cbref) {
- clp->lc_flags |= LCL_WAKEUPWANTED;
- (void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1, "nfsd clp",
- 10 * hz);
+ if ((nd->nd_flag & ND_NFSV41) == 0) {
+ /*
+ * Must wait until any outstanding callback on the old clp
+ * completes.
+ */
+ NFSLOCKSTATE();
+ while (clp->lc_cbref) {
+ clp->lc_flags |= LCL_WAKEUPWANTED;
+ (void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1,
+ "nfsdclp", 10 * hz);
+ }
+ NFSUNLOCKSTATE();
+ nfsrv_zapclient(clp, p);
+ *new_clpp = NULL;
}
- NFSUNLOCKSTATE();
- nfsrv_zapclient(clp, p);
- *new_clpp = NULL;
out:
NFSEXITCODE2(error, nd);
@@ -407,17 +442,23 @@ out:
*/
APPLESTATIC int
nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
- nfsquad_t confirm, struct nfsrv_descript *nd, NFSPROC_T *p)
+ struct nfsdsession *nsep, nfsquad_t confirm, uint32_t cbprogram,
+ struct nfsrv_descript *nd, NFSPROC_T *p)
{
struct nfsclient *clp;
struct nfsstate *stp;
int i;
struct nfsclienthashhead *hp;
int error = 0, igotlock, doneok;
+ struct nfssessionhash *shp;
+ struct nfsdsession *sep;
+ uint64_t sessid[2];
+ static uint64_t next_sess = 0;
if (clpp)
*clpp = NULL;
- if (nfsrvboottime != clientid.lval[0]) {
+ if ((nd == NULL || (nd->nd_flag & ND_NFSV41) == 0 ||
+ opflags != CLOPS_RENEW) && nfsrvboottime != clientid.lval[0]) {
error = NFSERR_STALECLIENTID;
goto out;
}
@@ -434,17 +475,39 @@ nfsrv_getclient(nfsquad_t clientid, int
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
NFSV4ROOTLOCKMUTEXPTR, NULL);
} while (!igotlock);
+ /*
+ * Create a new sessionid here, since we need to do it where
+ * there is a mutex held to serialize update of next_sess.
+ */
+ if ((nd->nd_flag & ND_NFSV41) != 0) {
+ sessid[0] = ++next_sess;
+ sessid[1] = clientid.qval;
+ }
NFSUNLOCKV4ROOTMUTEX();
} else if (opflags != CLOPS_RENEW) {
NFSLOCKSTATE();
}
- hp = NFSCLIENTHASH(clientid);
- LIST_FOREACH(clp, hp, lc_hash) {
- if (clp->lc_clientid.lval[1] == clientid.lval[1])
- break;
+ /* For NFSv4.1, the clp is acquired from the associated session. */
+ if (nd != NULL && (nd->nd_flag & ND_NFSV41) != 0 &&
+ opflags == CLOPS_RENEW) {
+ clp = NULL;
+ if ((nd->nd_flag & ND_HASSEQUENCE) != 0) {
+ shp = NFSSESSIONHASH(nd->nd_sessionid);
+ NFSLOCKSESSION(shp);
+ sep = nfsrv_findsession(nd->nd_sessionid);
+ if (sep != NULL)
+ clp = sep->sess_clp;
+ NFSUNLOCKSESSION(shp);
+ }
+ } else {
+ hp = NFSCLIENTHASH(clientid);
+ LIST_FOREACH(clp, hp, lc_hash) {
+ if (clp->lc_clientid.lval[1] == clientid.lval[1])
+ break;
+ }
}
- if (clp == LIST_END(hp)) {
+ if (clp == NULL) {
if (opflags & CLOPS_CONFIRM)
error = NFSERR_STALECLIENTID;
else
@@ -470,7 +533,10 @@ nfsrv_getclient(nfsquad_t clientid, int
* Perform any operations specified by the opflags.
*/
if (opflags & CLOPS_CONFIRM) {
- if (clp->lc_confirm.qval != confirm.qval)
+ if (((nd->nd_flag & ND_NFSV41) != 0 &&
+ clp->lc_confirm.lval[0] != confirm.lval[0]) ||
+ ((nd->nd_flag & ND_NFSV41) == 0 &&
+ clp->lc_confirm.qval != confirm.qval))
error = NFSERR_STALECLIENTID;
else if (nfsrv_notsamecredname(nd, clp))
error = NFSERR_CLIDINUSE;
@@ -485,7 +551,7 @@ nfsrv_getclient(nfsquad_t clientid, int
*/
nfsrv_cleanclient(clp, p);
nfsrv_freedeleglist(&clp->lc_olddeleg);
- if (nfsrv_checkgrace(0)) {
+ if (nfsrv_checkgrace(nd, clp, 0)) {
/* In grace, so just delete delegations */
nfsrv_freedeleglist(&clp->lc_deleg);
} else {
@@ -496,10 +562,23 @@ nfsrv_getclient(nfsquad_t clientid, int
LIST_NEWHEAD(&clp->lc_olddeleg, &clp->lc_deleg,
ls_list);
}
+ if ((nd->nd_flag & ND_NFSV41) != 0)
+ clp->lc_program = cbprogram;
}
clp->lc_flags &= ~(LCL_NEEDSCONFIRM | LCL_DONTCLEAN);
if (clp->lc_program)
clp->lc_flags |= LCL_NEEDSCBNULL;
+ /* For NFSv4.1, link the session onto the client. */
+ if (nsep != NULL) {
+ NFSBCOPY(sessid, nsep->sess_sessionid,
+ NFSX_V4SESSIONID);
+ shp = NFSSESSIONHASH(nsep->sess_sessionid);
+ NFSLOCKSESSION(shp);
+ LIST_INSERT_HEAD(&shp->list, nsep, sess_hash);
+ LIST_INSERT_HEAD(&clp->lc_session, nsep, sess_list);
+ nsep->sess_clp = clp;
+ NFSUNLOCKSESSION(shp);
+ }
}
} else if (clp->lc_flags & LCL_NEEDSCONFIRM) {
error = NFSERR_EXPIRED;
@@ -546,6 +625,74 @@ out:
}
/*
+ * Perform the NFSv4.1 destroy clientid.
+ */
+int
+nfsrv_destroyclient(nfsquad_t clientid, NFSPROC_T *p)
+{
+ struct nfsclient *clp;
+ struct nfsclienthashhead *hp;
+ int error = 0, i, igotlock;
+
+ if (nfsrvboottime != clientid.lval[0]) {
+ error = NFSERR_STALECLIENTID;
+ goto out;
+ }
+
+ /* Lock out other nfsd threads */
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_relref(&nfsv4rootfs_lock);
+ do {
+ igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
+ NFSV4ROOTLOCKMUTEXPTR, NULL);
+ } while (igotlock == 0);
+ NFSUNLOCKV4ROOTMUTEX();
+
+ hp = NFSCLIENTHASH(clientid);
+ LIST_FOREACH(clp, hp, lc_hash) {
+ if (clp->lc_clientid.lval[1] == clientid.lval[1])
+ break;
+ }
+ if (clp == NULL) {
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_unlock(&nfsv4rootfs_lock, 1);
+ NFSUNLOCKV4ROOTMUTEX();
+ /* Just return ok, since it is gone. */
+ goto out;
+ }
+
+ /* Scan for state on the clientid. */
+ for (i = 0; i < NFSSTATEHASHSIZE; i++)
+ if (!LIST_EMPTY(&clp->lc_stateid[i])) {
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_unlock(&nfsv4rootfs_lock, 1);
+ NFSUNLOCKV4ROOTMUTEX();
+ error = NFSERR_CLIENTIDBUSY;
+ goto out;
+ }
+ if (!LIST_EMPTY(&clp->lc_session) || !LIST_EMPTY(&clp->lc_deleg)) {
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_unlock(&nfsv4rootfs_lock, 1);
+ NFSUNLOCKV4ROOTMUTEX();
+ error = NFSERR_CLIENTIDBUSY;
+ goto out;
+ }
+
+ /* Destroy the clientid and return ok. */
+ nfsrv_cleanclient(clp, p);
+ nfsrv_freedeleglist(&clp->lc_deleg);
+ nfsrv_freedeleglist(&clp->lc_olddeleg);
+ LIST_REMOVE(clp, lc_hash);
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_unlock(&nfsv4rootfs_lock, 1);
+ NFSUNLOCKV4ROOTMUTEX();
+ nfsrv_zapclient(clp, p);
+out:
+ NFSEXITCODE2(error, nd);
+ return (error);
+}
+
+/*
* Called from the new nfssvc syscall to admin revoke a clientid.
* Returns 0 for success, error otherwise.
*/
@@ -983,9 +1130,13 @@ APPLESTATIC void
nfsrv_cleanclient(struct nfsclient *clp, NFSPROC_T *p)
{
struct nfsstate *stp, *nstp;
+ struct nfsdsession *sep, *nsep;
LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp)
nfsrv_freeopenowner(stp, 1, p);
+ if ((clp->lc_flags & LCL_ADMINREVOKED) == 0)
+ LIST_FOREACH_SAFE(sep, &clp->lc_session, sess_list, nsep)
+ (void)nfsrv_freesession(sep, NULL);
}
/*
@@ -1425,8 +1576,8 @@ tryagain:
* lease, but the concensus seems to be that it is ok
* for a server to do so.
*/
- error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp,
- (nfsquad_t)((u_quad_t)0), NULL, p);
+ error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
+ (nfsquad_t)((u_quad_t)0), 0, nd, p);
/*
* Since NFSERR_EXPIRED, NFSERR_ADMINREVOKED are not valid
@@ -1438,8 +1589,8 @@ tryagain:
error = 0;
lckstp = new_stp;
} else {
- error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp,
- (nfsquad_t)((u_quad_t)0), NULL, p);
+ error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
+ (nfsquad_t)((u_quad_t)0), 0, nd, p);
if (error == 0)
/*
* Look up the stateid
@@ -1528,8 +1679,11 @@ tryagain:
* allow for either server configuration.)
*/
if (!error && stp->ls_stateid.seqid!=new_stp->ls_stateid.seqid &&
- (!(new_stp->ls_flags & NFSLCK_CHECK) ||
- nfsrv_returnoldstateid))
+ (((nd->nd_flag & ND_NFSV41) == 0 &&
+ (!(new_stp->ls_flags & NFSLCK_CHECK) ||
+ nfsrv_returnoldstateid)) ||
+ ((nd->nd_flag & ND_NFSV41) != 0 &&
+ new_stp->ls_stateid.seqid != 0)))
error = NFSERR_OLDSTATEID;
}
}
@@ -1538,7 +1692,7 @@ tryagain:
* Now we can check for grace.
*/
if (!error)
- error = nfsrv_checkgrace(new_stp->ls_flags);
+ error = nfsrv_checkgrace(nd, clp, new_stp->ls_flags);
if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error &&
nfsrv_checkstable(clp))
error = NFSERR_NOGRACE;
@@ -1785,6 +1939,8 @@ tryagain:
end = new_lop->lo_end;
nfsrv_updatelock(stp, new_lopp, &other_lop, lfp);
stateidp->seqid = ++(stp->ls_stateid.seqid);
+ if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0)
+ stateidp->seqid = stp->ls_stateid.seqid = 1;
stateidp->other[0] = stp->ls_stateid.other[0];
stateidp->other[1] = stp->ls_stateid.other[1];
stateidp->other[2] = stp->ls_stateid.other[2];
@@ -1892,6 +2048,8 @@ tryagain:
if (!(new_stp->ls_flags & NFSLCK_OPENTOLOCK)) {
nfsrv_updatelock(lckstp, new_lopp, &other_lop, lfp);
stateidp->seqid = ++(lckstp->ls_stateid.seqid);
+ if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0)
+ stateidp->seqid = lckstp->ls_stateid.seqid = 1;
stateidp->other[0] = lckstp->ls_stateid.other[0];
stateidp->other[1] = lckstp->ls_stateid.other[1];
stateidp->other[2] = lckstp->ls_stateid.other[2];
@@ -1991,8 +2149,8 @@ tryagain:
/*
* Get the nfsclient structure.
*/
- error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp,
- (nfsquad_t)((u_quad_t)0), NULL, p);
+ error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
+ (nfsquad_t)((u_quad_t)0), 0, nd, p);
/*
* Look up the open owner. See if it needs confirmation and
@@ -2018,7 +2176,7 @@ tryagain:
* Check for grace.
*/
if (!error)
- error = nfsrv_checkgrace(new_stp->ls_flags);
+ error = nfsrv_checkgrace(nd, clp, new_stp->ls_flags);
if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error &&
nfsrv_checkstable(clp))
error = NFSERR_NOGRACE;
@@ -2252,8 +2410,8 @@ tryagain:
* storage file must be written prior to completion of state
* expiration.
*/
- error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp,
- (nfsquad_t)((u_quad_t)0), NULL, p);
+ error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
+ (nfsquad_t)((u_quad_t)0), 0, nd, p);
if (!error && (clp->lc_flags & LCL_NEEDSCBNULL) &&
clp->lc_program) {
/*
@@ -2506,7 +2664,7 @@ tryagain:
LIST_REMOVE(stp, ls_list);
LIST_REMOVE(stp, ls_hash);
stp->ls_flags &= ~NFSLCK_OLDDELEG;
- stp->ls_stateid.seqid = delegstateidp->seqid = 0;
+ stp->ls_stateid.seqid = delegstateidp->seqid = 1;
stp->ls_stateid.other[0] = delegstateidp->other[0] =
clp->lc_clientid.lval[0];
stp->ls_stateid.other[1] = delegstateidp->other[1] =
@@ -2527,7 +2685,7 @@ tryagain:
/*
* Now, do the associated open.
*/
- new_open->ls_stateid.seqid = 0;
+ new_open->ls_stateid.seqid = 1;
new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0];
new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1];
new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp);
@@ -2592,7 +2750,7 @@ tryagain:
* First, add the delegation. (Although we must issue the
* delegation, we can also ask for an immediate return.)
*/
- new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0;
+ new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1;
new_deleg->ls_stateid.other[0] = delegstateidp->other[0] =
clp->lc_clientid.lval[0];
new_deleg->ls_stateid.other[1] = delegstateidp->other[1] =
@@ -2631,7 +2789,7 @@ tryagain:
/*
* Now, do the associated open.
*/
- new_open->ls_stateid.seqid = 0;
+ new_open->ls_stateid.seqid = 1;
new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0];
new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1];
new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp);
@@ -2686,7 +2844,7 @@ tryagain:
stp = LIST_FIRST(&ownerstp->ls_open);
stp->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) |
NFSLCK_OPEN;
- stp->ls_stateid.seqid = 0;
+ stp->ls_stateid.seqid = 1;
stp->ls_uid = new_stp->ls_uid;
if (lfp != stp->ls_lfp) {
LIST_REMOVE(stp, ls_file);
@@ -2697,6 +2855,9 @@ tryagain:
} else if (openstp) {
openstp->ls_flags |= (new_stp->ls_flags & NFSLCK_SHAREBITS);
openstp->ls_stateid.seqid++;
+ if ((nd->nd_flag & ND_NFSV41) != 0 &&
+ openstp->ls_stateid.seqid == 0)
+ openstp->ls_stateid.seqid = 1;
/*
* This is where we can choose to issue a delegation.
@@ -2708,7 +2869,7 @@ tryagain:
LCL_CALLBACKSON &&
!NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) &&
NFSVNO_DELEGOK(vp)) {
- new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0;
+ new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1;
new_deleg->ls_stateid.other[0] = delegstateidp->other[0]
= clp->lc_clientid.lval[0];
new_deleg->ls_stateid.other[1] = delegstateidp->other[1]
@@ -2733,7 +2894,7 @@ tryagain:
nfsrv_delegatecnt++;
}
} else {
- new_open->ls_stateid.seqid = 0;
+ new_open->ls_stateid.seqid = 1;
new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0];
new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1];
new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp);
@@ -2762,7 +2923,7 @@ tryagain:
LCL_CALLBACKSON &&
!NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) &&
NFSVNO_DELEGOK(vp)) {
- new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0;
+ new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1;
new_deleg->ls_stateid.other[0] = delegstateidp->other[0]
= clp->lc_clientid.lval[0];
new_deleg->ls_stateid.other[1] = delegstateidp->other[1]
@@ -2800,7 +2961,7 @@ tryagain:
* Needs confirmation (unless a reclaim) and hang the
* new open off it.
*/
- new_open->ls_stateid.seqid = 0;
+ new_open->ls_stateid.seqid = 1;
new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0];
new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1];
new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp);
@@ -2814,6 +2975,9 @@ tryagain:
LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file);
if (new_stp->ls_flags & NFSLCK_RECLAIM) {
new_stp->ls_flags = 0;
+ } else if ((nd->nd_flag & ND_NFSV41) != 0) {
+ /* NFSv4.1 never needs confirmation. */
+ new_stp->ls_flags = 0;
} else {
*rflagsp |= NFSV4OPEN_RESULTCONFIRM;
new_stp->ls_flags = NFSLCK_NEEDSCONFIRM;
@@ -2881,8 +3045,8 @@ nfsrv_openupdate(vnode_t vp, struct nfss
/*
* Get the open structure via clientid and stateid.
*/
- error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp,
- (nfsquad_t)((u_quad_t)0), NULL, p);
+ error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
+ (nfsquad_t)((u_quad_t)0), 0, nd, p);
if (!error)
error = nfsrv_getstate(clp, &new_stp->ls_stateid,
new_stp->ls_flags, &stp);
@@ -2901,7 +3065,10 @@ nfsrv_openupdate(vnode_t vp, struct nfss
error = nfsrv_checkseqid(nd, new_stp->ls_seq,
stp->ls_openowner, new_stp->ls_op);
if (!error && stp->ls_stateid.seqid != new_stp->ls_stateid.seqid &&
- !(new_stp->ls_flags & NFSLCK_CONFIRM))
+ (((nd->nd_flag & ND_NFSV41) == 0 &&
+ !(new_stp->ls_flags & NFSLCK_CONFIRM)) ||
+ ((nd->nd_flag & ND_NFSV41) != 0 &&
+ new_stp->ls_stateid.seqid != 0)))
error = NFSERR_OLDSTATEID;
if (!error && vnode_vtype(vp) != VREG) {
if (vnode_vtype(vp) == VDIR)
@@ -2929,6 +3096,8 @@ nfsrv_openupdate(vnode_t vp, struct nfss
* Set the return stateid.
*/
stateidp->seqid = stp->ls_stateid.seqid + 1;
+ if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0)
+ stateidp->seqid = 1;
stateidp->other[0] = stp->ls_stateid.other[0];
stateidp->other[1] = stp->ls_stateid.other[1];
stateidp->other[2] = stp->ls_stateid.other[2];
@@ -2944,6 +3113,9 @@ nfsrv_openupdate(vnode_t vp, struct nfss
printf("Nfsv4d: stray open confirm\n");
stp->ls_openowner->ls_flags = 0;
stp->ls_stateid.seqid++;
+ if ((nd->nd_flag & ND_NFSV41) != 0 &&
+ stp->ls_stateid.seqid == 0)
+ stp->ls_stateid.seqid = 1;
if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) {
clp->lc_flags |= LCL_STAMPEDSTABLE;
len = clp->lc_idlen;
@@ -2980,6 +3152,9 @@ nfsrv_openupdate(vnode_t vp, struct nfss
}
stp->ls_flags = (bits | NFSLCK_OPEN);
stp->ls_stateid.seqid++;
+ if ((nd->nd_flag & ND_NFSV41) != 0 &&
+ stp->ls_stateid.seqid == 0)
+ stp->ls_stateid.seqid = 1;
NFSUNLOCKSTATE();
}
@@ -3001,8 +3176,9 @@ out:
* Delegation update. Does the purge and return.
*/
APPLESTATIC int
-nfsrv_delegupdate(nfsquad_t clientid, nfsv4stateid_t *stateidp,
- vnode_t vp, int op, struct ucred *cred, NFSPROC_T *p)
+nfsrv_delegupdate(struct nfsrv_descript *nd, nfsquad_t clientid,
+ nfsv4stateid_t *stateidp, vnode_t vp, int op, struct ucred *cred,
+ NFSPROC_T *p)
{
struct nfsstate *stp;
struct nfsclient *clp;
@@ -3032,8 +3208,8 @@ nfsrv_delegupdate(nfsquad_t clientid, nf
* Get the open structure via clientid and stateid.
*/
if (!error)
- error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp,
- (nfsquad_t)((u_quad_t)0), NULL, p);
+ error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
+ (nfsquad_t)((u_quad_t)0), 0, nd, p);
if (error) {
if (error == NFSERR_CBPATHDOWN)
error = 0;
@@ -3042,7 +3218,8 @@ nfsrv_delegupdate(nfsquad_t clientid, nf
}
if (!error && op == NFSV4OP_DELEGRETURN) {
error = nfsrv_getstate(clp, stateidp, NFSLCK_DELEGRETURN, &stp);
- if (!error && stp->ls_stateid.seqid != stateidp->seqid)
+ if (!error && stp->ls_stateid.seqid != stateidp->seqid &&
+ ((nd->nd_flag & ND_NFSV41) == 0 || stateidp->seqid != 0))
error = NFSERR_OLDSTATEID;
}
/*
@@ -3101,8 +3278,8 @@ nfsrv_releaselckown(struct nfsstate *new
/*
* Get the lock owner by name.
*/
- error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp,
- (nfsquad_t)((u_quad_t)0), NULL, p);
+ error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
+ (nfsquad_t)((u_quad_t)0), 0, NULL, p);
if (error) {
NFSUNLOCKSTATE();
goto out;
@@ -3420,6 +3597,9 @@ nfsrv_checkseqid(struct nfsrv_descript *
{
int error = 0;
+ if ((nd->nd_flag & ND_NFSV41) != 0)
+ /* NFSv4.1 ignores the open_seqid and lock_seqid. */
+ goto out;
if (op != nd->nd_rp)
panic("nfsrvstate checkseqid");
if (!(op->rc_flag & RC_INPROG))
@@ -3638,7 +3818,7 @@ nfsrv_checkrestart(nfsquad_t clientid, u
goto out;
NFSLOCKSTATE();
- ret = nfsrv_checkgrace(flags);
+ ret = nfsrv_checkgrace(NULL, NULL, flags);
NFSUNLOCKSTATE();
out:
@@ -3650,11 +3830,14 @@ out:
* Check for grace.
*/
static int
-nfsrv_checkgrace(u_int32_t flags)
+nfsrv_checkgrace(struct nfsrv_descript *nd, struct nfsclient *clp,
+ u_int32_t flags)
{
int error = 0;
- if (nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) {
+ if ((nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) != 0 ||
+ (nd != NULL && clp != NULL && (nd->nd_flag & ND_NFSV41) != 0 &&
+ (clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0)) {
if (flags & NFSLCK_RECLAIM) {
error = NFSERR_NOGRACE;
goto out;
@@ -5282,3 +5465,216 @@ nfsrv_throwawayallstate(NFSPROC_T *p)
}
}
+/*
+ * Check the sequence# for the session and slot provided as an argument.
+ * Also, renew the lease if the session will return NFS_OK.
+ */
+int
+nfsrv_checksequence(struct nfsrv_descript *nd, uint32_t sequenceid,
+ uint32_t *highest_slotidp, uint32_t *target_highest_slotidp, int cache_this,
+ uint32_t *sflagsp, NFSPROC_T *p)
+{
+ struct nfsdsession *sep;
+ struct nfssessionhash *shp;
+ int error;
+
+ shp = NFSSESSIONHASH(nd->nd_sessionid);
+ NFSLOCKSESSION(shp);
+ sep = nfsrv_findsession(nd->nd_sessionid);
+ if (sep == NULL) {
+ NFSUNLOCKSESSION(shp);
+ return (NFSERR_BADSESSION);
+ }
+ error = nfsv4_seqsession(sequenceid, nd->nd_slotid, *highest_slotidp,
+ sep->sess_slots, NULL, NFSV4_SLOTS - 1);
+ if (error != 0) {
+ NFSUNLOCKSESSION(shp);
+ return (error);
+ }
+ if (cache_this != 0)
+ nd->nd_flag |= ND_SAVEREPLY;
+ /* Renew the lease. */
+ sep->sess_clp->lc_expiry = nfsrv_leaseexpiry();
+ NFSUNLOCKSESSION(shp);
+ *sflagsp = 0;
+ if (error == NFSERR_EXPIRED) {
+ *sflagsp |= NFSV4SEQ_EXPIREDALLSTATEREVOKED;
+ error = 0;
+ } else if (error == NFSERR_ADMINREVOKED) {
+ *sflagsp |= NFSV4SEQ_ADMINSTATEREVOKED;
+ error = 0;
+ }
+ *highest_slotidp = *target_highest_slotidp = NFSV4_SLOTS - 1;
+ return (0);
+}
+
+/*
+ * Check/set reclaim complete for this session/clientid.
+ */
+int
+nfsrv_checkreclaimcomplete(struct nfsrv_descript *nd)
+{
+ struct nfsdsession *sep;
+ struct nfssessionhash *shp;
+ int error = 0;
+
+ shp = NFSSESSIONHASH(nd->nd_sessionid);
+ NFSLOCKSTATE();
+ NFSLOCKSESSION(shp);
+ sep = nfsrv_findsession(nd->nd_sessionid);
+ if (sep == NULL) {
+ NFSUNLOCKSESSION(shp);
+ NFSUNLOCKSTATE();
+ return (NFSERR_BADSESSION);
+ }
+
+ /* Check to see if reclaim complete has already happened. */
+ if ((sep->sess_clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0)
+ error = NFSERR_COMPLETEALREADY;
+ else
+ sep->sess_clp->lc_flags |= LCL_RECLAIMCOMPLETE;
+ NFSUNLOCKSESSION(shp);
+ NFSUNLOCKSTATE();
+ return (error);
+}
+
+/*
+ * Cache the reply in a session slot.
+ */
+void
+nfsrv_cache_session(uint8_t *sessionid, uint32_t slotid, int repstat,
+ struct mbuf **m)
+{
+ struct nfsdsession *sep;
+ struct nfssessionhash *shp;
+
+ shp = NFSSESSIONHASH(sessionid);
+ NFSLOCKSESSION(shp);
+ sep = nfsrv_findsession(sessionid);
+ if (sep == NULL) {
+ NFSUNLOCKSESSION(shp);
+ printf("nfsrv_cache_session: no session\n");
+ m_freem(*m);
+ return;
+ }
+ nfsv4_seqsess_cacherep(slotid, sep->sess_slots, repstat, m);
+ NFSUNLOCKSESSION(shp);
+}
+
+/*
+ * Search for a session that matches the sessionid.
+ */
+static struct nfsdsession *
+nfsrv_findsession(uint8_t *sessionid)
+{
+ struct nfsdsession *sep;
+ struct nfssessionhash *shp;
+
+ shp = NFSSESSIONHASH(sessionid);
+ LIST_FOREACH(sep, &shp->list, sess_hash) {
+ if (!NFSBCMP(sessionid, sep->sess_sessionid, NFSX_V4SESSIONID))
+ break;
+ }
+ return (sep);
+}
+
+/*
+ * Destroy a session.
+ */
+int
+nfsrv_destroysession(struct nfsrv_descript *nd, uint8_t *sessionid)
+{
+ int error, samesess;
+
+ samesess = 0;
+ if (!NFSBCMP(sessionid, nd->nd_sessionid, NFSX_V4SESSIONID)) {
+ samesess = 1;
+ if ((nd->nd_flag & ND_LASTOP) == 0)
+ return (NFSERR_BADSESSION);
+ }
+ error = nfsrv_freesession(NULL, sessionid);
+ if (error == 0 && samesess != 0)
+ nd->nd_flag &= ~ND_HASSEQUENCE;
+ return (error);
+}
+
+/*
+ * Free up a session structure.
+ */
+static int
+nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid)
+{
+ struct nfssessionhash *shp;
+ int i;
+
+ if (sep == NULL) {
+ shp = NFSSESSIONHASH(sessionid);
+ NFSLOCKSESSION(shp);
+ sep = nfsrv_findsession(sessionid);
+ } else {
+ shp = NFSSESSIONHASH(sep->sess_sessionid);
+ NFSLOCKSESSION(shp);
+ }
+ if (sep != NULL) {
+ LIST_REMOVE(sep, sess_hash);
+ LIST_REMOVE(sep, sess_list);
+ }
+ NFSUNLOCKSESSION(shp);
+ if (sep == NULL)
+ return (NFSERR_BADSESSION);
+ for (i = 0; i < NFSV4_SLOTS; i++)
+ if (sep->sess_slots[i].nfssl_reply != NULL)
+ m_freem(sep->sess_slots[i].nfssl_reply);
+ free(sep, M_NFSDSESSION);
+ return (0);
+}
+
+/*
+ * Free a stateid.
+ * RFC5661 says that it should fail when there are associated opens, locks
+ * or delegations. Since stateids represent opens, I don't see how you can
+ * free an open stateid (it will be free'd when closed), so this function
+ * only works for lock stateids (freeing the lock_owner) or delegations.
+ */
+int
+nfsrv_freestateid(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
+ NFSPROC_T *p)
+{
+ struct nfsclient *clp;
+ struct nfsstate *stp;
+ int error;
+
+ NFSLOCKSTATE();
+ /*
+ * Look up the stateid
+ */
+ error = nfsrv_getclient((nfsquad_t)((u_quad_t)0), CLOPS_RENEW, &clp,
+ NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
+ if (error == 0) {
+ /* First, check for a delegation. */
+ LIST_FOREACH(stp, &clp->lc_deleg, ls_list) {
+ if (!NFSBCMP(stp->ls_stateid.other, stateidp->other,
+ NFSX_STATEIDOTHER))
+ break;
+ }
+ if (stp != NULL) {
+ nfsrv_freedeleg(stp);
+ NFSUNLOCKSTATE();
+ return (error);
+ }
+ }
+ /* Not a delegation, try for a lock_owner. */
+ if (error == 0)
+ error = nfsrv_getstate(clp, stateidp, 0, &stp);
+ if (error == 0 && ((stp->ls_flags & (NFSLCK_OPEN | NFSLCK_DELEGREAD |
+ NFSLCK_DELEGWRITE)) != 0 || (stp->ls_flags & NFSLCK_LOCK) == 0))
+ /* Not a lock_owner stateid. */
+ error = NFSERR_LOCKSHELD;
+ if (error == 0 && !LIST_EMPTY(&stp->ls_lock))
+ error = NFSERR_LOCKSHELD;
+ if (error == 0)
+ nfsrv_freelockowner(stp, NULL, 0, p);
+ NFSUNLOCKSTATE();
+ return (error);
+}
+
More information about the svn-src-projects
mailing list