mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-16 06:52:27 +00:00
nfsd: Allow a mutex lock for clientID handling
On Feb. 28, a problem was reported on freebsd-stable@ where a nfsd thread processing an ExchangeID operation was blocked for a long time by another nfsd thread performing a copy_file_range. This occurred because the copy_file_range was taking a long time, but also because handling a clientID requires that all other nfsd threads be blocked via an exclusive lock, as required by ExchangeID. This patch allows clientID handling to be done with only a mutex held (instead of an exclusive lock that blocks all other nfsd threads) when vfs.nfsd.enable_locallocks is 0. For the case of vfs.nfsd.enable_locallocks set to 1, the exclusive lock that blocks all nfsd threads is still required. This patch does make changing the value of vfs.nfsd.enable_locallocks somewhat racy. A future commit will ensure any change is done when all nfsd threads are blocked to avoid this racyness. MFC after: 1 month
This commit is contained in:
parent
48dbc2a4f9
commit
dfaeeacc2c
|
@ -245,6 +245,45 @@ static void nfsrv_issuedelegation(struct vnode *vp, struct nfsclient *clp,
|
||||||
u_quad_t filerev, uint64_t rdonly, struct nfsstate **new_delegp,
|
u_quad_t filerev, uint64_t rdonly, struct nfsstate **new_delegp,
|
||||||
struct nfsstate *new_stp, struct nfslockfile *lfp, uint32_t *rflagsp,
|
struct nfsstate *new_stp, struct nfslockfile *lfp, uint32_t *rflagsp,
|
||||||
nfsv4stateid_t *delegstateidp);
|
nfsv4stateid_t *delegstateidp);
|
||||||
|
static void nfsrv_clientlock(bool mlocked);
|
||||||
|
static void nfsrv_clientunlock(bool mlocked);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock the client structure, either with the mutex or the exclusive nfsd lock.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
nfsrv_clientlock(bool mlocked)
|
||||||
|
{
|
||||||
|
int igotlock;
|
||||||
|
|
||||||
|
if (mlocked) {
|
||||||
|
NFSLOCKSTATE();
|
||||||
|
} else {
|
||||||
|
NFSLOCKV4ROOTMUTEX();
|
||||||
|
nfsv4_relref(&nfsv4rootfs_lock);
|
||||||
|
do {
|
||||||
|
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
|
||||||
|
NFSV4ROOTLOCKMUTEXPTR, NULL);
|
||||||
|
} while (!igotlock);
|
||||||
|
NFSUNLOCKV4ROOTMUTEX();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlock the client structure.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
nfsrv_clientunlock(bool mlocked)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (mlocked) {
|
||||||
|
NFSUNLOCKSTATE();
|
||||||
|
} else {
|
||||||
|
NFSLOCKV4ROOTMUTEX();
|
||||||
|
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
||||||
|
NFSUNLOCKV4ROOTMUTEX();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the client list for a match and either return the current one,
|
* Scan the client list for a match and either return the current one,
|
||||||
|
@ -266,7 +305,10 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
struct sockaddr_in6 *sin6, *rin6;
|
struct sockaddr_in6 *sin6, *rin6;
|
||||||
#endif
|
#endif
|
||||||
struct nfsdsession *sep, *nsep;
|
struct nfsdsession *sep, *nsep;
|
||||||
int zapit = 0, gotit, hasstate = 0, igotlock;
|
SVCXPRT *old_xprt;
|
||||||
|
struct nfssessionhead old_sess;
|
||||||
|
int zapit = 0, gotit, hasstate = 0;
|
||||||
|
bool mlocked;
|
||||||
static u_int64_t confirm_index = 0;
|
static u_int64_t confirm_index = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -294,14 +336,11 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
*/
|
*/
|
||||||
new_clp->lc_program = 0;
|
new_clp->lc_program = 0;
|
||||||
|
|
||||||
|
mlocked = true;
|
||||||
|
if (nfsrv_dolocallocks != 0)
|
||||||
|
mlocked = false;
|
||||||
/* Lock out other nfsd threads */
|
/* Lock out other nfsd threads */
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientlock(mlocked);
|
||||||
nfsv4_relref(&nfsv4rootfs_lock);
|
|
||||||
do {
|
|
||||||
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
|
|
||||||
NFSV4ROOTLOCKMUTEXPTR, NULL);
|
|
||||||
} while (!igotlock);
|
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search for a match in the client list.
|
* Search for a match in the client list.
|
||||||
|
@ -318,6 +357,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
if (gotit == 0)
|
if (gotit == 0)
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
old_xprt = NULL;
|
||||||
if (!gotit ||
|
if (!gotit ||
|
||||||
(clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_ADMINREVOKED))) {
|
(clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_ADMINREVOKED))) {
|
||||||
if ((nd->nd_flag & ND_NFSV41) != 0 && confirmp->lval[1] != 0) {
|
if ((nd->nd_flag & ND_NFSV41) != 0 && confirmp->lval[1] != 0) {
|
||||||
|
@ -325,9 +365,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
* For NFSv4.1, if confirmp->lval[1] is non-zero, the
|
* For NFSv4.1, if confirmp->lval[1] is non-zero, the
|
||||||
* client is trying to update a confirmed clientid.
|
* client is trying to update a confirmed clientid.
|
||||||
*/
|
*/
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
|
||||||
confirmp->lval[1] = 0;
|
confirmp->lval[1] = 0;
|
||||||
error = NFSERR_NOENT;
|
error = NFSERR_NOENT;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -337,7 +375,10 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
*/
|
*/
|
||||||
if (i != nfsrv_clienthashsize) {
|
if (i != nfsrv_clienthashsize) {
|
||||||
LIST_REMOVE(clp, lc_hash);
|
LIST_REMOVE(clp, lc_hash);
|
||||||
nfsrv_cleanclient(clp, p, false, NULL);
|
if (mlocked)
|
||||||
|
nfsrv_cleanclient(clp, p, true, &old_xprt);
|
||||||
|
else
|
||||||
|
nfsrv_cleanclient(clp, p, false, NULL);
|
||||||
nfsrv_freedeleglist(&clp->lc_deleg);
|
nfsrv_freedeleglist(&clp->lc_deleg);
|
||||||
nfsrv_freedeleglist(&clp->lc_olddeleg);
|
nfsrv_freedeleglist(&clp->lc_olddeleg);
|
||||||
zapit = 1;
|
zapit = 1;
|
||||||
|
@ -372,11 +413,12 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
NFSD_VNET(nfsstatsv1_p)->srvclients++;
|
NFSD_VNET(nfsstatsv1_p)->srvclients++;
|
||||||
nfsrv_openpluslock++;
|
nfsrv_openpluslock++;
|
||||||
nfsrv_clients++;
|
nfsrv_clients++;
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
if (zapit != 0) {
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
if (old_xprt != NULL)
|
||||||
if (zapit)
|
SVC_RELEASE(old_xprt);
|
||||||
nfsrv_zapclient(clp, p);
|
nfsrv_zapclient(clp, p);
|
||||||
|
}
|
||||||
*new_clpp = NULL;
|
*new_clpp = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -390,7 +432,10 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
*/
|
*/
|
||||||
if (clp->lc_expiry < NFSD_MONOSEC &&
|
if (clp->lc_expiry < NFSD_MONOSEC &&
|
||||||
(!LIST_EMPTY(&clp->lc_open) || !LIST_EMPTY(&clp->lc_deleg))) {
|
(!LIST_EMPTY(&clp->lc_open) || !LIST_EMPTY(&clp->lc_deleg))) {
|
||||||
nfsrv_cleanclient(clp, p, false, NULL);
|
if (mlocked)
|
||||||
|
nfsrv_cleanclient(clp, p, true, &old_xprt);
|
||||||
|
else
|
||||||
|
nfsrv_cleanclient(clp, p, false, NULL);
|
||||||
nfsrv_freedeleglist(&clp->lc_deleg);
|
nfsrv_freedeleglist(&clp->lc_deleg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,9 +480,9 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
if (old_xprt != NULL)
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
SVC_RELEASE(old_xprt);
|
||||||
error = NFSERR_CLIDINUSE;
|
error = NFSERR_CLIDINUSE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -452,13 +497,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
*/
|
*/
|
||||||
LIST_REMOVE(clp, lc_hash);
|
LIST_REMOVE(clp, lc_hash);
|
||||||
|
|
||||||
/* Get rid of all sessions on this clientid. */
|
LIST_NEWHEAD(&old_sess, &clp->lc_session, sess_list);
|
||||||
LIST_FOREACH_SAFE(sep, &clp->lc_session, sess_list, nsep) {
|
|
||||||
ret = nfsrv_freesession(NULL, sep, NULL, false, NULL);
|
|
||||||
if (ret != 0)
|
|
||||||
printf("nfsrv_setclient: verifier changed free"
|
|
||||||
" session failed=%d\n", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_clp->lc_flags |= LCL_NEEDSCONFIRM;
|
new_clp->lc_flags |= LCL_NEEDSCONFIRM;
|
||||||
if ((nd->nd_flag & ND_NFSV41) != 0) {
|
if ((nd->nd_flag & ND_NFSV41) != 0) {
|
||||||
|
@ -502,21 +541,31 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
NFSD_VNET(nfsstatsv1_p)->srvclients++;
|
NFSD_VNET(nfsstatsv1_p)->srvclients++;
|
||||||
nfsrv_openpluslock++;
|
nfsrv_openpluslock++;
|
||||||
nfsrv_clients++;
|
nfsrv_clients++;
|
||||||
NFSLOCKV4ROOTMUTEX();
|
if (!mlocked) {
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
nfsrv_clientunlock(mlocked);
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
NFSLOCKSTATE();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Must wait until any outstanding callback on the old clp
|
* Must wait until any outstanding callback on the old clp
|
||||||
* completes.
|
* completes.
|
||||||
*/
|
*/
|
||||||
NFSLOCKSTATE();
|
|
||||||
while (clp->lc_cbref) {
|
while (clp->lc_cbref) {
|
||||||
clp->lc_flags |= LCL_WAKEUPWANTED;
|
clp->lc_flags |= LCL_WAKEUPWANTED;
|
||||||
(void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1,
|
(void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1,
|
||||||
"nfsd clp", 10 * hz);
|
"nfsd clp", 10 * hz);
|
||||||
}
|
}
|
||||||
NFSUNLOCKSTATE();
|
NFSUNLOCKSTATE();
|
||||||
|
if (old_xprt != NULL)
|
||||||
|
SVC_RELEASE(old_xprt);
|
||||||
|
/* Get rid of all sessions on this clientid. */
|
||||||
|
LIST_FOREACH_SAFE(sep, &old_sess, sess_list, nsep) {
|
||||||
|
ret = nfsrv_freesession(NULL, sep, NULL, false, NULL);
|
||||||
|
if (ret != 0)
|
||||||
|
printf("nfsrv_setclient: verifier changed free"
|
||||||
|
" session failed=%d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
nfsrv_zapclient(clp, p);
|
nfsrv_zapclient(clp, p);
|
||||||
*new_clpp = NULL;
|
*new_clpp = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -568,24 +617,31 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
|
||||||
nfsrv_openpluslock++;
|
nfsrv_openpluslock++;
|
||||||
nfsrv_clients++;
|
nfsrv_clients++;
|
||||||
}
|
}
|
||||||
NFSLOCKV4ROOTMUTEX();
|
if (!mlocked)
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
nfsrv_clientunlock(mlocked);
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
|
||||||
|
|
||||||
if ((nd->nd_flag & ND_NFSV41) == 0) {
|
if ((nd->nd_flag & ND_NFSV41) == 0) {
|
||||||
/*
|
/*
|
||||||
* Must wait until any outstanding callback on the old clp
|
* Must wait until any outstanding callback on the old clp
|
||||||
* completes.
|
* completes.
|
||||||
*/
|
*/
|
||||||
NFSLOCKSTATE();
|
if (!mlocked)
|
||||||
|
NFSLOCKSTATE();
|
||||||
while (clp->lc_cbref) {
|
while (clp->lc_cbref) {
|
||||||
clp->lc_flags |= LCL_WAKEUPWANTED;
|
clp->lc_flags |= LCL_WAKEUPWANTED;
|
||||||
(void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1,
|
(void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1,
|
||||||
"nfsdclp", 10 * hz);
|
"nfsdclp", 10 * hz);
|
||||||
}
|
}
|
||||||
NFSUNLOCKSTATE();
|
NFSUNLOCKSTATE();
|
||||||
|
if (old_xprt != NULL)
|
||||||
|
SVC_RELEASE(old_xprt);
|
||||||
nfsrv_zapclient(clp, p);
|
nfsrv_zapclient(clp, p);
|
||||||
*new_clpp = NULL;
|
*new_clpp = NULL;
|
||||||
|
} else {
|
||||||
|
if (mlocked)
|
||||||
|
NFSUNLOCKSTATE();
|
||||||
|
if (old_xprt != NULL)
|
||||||
|
SVC_RELEASE(old_xprt);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -605,11 +661,13 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||||
struct nfsstate *stp;
|
struct nfsstate *stp;
|
||||||
int i;
|
int i;
|
||||||
struct nfsclienthashhead *hp;
|
struct nfsclienthashhead *hp;
|
||||||
int error = 0, igotlock, doneok;
|
int error = 0, doneok, igotlock;
|
||||||
struct nfssessionhash *shp;
|
struct nfssessionhash *shp;
|
||||||
struct nfsdsession *sep;
|
struct nfsdsession *sep;
|
||||||
uint64_t sessid[2];
|
uint64_t sessid[2];
|
||||||
bool sess_replay;
|
CLIENT *client;
|
||||||
|
SVCXPRT *old_xprt;
|
||||||
|
bool mlocked, sess_replay;
|
||||||
static uint64_t next_sess = 0;
|
static uint64_t next_sess = 0;
|
||||||
|
|
||||||
if (clpp)
|
if (clpp)
|
||||||
|
@ -626,13 +684,27 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||||
* already held. Otherwise, we need to get either that or,
|
* already held. Otherwise, we need to get either that or,
|
||||||
* for the case of Confirm, lock out the nfsd threads.
|
* for the case of Confirm, lock out the nfsd threads.
|
||||||
*/
|
*/
|
||||||
|
client = NULL;
|
||||||
|
old_xprt = NULL;
|
||||||
|
mlocked = true;
|
||||||
|
if (nfsrv_dolocallocks != 0)
|
||||||
|
mlocked = false;
|
||||||
if (opflags & CLOPS_CONFIRM) {
|
if (opflags & CLOPS_CONFIRM) {
|
||||||
NFSLOCKV4ROOTMUTEX();
|
if (nsep != NULL &&
|
||||||
nfsv4_relref(&nfsv4rootfs_lock);
|
(nsep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0)
|
||||||
do {
|
client = (struct __rpc_client *)
|
||||||
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
|
clnt_bck_create(nd->nd_xprt->xp_socket,
|
||||||
NFSV4ROOTLOCKMUTEXPTR, NULL);
|
cbprogram, NFSV4_CBVERS);
|
||||||
} while (!igotlock);
|
if (mlocked) {
|
||||||
|
nfsrv_clientlock(mlocked);
|
||||||
|
} else {
|
||||||
|
NFSLOCKV4ROOTMUTEX();
|
||||||
|
nfsv4_relref(&nfsv4rootfs_lock);
|
||||||
|
do {
|
||||||
|
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1,
|
||||||
|
NULL, NFSV4ROOTLOCKMUTEXPTR, NULL);
|
||||||
|
} while (!igotlock);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Create a new sessionid here, since we need to do it where
|
* Create a new sessionid here, since we need to do it where
|
||||||
* there is a mutex held to serialize update of next_sess.
|
* there is a mutex held to serialize update of next_sess.
|
||||||
|
@ -641,7 +713,8 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||||
sessid[0] = ++next_sess;
|
sessid[0] = ++next_sess;
|
||||||
sessid[1] = clientid.qval;
|
sessid[1] = clientid.qval;
|
||||||
}
|
}
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
if (!mlocked)
|
||||||
|
NFSUNLOCKV4ROOTMUTEX();
|
||||||
} else if (opflags != CLOPS_RENEW) {
|
} else if (opflags != CLOPS_RENEW) {
|
||||||
NFSLOCKSTATE();
|
NFSLOCKSTATE();
|
||||||
}
|
}
|
||||||
|
@ -678,9 +751,9 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||||
}
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
if (opflags & CLOPS_CONFIRM) {
|
if (opflags & CLOPS_CONFIRM) {
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
if (client != NULL)
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
CLNT_RELEASE(client);
|
||||||
} else if (opflags != CLOPS_RENEW) {
|
} else if (opflags != CLOPS_RENEW) {
|
||||||
NFSUNLOCKSTATE();
|
NFSUNLOCKSTATE();
|
||||||
}
|
}
|
||||||
|
@ -725,7 +798,10 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||||
* for an Open with CLAIM_DELEGATE_PREV unless in
|
* for an Open with CLAIM_DELEGATE_PREV unless in
|
||||||
* grace, but get rid of the rest of the state.
|
* grace, but get rid of the rest of the state.
|
||||||
*/
|
*/
|
||||||
nfsrv_cleanclient(clp, p, false, NULL);
|
if (mlocked)
|
||||||
|
nfsrv_cleanclient(clp, p, true, &old_xprt);
|
||||||
|
else
|
||||||
|
nfsrv_cleanclient(clp, p, false, NULL);
|
||||||
nfsrv_freedeleglist(&clp->lc_olddeleg);
|
nfsrv_freedeleglist(&clp->lc_olddeleg);
|
||||||
if (nfsrv_checkgrace(nd, clp, 0)) {
|
if (nfsrv_checkgrace(nd, clp, 0)) {
|
||||||
/* In grace, so just delete delegations */
|
/* In grace, so just delete delegations */
|
||||||
|
@ -749,10 +825,10 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||||
/* Hold a reference on the xprt for a backchannel. */
|
/* Hold a reference on the xprt for a backchannel. */
|
||||||
if ((nsep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN)
|
if ((nsep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN)
|
||||||
!= 0 && !sess_replay) {
|
!= 0 && !sess_replay) {
|
||||||
if (clp->lc_req.nr_client == NULL)
|
if (clp->lc_req.nr_client == NULL) {
|
||||||
clp->lc_req.nr_client = (struct __rpc_client *)
|
clp->lc_req.nr_client = client;
|
||||||
clnt_bck_create(nd->nd_xprt->xp_socket,
|
client = NULL;
|
||||||
cbprogram, NFSV4_CBVERS);
|
}
|
||||||
if (clp->lc_req.nr_client != NULL) {
|
if (clp->lc_req.nr_client != NULL) {
|
||||||
SVC_ACQUIRE(nd->nd_xprt);
|
SVC_ACQUIRE(nd->nd_xprt);
|
||||||
CLNT_ACQUIRE(clp->lc_req.nr_client);
|
CLNT_ACQUIRE(clp->lc_req.nr_client);
|
||||||
|
@ -769,13 +845,15 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||||
NFSX_V4SESSIONID);
|
NFSX_V4SESSIONID);
|
||||||
if (!sess_replay) {
|
if (!sess_replay) {
|
||||||
shp = NFSSESSIONHASH(nsep->sess_sessionid);
|
shp = NFSSESSIONHASH(nsep->sess_sessionid);
|
||||||
NFSLOCKSTATE();
|
if (!mlocked)
|
||||||
|
NFSLOCKSTATE();
|
||||||
NFSLOCKSESSION(shp);
|
NFSLOCKSESSION(shp);
|
||||||
LIST_INSERT_HEAD(&shp->list, nsep, sess_hash);
|
LIST_INSERT_HEAD(&shp->list, nsep, sess_hash);
|
||||||
LIST_INSERT_HEAD(&clp->lc_session, nsep, sess_list);
|
LIST_INSERT_HEAD(&clp->lc_session, nsep, sess_list);
|
||||||
nsep->sess_clp = clp;
|
nsep->sess_clp = clp;
|
||||||
NFSUNLOCKSESSION(shp);
|
NFSUNLOCKSESSION(shp);
|
||||||
NFSUNLOCKSTATE();
|
if (!mlocked)
|
||||||
|
NFSUNLOCKSTATE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -809,9 +887,11 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
|
||||||
clp->lc_expiry = nfsrv_leaseexpiry();
|
clp->lc_expiry = nfsrv_leaseexpiry();
|
||||||
}
|
}
|
||||||
if (opflags & CLOPS_CONFIRM) {
|
if (opflags & CLOPS_CONFIRM) {
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
if (client != NULL)
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
CLNT_RELEASE(client);
|
||||||
|
if (old_xprt != NULL)
|
||||||
|
SVC_RELEASE(old_xprt);
|
||||||
} else if (opflags != CLOPS_RENEW) {
|
} else if (opflags != CLOPS_RENEW) {
|
||||||
NFSUNLOCKSTATE();
|
NFSUNLOCKSTATE();
|
||||||
}
|
}
|
||||||
|
@ -831,21 +911,20 @@ nfsrv_destroyclient(struct nfsrv_descript *nd, nfsquad_t clientid, NFSPROC_T *p)
|
||||||
{
|
{
|
||||||
struct nfsclient *clp;
|
struct nfsclient *clp;
|
||||||
struct nfsclienthashhead *hp;
|
struct nfsclienthashhead *hp;
|
||||||
int error = 0, i, igotlock;
|
SVCXPRT *old_xprt;
|
||||||
|
int error = 0, i;
|
||||||
|
bool mlocked;
|
||||||
|
|
||||||
if (NFSD_VNET(nfsrvboottime) != clientid.lval[0]) {
|
if (NFSD_VNET(nfsrvboottime) != clientid.lval[0]) {
|
||||||
error = NFSERR_STALECLIENTID;
|
error = NFSERR_STALECLIENTID;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mlocked = true;
|
||||||
|
if (nfsrv_dolocallocks != 0)
|
||||||
|
mlocked = false;
|
||||||
/* Lock out other nfsd threads */
|
/* Lock out other nfsd threads */
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientlock(mlocked);
|
||||||
nfsv4_relref(&nfsv4rootfs_lock);
|
|
||||||
do {
|
|
||||||
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
|
|
||||||
NFSV4ROOTLOCKMUTEXPTR, NULL);
|
|
||||||
} while (igotlock == 0);
|
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
|
||||||
|
|
||||||
hp = NFSCLIENTHASH(clientid);
|
hp = NFSCLIENTHASH(clientid);
|
||||||
LIST_FOREACH(clp, hp, lc_hash) {
|
LIST_FOREACH(clp, hp, lc_hash) {
|
||||||
|
@ -853,9 +932,7 @@ nfsrv_destroyclient(struct nfsrv_descript *nd, nfsquad_t clientid, NFSPROC_T *p)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (clp == NULL) {
|
if (clp == NULL) {
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
|
||||||
/* Just return ok, since it is gone. */
|
/* Just return ok, since it is gone. */
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -863,9 +940,7 @@ nfsrv_destroyclient(struct nfsrv_descript *nd, nfsquad_t clientid, NFSPROC_T *p)
|
||||||
/* Check for the SP4_MACH_CRED case. */
|
/* Check for the SP4_MACH_CRED case. */
|
||||||
error = nfsrv_checkmachcred(NFSV4OP_DESTROYCLIENTID, nd, clp);
|
error = nfsrv_checkmachcred(NFSV4OP_DESTROYCLIENTID, nd, clp);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,28 +953,28 @@ nfsrv_destroyclient(struct nfsrv_descript *nd, nfsquad_t clientid, NFSPROC_T *p)
|
||||||
/* Scan for state on the clientid. */
|
/* Scan for state on the clientid. */
|
||||||
for (i = 0; i < nfsrv_statehashsize; i++)
|
for (i = 0; i < nfsrv_statehashsize; i++)
|
||||||
if (!LIST_EMPTY(&clp->lc_stateid[i])) {
|
if (!LIST_EMPTY(&clp->lc_stateid[i])) {
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
|
||||||
error = NFSERR_CLIENTIDBUSY;
|
error = NFSERR_CLIENTIDBUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!LIST_EMPTY(&clp->lc_session) || !LIST_EMPTY(&clp->lc_deleg)) {
|
if (!LIST_EMPTY(&clp->lc_session) || !LIST_EMPTY(&clp->lc_deleg)) {
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
|
||||||
error = NFSERR_CLIENTIDBUSY;
|
error = NFSERR_CLIENTIDBUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy the clientid and return ok. */
|
/* Destroy the clientid and return ok. */
|
||||||
nfsrv_cleanclient(clp, p, false, NULL);
|
old_xprt = NULL;
|
||||||
|
if (mlocked)
|
||||||
|
nfsrv_cleanclient(clp, p, true, &old_xprt);
|
||||||
|
else
|
||||||
|
nfsrv_cleanclient(clp, p, false, NULL);
|
||||||
nfsrv_freedeleglist(&clp->lc_deleg);
|
nfsrv_freedeleglist(&clp->lc_deleg);
|
||||||
nfsrv_freedeleglist(&clp->lc_olddeleg);
|
nfsrv_freedeleglist(&clp->lc_olddeleg);
|
||||||
LIST_REMOVE(clp, lc_hash);
|
LIST_REMOVE(clp, lc_hash);
|
||||||
NFSLOCKV4ROOTMUTEX();
|
nfsrv_clientunlock(mlocked);
|
||||||
nfsv4_unlock(&nfsv4rootfs_lock, 1);
|
if (old_xprt != NULL)
|
||||||
NFSUNLOCKV4ROOTMUTEX();
|
SVC_RELEASE(old_xprt);
|
||||||
nfsrv_zapclient(clp, p);
|
nfsrv_zapclient(clp, p);
|
||||||
out:
|
out:
|
||||||
NFSEXITCODE2(error, nd);
|
NFSEXITCODE2(error, nd);
|
||||||
|
@ -1388,8 +1463,12 @@ nfsrv_cleanclient(struct nfsclient *clp, NFSPROC_T *p, bool locked,
|
||||||
struct nfsstate *stp, *nstp;
|
struct nfsstate *stp, *nstp;
|
||||||
struct nfsdsession *sep, *nsep;
|
struct nfsdsession *sep, *nsep;
|
||||||
|
|
||||||
LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp)
|
LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) {
|
||||||
nfsrv_freeopenowner(stp, 1, p);
|
if (locked)
|
||||||
|
nfsrv_freeopenowner(stp, 0, p);
|
||||||
|
else
|
||||||
|
nfsrv_freeopenowner(stp, 1, p);
|
||||||
|
}
|
||||||
if ((clp->lc_flags & LCL_ADMINREVOKED) == 0)
|
if ((clp->lc_flags & LCL_ADMINREVOKED) == 0)
|
||||||
LIST_FOREACH_SAFE(sep, &clp->lc_session, sess_list, nsep)
|
LIST_FOREACH_SAFE(sep, &clp->lc_session, sess_list, nsep)
|
||||||
(void)nfsrv_freesession(NULL, sep, NULL, locked,
|
(void)nfsrv_freesession(NULL, sep, NULL, locked,
|
||||||
|
|
Loading…
Reference in a new issue