From owner-svn-src-stable@freebsd.org Mon Apr 24 23:47:15 2017 Return-Path: Delivered-To: svn-src-stable@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 16F8CD4E8B1; Mon, 24 Apr 2017 23:47:15 +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 D4405319; Mon, 24 Apr 2017 23:47:14 +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 v3ONlDs1040581; Mon, 24 Apr 2017 23:47:13 GMT (envelope-from rmacklem@FreeBSD.org) Received: (from rmacklem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v3ONlD5h040571; Mon, 24 Apr 2017 23:47:13 GMT (envelope-from rmacklem@FreeBSD.org) Message-Id: <201704242347.v3ONlD5h040571@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rmacklem set sender to rmacklem@FreeBSD.org using -f From: Rick Macklem Date: Mon, 24 Apr 2017 23:47:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r317393 - in stable/11/sys/fs: nfs nfsclient X-SVN-Group: stable-11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 24 Apr 2017 23:47:15 -0000 Author: rmacklem Date: Mon Apr 24 23:47:12 2017 New Revision: 317393 URL: https://svnweb.freebsd.org/changeset/base/317393 Log: MFC: r310491 Fix NFSv4.1 client recovery from NFS4ERR_BAD_SESSION errors. For most NFSv4.1 servers, a NFS4ERR_BAD_SESSION error is a rare failure that indicates that the server has lost session/open/lock state. However, recent testing by cperciva@ against the AmazonEFS server found several problems with client recovery from this due to it generating this failure frequently. Briefly, the problems fixed are: - If all session slots were in use at the time of the failure, some processes would continue to loop waiting for a slot on the old session forever. - If an RPC that doesn't use open/lock state failed with NFS4ERR_BAD_SESSION, it would fail the RPC/syscall instead of initiating recovery and then looping to retry the RPC. - If a successful reply to an RPC for an old session wasn't processed until after a new session was created for a NFS4ERR_BAD_SESSION error, it would erroneously update the new session and corrupt it. - The use of the first element of the session list in the nfs mount structure (which is always the current metadata session) was slightly racey. With changes for the above problems it became more racey, so all uses of this head pointer was wrapped with a NFSLOCKMNT()/NFSUNLOCKMNT(). - Although the kernel malloc() usually allocates more bytes than requested and, as such, this wouldn't have caused problems, the allocation of a session structure was 1 byte smaller than it should have been. (Null termination byte for the string not included in byte count.) There are probably still problems with a pNFS data server that fails with NFS4ERR_BAD_SESSION, but I have no server that does this to test against (the AmazonEFS server doesn't do pNFS), so I can't fix these yet. Although this patch is fairly large, it should only affect the handling of NFS4ERR_BAD_SESSION error replies from an NFSv4.1 server. Thanks go to cperciva@ for the extension testing he did to help isolate/fix these problems. Modified: stable/11/sys/fs/nfs/nfs.h stable/11/sys/fs/nfs/nfs_commonkrpc.c stable/11/sys/fs/nfs/nfs_commonport.c stable/11/sys/fs/nfs/nfs_commonsubs.c stable/11/sys/fs/nfs/nfsclstate.h stable/11/sys/fs/nfsclient/nfs_clcomsubs.c stable/11/sys/fs/nfsclient/nfs_clport.c stable/11/sys/fs/nfsclient/nfs_clrpcops.c stable/11/sys/fs/nfsclient/nfs_clstate.c stable/11/sys/fs/nfsclient/nfs_clvfsops.c stable/11/sys/fs/nfsclient/nfsmount.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/fs/nfs/nfs.h ============================================================================== --- stable/11/sys/fs/nfs/nfs.h Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfs/nfs.h Mon Apr 24 23:47:12 2017 (r317393) @@ -601,6 +601,7 @@ struct nfsrv_descript { uint8_t nd_sessionid[NFSX_V4SESSIONID]; /* Session id */ uint32_t nd_slotid; /* Slotid for this RPC */ SVCXPRT *nd_xprt; /* Server RPC handle */ + uint32_t *nd_sequence; /* Sequence Op. ptr */ }; #define nd_princlen nd_gssnamelen @@ -636,6 +637,7 @@ struct nfsrv_descript { #define ND_HASSEQUENCE 0x04000000 #define ND_CACHETHIS 0x08000000 #define ND_LASTOP 0x10000000 +#define ND_LOOPBADSESS 0x20000000 /* * ND_GSS should be the "or" of all GSS type authentications. @@ -649,6 +651,7 @@ struct nfsv4_opflag { int modifyfs; int lktype; int needsseq; + int loopbadsess; }; /* Modified: stable/11/sys/fs/nfs/nfs_commonkrpc.c ============================================================================== --- stable/11/sys/fs/nfs/nfs_commonkrpc.c Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfs/nfs_commonkrpc.c Mon Apr 24 23:47:12 2017 (r317393) @@ -89,6 +89,7 @@ uint32_t nfscl_nfs4_done_probes[NFSV41_N NFSSTATESPINLOCK; NFSREQSPINLOCK; NFSDLOCKMUTEX; +NFSCLSTATEMUTEX; extern struct nfsstatsv1 nfsstatsv1; extern struct nfsreqhead nfsd_reqq; extern int nfscl_ticks; @@ -473,13 +474,13 @@ int newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, struct nfsclient *clp, struct nfssockreq *nrp, vnode_t vp, struct thread *td, struct ucred *cred, u_int32_t prog, u_int32_t vers, - u_char *retsum, int toplevel, u_int64_t *xidp, struct nfsclsession *sep) + u_char *retsum, int toplevel, u_int64_t *xidp, struct nfsclsession *dssep) { - u_int32_t retseq, retval, *tl; + uint32_t retseq, retval, slotseq, *tl; time_t waituntil; int i = 0, j = 0, opcnt, set_sigset = 0, slot; int trycnt, error = 0, usegssname = 0, secflavour = AUTH_SYS; - int freeslot, timeo; + int freeslot, maxslot, reterr, slotpos, timeo; u_int16_t procnum; u_int trylater_delay = 1; struct nfs_feedback_arg nf; @@ -491,7 +492,10 @@ newnfs_request(struct nfsrv_descript *nd char *srv_principal = NULL, *clnt_principal = NULL; sigset_t oldset; struct ucred *authcred; + struct nfsclsession *sep; + uint8_t sessionid[NFSX_V4SESSIONID]; + sep = dssep; if (xidp != NULL) *xidp = 0; /* Reject requests while attempting a forced unmount. */ @@ -803,7 +807,7 @@ tryagain: nd->nd_procnum != NFSV4PROC_CBNULL) { /* If sep == NULL, set it to the default in nmp. */ if (sep == NULL && nmp != NULL) - sep = NFSMNT_MDSSESSION(nmp); + sep = nfsmnt_mdssession(nmp); /* * and now the actual NFS xdr. */ @@ -847,18 +851,25 @@ tryagain: NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); mtx_lock(&sep->nfsess_mtx); - tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; - retseq = fxdr_unsigned(uint32_t, *tl++); - slot = fxdr_unsigned(int, *tl++); - freeslot = slot; - if (retseq != sep->nfsess_slotseq[slot]) - printf("retseq diff 0x%x\n", retseq); - retval = fxdr_unsigned(uint32_t, *++tl); - if ((retval + 1) < sep->nfsess_foreslots) - sep->nfsess_foreslots = (retval + 1); - else if ((retval + 1) > sep->nfsess_foreslots) - sep->nfsess_foreslots = (retval < 64) ? - (retval + 1) : 64; + if (bcmp(tl, sep->nfsess_sessionid, + NFSX_V4SESSIONID) == 0) { + tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; + retseq = fxdr_unsigned(uint32_t, *tl++); + slot = fxdr_unsigned(int, *tl++); + freeslot = slot; + if (retseq != sep->nfsess_slotseq[slot]) + printf("retseq diff 0x%x\n", + retseq); + retval = fxdr_unsigned(uint32_t, *++tl); + if ((retval + 1) < sep->nfsess_foreslots + ) + sep->nfsess_foreslots = (retval + + 1); + else if ((retval + 1) > + sep->nfsess_foreslots) + sep->nfsess_foreslots = (retval + < 64) ? (retval + 1) : 64; + } mtx_unlock(&sep->nfsess_mtx); /* Grab the op and status for the next one. */ @@ -871,6 +882,76 @@ tryagain: } } if (nd->nd_repstat != 0) { + if (nd->nd_repstat == NFSERR_BADSESSION && + nmp != NULL && dssep == NULL) { + /* + * If this is a client side MDS RPC, mark + * the MDS session defunct and initiate + * recovery, as required. + * The nfsess_defunct field is protected by + * the NFSLOCKMNT()/nm_mtx lock and not the + * nfsess_mtx lock to simplify its handling, + * for the MDS session. This lock is also + * sufficient for nfsess_sessionid, since it + * never changes in the structure. + */ + NFSCL_DEBUG(1, "Got badsession\n"); + NFSLOCKCLSTATE(); + NFSLOCKMNT(nmp); + sep = NFSMNT_MDSSESSION(nmp); + if (bcmp(sep->nfsess_sessionid, nd->nd_sequence, + NFSX_V4SESSIONID) == 0) { + /* Initiate recovery. */ + sep->nfsess_defunct = 1; + NFSCL_DEBUG(1, "Marked defunct\n"); + if (nmp->nm_clp != NULL) { + nmp->nm_clp->nfsc_flags |= + NFSCLFLAGS_RECOVER; + wakeup(nmp->nm_clp); + } + } + NFSUNLOCKCLSTATE(); + /* + * Sleep for up to 1sec waiting for a new + * session. + */ + mtx_sleep(&nmp->nm_sess, &nmp->nm_mtx, PZERO, + "nfsbadsess", hz); + /* + * Get the session again, in case a new one + * has been created during the sleep. + */ + sep = NFSMNT_MDSSESSION(nmp); + NFSUNLOCKMNT(nmp); + if ((nd->nd_flag & ND_LOOPBADSESS) != 0) { + reterr = nfsv4_sequencelookup(nmp, sep, + &slotpos, &maxslot, &slotseq, + sessionid); + if (reterr == 0) { + /* Fill in new session info. */ + NFSCL_DEBUG(1, + "Filling in new sequence\n"); + tl = nd->nd_sequence; + bcopy(sessionid, tl, + NFSX_V4SESSIONID); + tl += NFSX_V4SESSIONID / + NFSX_UNSIGNED; + *tl++ = txdr_unsigned(slotseq); + *tl++ = txdr_unsigned(slotpos); + *tl = txdr_unsigned(maxslot); + } + if (reterr == NFSERR_BADSESSION || + reterr == 0) { + NFSCL_DEBUG(1, + "Badsession looping\n"); + m_freem(nd->nd_mrep); + nd->nd_mrep = NULL; + goto tryagain; + } + nd->nd_repstat = reterr; + NFSCL_DEBUG(1, "Got err=%d\n", reterr); + } + } if (((nd->nd_repstat == NFSERR_DELAY || nd->nd_repstat == NFSERR_GRACE) && (nd->nd_flag & ND_NFSV4) && Modified: stable/11/sys/fs/nfs/nfs_commonport.c ============================================================================== --- stable/11/sys/fs/nfs/nfs_commonport.c Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfs/nfs_commonport.c Mon Apr 24 23:47:12 2017 (r317393) @@ -129,6 +129,7 @@ struct mtx nfs_state_mutex; struct mtx nfs_nameid_mutex; struct mtx nfs_req_mutex; struct mtx nfs_slock_mutex; +struct mtx nfs_clstate_mutex; /* local functions */ static int nfssvc_call(struct thread *, struct nfssvc_args *, struct ucred *); @@ -647,6 +648,7 @@ newnfs_portinit(void) /* Initialize SMP locks used by both client and server. */ mtx_init(&newnfsd_mtx, "newnfsd_mtx", NULL, MTX_DEF); mtx_init(&nfs_state_mutex, "nfs_state_mutex", NULL, MTX_DEF); + mtx_init(&nfs_clstate_mutex, "nfs_clstate_mutex", NULL, MTX_DEF); } /* @@ -712,6 +714,7 @@ nfscommon_modevent(module_t mod, int typ mtx_destroy(&nfs_nameid_mutex); mtx_destroy(&newnfsd_mtx); mtx_destroy(&nfs_state_mutex); + mtx_destroy(&nfs_clstate_mutex); mtx_destroy(&nfs_sockl_mutex); mtx_destroy(&nfs_slock_mutex); mtx_destroy(&nfs_req_mutex); Modified: stable/11/sys/fs/nfs/nfs_commonsubs.c ============================================================================== --- stable/11/sys/fs/nfs/nfs_commonsubs.c Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfs/nfs_commonsubs.c Mon Apr 24 23:47:12 2017 (r317393) @@ -90,65 +90,65 @@ extern int nfsrv_lughashsize; * Define it here, since it is used by both the client and server. */ struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = { - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ - { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */ - { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */ - { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */ - { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */ - { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */ - { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */ - { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */ - { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */ - { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */ - { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */ - { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */ - { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */ - { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */ - { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */ - { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */ - { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */ - { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */ - { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */ - { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */ - { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ + { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */ + { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */ + { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */ + { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */ + { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */ + { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */ + { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */ + { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */ + { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */ + { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */ + { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */ + { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */ + { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */ + { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */ + { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */ + { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */ + { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */ + { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */ + { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Bind Conn to Sess */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */ + { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */ + { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Reclaim Complete */ }; #endif /* !APPLEKEXT */ @@ -4134,22 +4134,35 @@ nfsv4_setsequence(struct nfsmount *nmp, error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, sessionid); - if (error != 0) - return; - KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); /* Build the Sequence arguments. */ NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); + nd->nd_sequence = tl; bcopy(sessionid, tl, NFSX_V4SESSIONID); tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; nd->nd_slotseq = tl; - *tl++ = txdr_unsigned(slotseq); - *tl++ = txdr_unsigned(slotpos); - *tl++ = txdr_unsigned(maxslot); - if (dont_replycache == 0) - *tl = newnfs_true; - else - *tl = newnfs_false; + if (error == 0) { + *tl++ = txdr_unsigned(slotseq); + *tl++ = txdr_unsigned(slotpos); + *tl++ = txdr_unsigned(maxslot); + if (dont_replycache == 0) + *tl = newnfs_true; + else + *tl = newnfs_false; + } else { + /* + * There are two errors and the rest of the session can + * just be zeros. + * NFSERR_BADSESSION: This bad session should just generate + * the same error again when the RPC is retried. + * ESTALE: A forced dismount is in progress and will cause the + * RPC to fail later. + */ + *tl++ = 0; + *tl++ = 0; + *tl++ = 0; + *tl = 0; + } nd->nd_flag |= ND_HASSEQUENCE; } @@ -4165,6 +4178,13 @@ nfsv4_sequencelookup(struct nfsmount *nm maxslot = -1; mtx_lock(&sep->nfsess_mtx); do { + if (nmp != NULL && sep->nfsess_defunct != 0) { + /* Just return the bad session. */ + bcopy(sep->nfsess_sessionid, sessionid, + NFSX_V4SESSIONID); + mtx_unlock(&sep->nfsess_mtx); + return (NFSERR_BADSESSION); + } bitval = 1; for (i = 0; i < sep->nfsess_foreslots; i++) { if ((bitval & sep->nfsess_slots) == 0) { Modified: stable/11/sys/fs/nfs/nfsclstate.h ============================================================================== --- stable/11/sys/fs/nfs/nfsclstate.h Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfs/nfsclstate.h Mon Apr 24 23:47:12 2017 (r317393) @@ -65,6 +65,7 @@ struct nfsclsession { uint16_t nfsess_foreslots; uint16_t nfsess_backslots; uint8_t nfsess_sessionid[NFSX_V4SESSIONID]; + uint8_t nfsess_defunct; /* Non-zero for old sessions */ }; /* Modified: stable/11/sys/fs/nfsclient/nfs_clcomsubs.c ============================================================================== --- stable/11/sys/fs/nfsclient/nfs_clcomsubs.c Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfsclient/nfs_clcomsubs.c Mon Apr 24 23:47:12 2017 (r317393) @@ -200,13 +200,16 @@ nfscl_reqstart(struct nfsrv_descript *nd *tl = txdr_unsigned(opcnt); if ((nd->nd_flag & ND_NFSV41) != 0 && nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) { + if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess > + 0) + nd->nd_flag |= ND_LOOPBADSESS; NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_SEQUENCE); - if (sep == NULL) - nfsv4_setsequence(nmp, nd, - NFSMNT_MDSSESSION(nmp), + if (sep == NULL) { + sep = nfsmnt_mdssession(nmp); + nfsv4_setsequence(nmp, nd, sep, nfs_bigreply[procnum]); - else + } else nfsv4_setsequence(nmp, nd, sep, nfs_bigreply[procnum]); } Modified: stable/11/sys/fs/nfsclient/nfs_clport.c ============================================================================== --- stable/11/sys/fs/nfsclient/nfs_clport.c Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfsclient/nfs_clport.c Mon Apr 24 23:47:12 2017 (r317393) @@ -82,7 +82,6 @@ extern short nfsv4_cbport; extern int nfscl_enablecallb; extern int nfs_numnfscbd; extern int nfscl_inited; -struct mtx nfs_clstate_mutex; struct mtx ncl_iod_mutex; NFSDLOCKMUTEX; @@ -1381,8 +1380,6 @@ nfscl_modevent(module_t mod, int type, v if (loaded) return (0); newnfs_portinit(); - mtx_init(&nfs_clstate_mutex, "nfs_clstate_mutex", NULL, - MTX_DEF); mtx_init(&ncl_iod_mutex, "ncl_iod_mutex", NULL, MTX_DEF); nfscl_init(); NFSD_LOCK(); @@ -1406,7 +1403,6 @@ nfscl_modevent(module_t mod, int type, v ncl_call_invalcaches = NULL; nfsd_call_nfscl = NULL; /* and get rid of the mutexes */ - mtx_destroy(&nfs_clstate_mutex); mtx_destroy(&ncl_iod_mutex); loaded = 0; break; Modified: stable/11/sys/fs/nfsclient/nfs_clrpcops.c ============================================================================== --- stable/11/sys/fs/nfsclient/nfs_clrpcops.c Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfsclient/nfs_clrpcops.c Mon Apr 24 23:47:12 2017 (r317393) @@ -384,6 +384,7 @@ nfsrpc_openrpc(struct nfsmount *nmp, vno u_int32_t rflags, deleg; nfsattrbit_t attrbits; int error, ret, acesize, limitby; + struct nfsclsession *tsep; dp = *dpp; *dpp = NULL; @@ -392,8 +393,9 @@ nfsrpc_openrpc(struct nfsmount *nmp, vno *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; - *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); @@ -557,7 +559,7 @@ nfsrpc_openrpc(struct nfsmount *nmp, vno } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; - if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) + if (error == NFSERR_STALECLIENTID) nfscl_initiate_recovery(op->nfso_own->nfsow_clp); nfsmout: if (!error) @@ -604,7 +606,7 @@ nfsrpc_opendowngrade(vnode_t vp, u_int32 } if (nd->nd_repstat && error == 0) error = nd->nd_repstat; - if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) + if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(op->nfso_own->nfsow_clp); nfsmout: mbuf_freem(nd->nd_mrep); @@ -762,7 +764,7 @@ nfsrpc_closerpc(struct nfsrv_descript *n if (nd->nd_repstat == 0) NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); error = nd->nd_repstat; - if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) + if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(op->nfso_own->nfsow_clp); nfsmout: mbuf_freem(nd->nd_mrep); @@ -803,7 +805,7 @@ nfsrpc_openconfirm(vnode_t vp, u_int8_t op->nfso_stateid.other[2] = *tl; } error = nd->nd_repstat; - if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) + if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(op->nfso_own->nfsow_clp); nfsmout: mbuf_freem(nd->nd_mrep); @@ -828,33 +830,53 @@ nfsrpc_setclient(struct nfsmount *nmp, s nfsquad_t confirm; u_int32_t lease; static u_int32_t rev = 0; - struct nfsclds *dsp, *ndsp, *tdsp; + struct nfsclds *dsp; struct in6_addr a6; + struct nfsclsession *tsep; if (nfsboottime.tv_sec == 0) NFSSETBOOTTIME(nfsboottime); clp->nfsc_rev = rev++; if (NFSHASNFSV4N(nmp)) { + /* + * Either there was no previous session or the + * previous session has failed, so... + * do an ExchangeID followed by the CreateSession. + */ error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p); NFSCL_DEBUG(1, "aft exch=%d\n", error); - if (error == 0) { + if (error == 0) error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, &nmp->nm_sockreq, dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p); - if (error == 0) { - NFSLOCKMNT(nmp); - TAILQ_FOREACH_SAFE(tdsp, &nmp->nm_sess, - nfsclds_list, ndsp) - nfscl_freenfsclds(tdsp); - TAILQ_INIT(&nmp->nm_sess); - TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, - nfsclds_list); - NFSUNLOCKMNT(nmp); - } else - nfscl_freenfsclds(dsp); - NFSCL_DEBUG(1, "aft createsess=%d\n", error); - } + if (error == 0) { + NFSLOCKMNT(nmp); + /* + * The old sessions cannot be safely free'd + * here, since they may still be used by + * in-progress RPCs. + */ + tsep = NULL; + if (TAILQ_FIRST(&nmp->nm_sess) != NULL) + tsep = NFSMNT_MDSSESSION(nmp); + TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, + nfsclds_list); + /* + * Wake up RPCs waiting for a slot on the + * old session. These will then fail with + * NFSERR_BADSESSION and be retried with the + * new session by nfsv4_setsequence(). + * Also wakeup() processes waiting for the + * new session. + */ + if (tsep != NULL) + wakeup(&tsep->nfsess_slots); + wakeup(&nmp->nm_sess); + NFSUNLOCKMNT(nmp); + } else + nfscl_freenfsclds(dsp); + NFSCL_DEBUG(1, "aft createsess=%d\n", error); if (error == 0 && reclaim == 0) { error = nfsrpc_reclaimcomplete(nmp, cred, p); NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error); @@ -875,6 +897,7 @@ nfsrpc_setclient(struct nfsmount *nmp, s mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); NFSLOCKMNT(nmp); TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list); + tsep = NFSMNT_MDSSESSION(nmp); NFSUNLOCKMNT(nmp); nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL); @@ -936,8 +959,8 @@ nfsrpc_setclient(struct nfsmount *nmp, s return (error); if (nd->nd_repstat == 0) { NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0] = *tl++; - NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1] = *tl++; + tsep->nfsess_clientid.lval[0] = *tl++; + tsep->nfsess_clientid.lval[1] = *tl++; confirm.lval[0] = *tl++; confirm.lval[1] = *tl; mbuf_freem(nd->nd_mrep); @@ -949,8 +972,8 @@ nfsrpc_setclient(struct nfsmount *nmp, s nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL, NULL); NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl++ = tsep->nfsess_clientid.lval[1]; *tl++ = confirm.lval[0]; *tl = confirm.lval[1]; nd->nd_flag |= ND_USEGSSNAME; @@ -1111,7 +1134,7 @@ nfsrpc_setattr(vnode_t vp, struct vattr else error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid, stuff); - if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) + if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); @@ -1368,7 +1391,7 @@ nfsrpc_read(vnode_t vp, struct uio *uiop &lckp); error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, attrflagp, stuff); - if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) + if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); @@ -1538,7 +1561,7 @@ nfsrpc_write(vnode_t vp, struct uio *uio else error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, newcred, &stateid, p, nap, attrflagp, stuff); - if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) + if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) nfscl_lockderef(lckp); @@ -1964,6 +1987,7 @@ nfsrpc_createv4(vnode_t dvp, char *name, nfsv4stateid_t stateid; u_int32_t rflags; struct nfsmount *nmp; + struct nfsclsession *tsep; nmp = VFSTONFS(dvp->v_mount); np = VTONFS(dvp); @@ -1983,8 +2007,9 @@ nfsrpc_createv4(vnode_t dvp, char *name, *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD); *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; - *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); @@ -2178,7 +2203,7 @@ nfsrpc_createv4(vnode_t dvp, char *name, } if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; - if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) + if (error == NFSERR_STALECLIENTID) nfscl_initiate_recovery(owp->nfsow_clp); nfsmout: if (!error) @@ -3840,6 +3865,7 @@ nfsrpc_lockt(struct nfsrv_descript *nd, uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; struct nfsnode *np; struct nfsmount *nmp; + struct nfsclsession *tsep; nmp = VFSTONFS(vp->v_mount); NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); @@ -3852,8 +3878,9 @@ nfsrpc_lockt(struct nfsrv_descript *nd, tl += 2; txdr_hyper(len, tl); tl += 2; - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; - *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; nfscl_filllockowner(id, own, flags); np = VTONFS(vp); NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], @@ -3893,8 +3920,7 @@ nfsrpc_lockt(struct nfsrv_descript *nd, error = EBADRPC; if (!error) error = nfsm_advance(nd, NFSM_RNDUP(size), -1); - } else if (nd->nd_repstat == NFSERR_STALECLIENTID || - nd->nd_repstat == NFSERR_BADSESSION) + } else if (nd->nd_repstat == NFSERR_STALECLIENTID) nfscl_initiate_recovery(clp); nfsmout: mbuf_freem(nd->nd_mrep); @@ -3944,8 +3970,7 @@ nfsrpc_locku(struct nfsrv_descript *nd, lp->nfsl_stateid.other[0] = *tl++; lp->nfsl_stateid.other[1] = *tl++; lp->nfsl_stateid.other[2] = *tl; - } else if (nd->nd_repstat == NFSERR_STALESTATEID || - nd->nd_repstat == NFSERR_BADSESSION) + } else if (nd->nd_repstat == NFSERR_STALESTATEID) nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); nfsmout: mbuf_freem(nd->nd_mrep); @@ -3964,6 +3989,7 @@ nfsrpc_lock(struct nfsrv_descript *nd, s u_int32_t *tl; int error, size; uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; + struct nfsclsession *tsep; nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL); NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); @@ -3989,8 +4015,9 @@ nfsrpc_lock(struct nfsrv_descript *nd, s *tl++ = lp->nfsl_open->nfso_stateid.other[1]; *tl++ = lp->nfsl_open->nfso_stateid.other[2]; *tl++ = txdr_unsigned(lp->nfsl_seqid); - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; - *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); @@ -4031,8 +4058,7 @@ nfsrpc_lock(struct nfsrv_descript *nd, s error = EBADRPC; if (!error) error = nfsm_advance(nd, NFSM_RNDUP(size), -1); - } else if (nd->nd_repstat == NFSERR_STALESTATEID || - nd->nd_repstat == NFSERR_BADSESSION) + } else if (nd->nd_repstat == NFSERR_STALESTATEID) nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); nfsmout: mbuf_freem(nd->nd_mrep); @@ -4232,25 +4258,36 @@ nfsrpc_renew(struct nfsclclient *clp, st struct nfsmount *nmp; int error; struct nfssockreq *nrp; + struct nfsclsession *tsep; nmp = clp->nfsc_nmp; if (nmp == NULL) return (0); - nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, - &dsp->nfsclds_sess); + if (dsp == NULL) + nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL); + else + nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, + &dsp->nfsclds_sess); if (!NFSHASNFSV4N(nmp)) { /* NFSv4.1 just uses a Sequence Op and not a Renew. */ NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; - *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; - } - nrp = dsp->nfsclds_sockp; + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; + } + nrp = NULL; + if (dsp != NULL) + nrp = dsp->nfsclds_sockp; if (nrp == NULL) /* If NULL, use the MDS socket. */ nrp = &nmp->nm_sockreq; nd->nd_flag |= ND_USEGSSNAME; - error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, - NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); + if (dsp == NULL) + error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, + NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); + else + error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, + NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); if (error) return (error); error = nd->nd_repstat; @@ -4269,6 +4306,7 @@ nfsrpc_rellockown(struct nfsmount *nmp, u_int32_t *tl; int error; uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; + struct nfsclsession *tsep; if (NFSHASNFSV4N(nmp)) { /* For NFSv4.1, do a FreeStateID. */ @@ -4279,8 +4317,9 @@ nfsrpc_rellockown(struct nfsmount *nmp, nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, NULL); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; - *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); @@ -4518,7 +4557,7 @@ nfsrpc_exchangeid(struct nfsmount *nmp, error = NFSERR_BADXDR; goto nfsmout; } - dsp = malloc(sizeof(struct nfsclds) + len, M_NFSCLDS, + dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS, M_WAITOK | M_ZERO); dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; dsp->nfsclds_servownlen = len; @@ -4661,10 +4700,12 @@ nfsrpc_destroysession(struct nfsmount *n struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; int error; + struct nfsclsession *tsep; nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL); NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); - bcopy(NFSMNT_MDSSESSION(nmp)->nfsess_sessionid, tl, NFSX_V4SESSIONID); + tsep = nfsmnt_mdssession(nmp); + bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID); nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); @@ -4686,11 +4727,13 @@ nfsrpc_destroyclient(struct nfsmount *nm struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; int error; + struct nfsclsession *tsep; nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL); NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); - *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; - *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; + tsep = nfsmnt_mdssession(nmp); + *tl++ = tsep->nfsess_clientid.lval[0]; + *tl = tsep->nfsess_clientid.lval[1]; nd->nd_flag |= ND_USEGSSNAME; error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); @@ -5158,6 +5201,7 @@ nfsrpc_getlayout(struct nfsmount *nmp, v struct nfsclflayouthead flh; int error = 0, islocked, layoutlen, recalled, retonclose; nfsv4stateid_t stateid; + struct nfsclsession *tsep; *lypp = NULL; /* @@ -5172,7 +5216,8 @@ nfsrpc_getlayout(struct nfsmount *nmp, v if (recalled != 0) return (EIO); LIST_INIT(&flh); - layoutlen = NFSMNT_MDSSESSION(nmp)->nfsess_maxcache - + tsep = nfsmnt_mdssession(nmp); + layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); if (lyp == NULL) { stateid.seqid = 0; @@ -5269,7 +5314,8 @@ nfsrpc_fillsa(struct nfsmount *nmp, stru if (msad != NULL && msad->sin_family == AF_INET && ssd->sin_addr.s_addr == msad->sin_addr.s_addr && ssd->sin_port == msad->sin_port && - (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) { + (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && + tdsp->nfsclds_sess.nfsess_defunct == 0) { *dspp = tdsp; NFSUNLOCKMNT(nmp); NFSCL_DEBUG(4, "fnd same addr\n"); @@ -5309,7 +5355,8 @@ nfsrpc_fillsa(struct nfsmount *nmp, stru IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr, &msad6->sin6_addr) && ssd6->sin6_port == msad6->sin6_port && - (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) { + (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && + tdsp->nfsclds_sess.nfsess_defunct == 0) { *dspp = tdsp; NFSUNLOCKMNT(nmp); return (0); @@ -5862,7 +5909,8 @@ nfscl_getsameserver(struct nfsmount *nmp if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && dsp->nfsclds_servownlen != 0 && !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, - dsp->nfsclds_servownlen)) { + dsp->nfsclds_servownlen) && + dsp->nfsclds_sess.nfsess_defunct == 0) { NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", TAILQ_FIRST(&nmp->nm_sess), dsp, dsp->nfsclds_flags); Modified: stable/11/sys/fs/nfsclient/nfs_clstate.c ============================================================================== --- stable/11/sys/fs/nfsclient/nfs_clstate.c Mon Apr 24 22:44:59 2017 (r317392) +++ stable/11/sys/fs/nfsclient/nfs_clstate.c Mon Apr 24 23:47:12 2017 (r317393) @@ -2470,8 +2470,11 @@ nfscl_renewthread(struct nfsclclient *cl if (recover_done_time < NFSD_MONOSEC) { recover_done_time = NFSD_MONOSEC + clp->nfsc_renew; + NFSCL_DEBUG(1, "Doing recovery..\n"); nfscl_recover(clp, cred, p); } else { + NFSCL_DEBUG(1, "Clear Recovery dt=%u ms=%jd\n", + recover_done_time, (intmax_t)NFSD_MONOSEC); NFSLOCKCLSTATE(); clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER; NFSUNLOCKCLSTATE(); @@ -2481,8 +2484,7 @@ nfscl_renewthread(struct nfsclclient *cl (clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID)) { clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; clidrev = clp->nfsc_clientidrev; - error = nfsrpc_renew(clp, - TAILQ_FIRST(&clp->nfsc_nmp->nm_sess), cred, p); + error = nfsrpc_renew(clp, NULL, cred, p); if (error == NFSERR_CBPATHDOWN) cbpathdown = 1; else if (error == NFSERR_STALECLIENTID || @@ -2494,24 +2496,27 @@ nfscl_renewthread(struct nfsclclient *cl (void) nfscl_hasexpired(clp, clidrev, p); } - /* Do renews for any DS sessions. */ checkdsrenew: - NFSLOCKMNT(clp->nfsc_nmp); - /* Skip first entry, since the MDS is handled above. */ - dsp = TAILQ_FIRST(&clp->nfsc_nmp->nm_sess); - if (dsp != NULL) - dsp = TAILQ_NEXT(dsp, nfsclds_list); - while (dsp != NULL) { - if (dsp->nfsclds_expire <= NFSD_MONOSEC) { - dsp->nfsclds_expire = NFSD_MONOSEC + - clp->nfsc_renew; - NFSUNLOCKMNT(clp->nfsc_nmp); - (void)nfsrpc_renew(clp, dsp, cred, p); - goto checkdsrenew; + if (NFSHASNFSV4N(clp->nfsc_nmp)) { + /* Do renews for any DS sessions. */ + NFSLOCKMNT(clp->nfsc_nmp); + /* Skip first entry, since the MDS is handled above. */ + dsp = TAILQ_FIRST(&clp->nfsc_nmp->nm_sess); + if (dsp != NULL) + dsp = TAILQ_NEXT(dsp, nfsclds_list); + while (dsp != NULL) { + if (dsp->nfsclds_expire <= NFSD_MONOSEC && + dsp->nfsclds_sess.nfsess_defunct == 0) { + dsp->nfsclds_expire = NFSD_MONOSEC + + clp->nfsc_renew; + NFSUNLOCKMNT(clp->nfsc_nmp); + (void)nfsrpc_renew(clp, dsp, cred, p); + goto checkdsrenew; + } + dsp = TAILQ_NEXT(dsp, nfsclds_list); } - dsp = TAILQ_NEXT(dsp, nfsclds_list); + NFSUNLOCKMNT(clp->nfsc_nmp); } - NFSUNLOCKMNT(clp->nfsc_nmp); TAILQ_INIT(&dh); NFSLOCKCLSTATE(); @@ -3163,6 +3168,7 @@ nfscl_docb(struct nfsrv_descript *nd, NF int changed, gotone, laytype, recalltype; uint32_t iomode; struct nfsclrecalllayout *recallp = NULL; + struct nfsclsession *tsep; gotseq_ok = 0; nfsrvd_rephead(nd); @@ -3472,13 +3478,12 @@ nfscl_docb(struct nfsrv_descript *nd, NF error = NFSERR_SERVERFAULT; } else error = NFSERR_SEQUENCEPOS; - if (error == 0) + if (error == 0) { + tsep = nfsmnt_mdssession(clp->nfsc_nmp); error = nfsv4_seqsession(seqid, slotid, - highslot, - NFSMNT_MDSSESSION(clp->nfsc_nmp)-> - nfsess_cbslots, &rep, - NFSMNT_MDSSESSION(clp->nfsc_nmp)-> - nfsess_backslots); + highslot, tsep->nfsess_cbslots, &rep, + tsep->nfsess_backslots); + } NFSUNLOCKCLSTATE(); if (error == 0) { gotseq_ok = 1; @@ -3546,8 +3551,8 @@ out: NFSLOCKCLSTATE(); clp = nfscl_getclntsess(sessionid); if (clp != NULL) { - nfsv4_seqsess_cacherep(slotid, - NFSMNT_MDSSESSION(clp->nfsc_nmp)->nfsess_cbslots, + tsep = nfsmnt_mdssession(clp->nfsc_nmp); + nfsv4_seqsess_cacherep(slotid, tsep->nfsess_cbslots, NFSERR_OK, &rep); NFSUNLOCKCLSTATE(); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***