svn commit: r291869 - in stable/10/sys/fs: nfs nfsserver
Rick Macklem
rmacklem at FreeBSD.org
Sat Dec 5 21:38:55 UTC 2015
Author: rmacklem
Date: Sat Dec 5 21:38:53 2015
New Revision: 291869
URL: https://svnweb.freebsd.org/changeset/base/291869
Log:
MFC: r291150
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.
Modified:
stable/10/sys/fs/nfs/nfs_var.h
stable/10/sys/fs/nfsserver/nfs_nfsdkrpc.c
stable/10/sys/fs/nfsserver/nfs_nfsdstate.c
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/fs/nfs/nfs_var.h
==============================================================================
--- stable/10/sys/fs/nfs/nfs_var.h Sat Dec 5 21:38:04 2015 (r291868)
+++ stable/10/sys/fs/nfs/nfs_var.h Sat Dec 5 21:38:53 2015 (r291869)
@@ -135,6 +135,7 @@ int nfsrv_checksequence(struct nfsrv_des
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,
Modified: stable/10/sys/fs/nfsserver/nfs_nfsdkrpc.c
==============================================================================
--- stable/10/sys/fs/nfsserver/nfs_nfsdkrpc.c Sat Dec 5 21:38:04 2015 (r291868)
+++ stable/10/sys/fs/nfsserver/nfs_nfsdkrpc.c Sat Dec 5 21:38:53 2015 (r291869)
@@ -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();
Modified: stable/10/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- stable/10/sys/fs/nfsserver/nfs_nfsdstate.c Sat Dec 5 21:38:04 2015 (r291868)
+++ stable/10/sys/fs/nfsserver/nfs_nfsdstate.c Sat Dec 5 21:38:53 2015 (r291869)
@@ -4188,10 +4188,23 @@ nfsrv_docallback(struct nfsclient *clp,
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_descrip
* 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
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);
+ }
+ }
+ }
+}
+
More information about the svn-src-stable-10
mailing list