When the nfsd threads are terminated, the NFSv4 server state
(opens, locks, etc) is retained, which I believe is correct behaviour. However, for NFSv4.1, the server also retained a reference to the xprt (RPC transport socket structure) for the backchannel. This caused svcpool_destroy() to not call SVC_DESTROY() for the xprt and allowed a socket upcall to occur after the mutexes in the svcpool were destroyed, causing a crash. This patch fixes the code so that the backchannel xprt structure is dereferenced just before svcpool_destroy() is called, so the code does do an SVC_DESTROY() on the xprt, which shuts down the socket upcall. Tested by: g_amanakis@yahoo.com PR: 204340 MFC after: 2 weeks
This commit is contained in:
parent
e0848bbb0c
commit
a0962bf8bc
@ -135,6 +135,7 @@ int nfsrv_checksequence(struct nfsrv_descript *, uint32_t, uint32_t *,
|
||||
uint32_t *, int, uint32_t *, NFSPROC_T *);
|
||||
int nfsrv_checkreclaimcomplete(struct nfsrv_descript *);
|
||||
void nfsrv_cache_session(uint8_t *, uint32_t, int, struct mbuf **);
|
||||
void nfsrv_freeallbackchannel_xprts(void);
|
||||
|
||||
/* nfs_nfsdserv.c */
|
||||
int nfsrvd_access(struct nfsrv_descript *, int,
|
||||
|
@ -544,6 +544,7 @@ nfsrvd_init(int terminating)
|
||||
if (terminating) {
|
||||
nfsd_master_proc = NULL;
|
||||
NFSD_UNLOCK();
|
||||
nfsrv_freeallbackchannel_xprts();
|
||||
svcpool_destroy(nfsrvd_pool);
|
||||
nfsrvd_pool = NULL;
|
||||
NFSD_LOCK();
|
||||
|
@ -4191,10 +4191,23 @@ nfsrv_docallback(struct nfsclient *clp, int procnum,
|
||||
if (!error) {
|
||||
if ((nd->nd_flag & ND_NFSV41) != 0) {
|
||||
KASSERT(sep != NULL, ("sep NULL"));
|
||||
error = newnfs_request(nd, NULL, clp, &clp->lc_req,
|
||||
NULL, NULL, cred, clp->lc_program,
|
||||
clp->lc_req.nr_vers, NULL, 1, NULL,
|
||||
&sep->sess_cbsess);
|
||||
if (sep->sess_cbsess.nfsess_xprt != NULL)
|
||||
error = newnfs_request(nd, NULL, clp,
|
||||
&clp->lc_req, NULL, NULL, cred,
|
||||
clp->lc_program, clp->lc_req.nr_vers, NULL,
|
||||
1, NULL, &sep->sess_cbsess);
|
||||
else {
|
||||
/*
|
||||
* This should probably never occur, but if a
|
||||
* client somehow does an RPC without a
|
||||
* SequenceID Op that causes a callback just
|
||||
* after the nfsd threads have been terminated
|
||||
* and restared we could conceivably get here
|
||||
* without a backchannel xprt.
|
||||
*/
|
||||
printf("nfsrv_docallback: no xprt\n");
|
||||
error = ECONNREFUSED;
|
||||
}
|
||||
nfsrv_freesession(sep, NULL);
|
||||
} else
|
||||
error = newnfs_request(nd, NULL, clp, &clp->lc_req,
|
||||
@ -5784,14 +5797,16 @@ nfsrv_checksequence(struct nfsrv_descript *nd, uint32_t sequenceid,
|
||||
* If this session handles the backchannel, save the nd_xprt for this
|
||||
* RPC, since this is the one being used.
|
||||
*/
|
||||
if (sep->sess_cbsess.nfsess_xprt != NULL &&
|
||||
if (sep->sess_clp->lc_req.nr_client != NULL &&
|
||||
(sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0) {
|
||||
savxprt = sep->sess_cbsess.nfsess_xprt;
|
||||
SVC_ACQUIRE(nd->nd_xprt);
|
||||
nd->nd_xprt->xp_p2 = savxprt->xp_p2;
|
||||
nd->nd_xprt->xp_p2 =
|
||||
sep->sess_clp->lc_req.nr_client->cl_private;
|
||||
nd->nd_xprt->xp_idletimeout = 0; /* Disable timeout. */
|
||||
sep->sess_cbsess.nfsess_xprt = nd->nd_xprt;
|
||||
SVC_RELEASE(savxprt);
|
||||
if (savxprt != NULL)
|
||||
SVC_RELEASE(savxprt);
|
||||
}
|
||||
|
||||
*sflagsp = 0;
|
||||
@ -6050,3 +6065,29 @@ nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up all backchannel xprts. This needs to be done when the nfsd threads
|
||||
* exit, since those transports will all be going away.
|
||||
* This is only called after all the nfsd threads are done performing RPCs,
|
||||
* so locking shouldn't be an issue.
|
||||
*/
|
||||
APPLESTATIC void
|
||||
nfsrv_freeallbackchannel_xprts(void)
|
||||
{
|
||||
struct nfsdsession *sep;
|
||||
struct nfsclient *clp;
|
||||
SVCXPRT *xprt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nfsrv_clienthashsize; i++) {
|
||||
LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) {
|
||||
LIST_FOREACH(sep, &clp->lc_session, sess_list) {
|
||||
xprt = sep->sess_cbsess.nfsess_xprt;
|
||||
sep->sess_cbsess.nfsess_xprt = NULL;
|
||||
if (xprt != NULL)
|
||||
SVC_RELEASE(xprt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user