From owner-svn-src-head@freebsd.org Sat Nov 21 23:55:48 2015 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 04843A3446F; Sat, 21 Nov 2015 23:55:48 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id B9AAF1F40; Sat, 21 Nov 2015 23:55:47 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tALNtkCw025183; Sat, 21 Nov 2015 23:55:46 GMT (envelope-from rmacklem@FreeBSD.org) Received: (from rmacklem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tALNtkOY025180; Sat, 21 Nov 2015 23:55:46 GMT (envelope-from rmacklem@FreeBSD.org) Message-Id: <201511212355.tALNtkOY025180@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rmacklem set sender to rmacklem@FreeBSD.org using -f From: Rick Macklem Date: Sat, 21 Nov 2015 23:55:46 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r291150 - in head/sys/fs: nfs nfsserver X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 21 Nov 2015 23:55:48 -0000 Author: rmacklem Date: Sat Nov 21 23:55:46 2015 New Revision: 291150 URL: https://svnweb.freebsd.org/changeset/base/291150 Log: 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 Modified: head/sys/fs/nfs/nfs_var.h head/sys/fs/nfsserver/nfs_nfsdkrpc.c head/sys/fs/nfsserver/nfs_nfsdstate.c Modified: head/sys/fs/nfs/nfs_var.h ============================================================================== --- head/sys/fs/nfs/nfs_var.h Sat Nov 21 23:30:47 2015 (r291149) +++ head/sys/fs/nfs/nfs_var.h Sat Nov 21 23:55:46 2015 (r291150) @@ -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: head/sys/fs/nfsserver/nfs_nfsdkrpc.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdkrpc.c Sat Nov 21 23:30:47 2015 (r291149) +++ head/sys/fs/nfsserver/nfs_nfsdkrpc.c Sat Nov 21 23:55:46 2015 (r291150) @@ -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(); Modified: head/sys/fs/nfsserver/nfs_nfsdstate.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdstate.c Sat Nov 21 23:30:47 2015 (r291149) +++ head/sys/fs/nfsserver/nfs_nfsdstate.c Sat Nov 21 23:55:46 2015 (r291150) @@ -4191,10 +4191,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, @@ -5784,14 +5797,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; @@ -6050,3 +6065,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); + } + } + } +} +