diff options
-rw-r--r-- | sys/fs/nfs/nfs_var.h | 1 | ||||
-rw-r--r-- | sys/fs/nfsserver/nfs_nfsdkrpc.c | 1 | ||||
-rw-r--r-- | sys/fs/nfsserver/nfs_nfsdstate.c | 55 |
3 files changed, 50 insertions, 7 deletions
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 2abd7e4..d540dc9 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -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, diff --git a/sys/fs/nfsserver/nfs_nfsdkrpc.c b/sys/fs/nfsserver/nfs_nfsdkrpc.c index e68a18b..7326038 100644 --- a/sys/fs/nfsserver/nfs_nfsdkrpc.c +++ b/sys/fs/nfsserver/nfs_nfsdkrpc.c @@ -547,6 +547,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(); diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index c6d9448..37fb3b6 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -4188,10 +4188,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, @@ -5776,14 +5789,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; @@ -6042,3 +6057,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); + } + } + } +} + |