--- fs/nfsserver/nfs_nfsdstate.c.nodstsess 2018-05-29 18:15:02.777775000 -0400 +++ fs/nfsserver/nfs_nfsdstate.c 2018-05-29 18:49:21.903599000 -0400 @@ -710,8 +710,10 @@ nfsrv_destroyclient(nfsquad_t clientid, { struct nfsclient *clp; struct nfsclienthashhead *hp; - int error = 0, i, igotlock; + struct nfsdsession *sep; + int error, i, igotlock; + error = 0; if (nfsrvboottime != clientid.lval[0]) { error = NFSERR_STALECLIENTID; goto out; @@ -740,19 +742,24 @@ nfsrv_destroyclient(nfsquad_t clientid, } /* Scan for state on the clientid. */ - for (i = 0; i < nfsrv_statehashsize; i++) - if (!LIST_EMPTY(&clp->lc_stateid[i])) { - NFSLOCKV4ROOTMUTEX(); - nfsv4_unlock(&nfsv4rootfs_lock, 1); - NFSUNLOCKV4ROOTMUTEX(); + if (!LIST_EMPTY(&clp->lc_deleg)) + error = NFSERR_CLIENTIDBUSY; + for (i = 0; i < nfsrv_statehashsize && error == 0; i++) + if (!LIST_EMPTY(&clp->lc_stateid[i])) error = NFSERR_CLIENTIDBUSY; - goto out; + if (error == 0) { + LIST_FOREACH(sep, &clp->lc_session, sess_list) { + if ((sep->sess_crflags & NFSV4CRSESS_DEFUNCT) == 0) { + error = NFSERR_CLIENTIDBUSY; + break; + } } - if (!LIST_EMPTY(&clp->lc_session) || !LIST_EMPTY(&clp->lc_deleg)) { + } + + if (error != 0) { NFSLOCKV4ROOTMUTEX(); nfsv4_unlock(&nfsv4rootfs_lock, 1); NFSUNLOCKV4ROOTMUTEX(); - error = NFSERR_CLIENTIDBUSY; goto out; } @@ -5993,7 +6000,8 @@ nfsrv_findsession(uint8_t *sessionid) shp = NFSSESSIONHASH(sessionid); LIST_FOREACH(sep, &shp->list, sess_hash) { - if (!NFSBCMP(sessionid, sep->sess_sessionid, NFSX_V4SESSIONID)) + if (NFSBCMP(sessionid, sep->sess_sessionid, NFSX_V4SESSIONID) == + 0 && (sep->sess_crflags & NFSV4CRSESS_DEFUNCT) == 0) break; } return (sep); @@ -6005,15 +6013,25 @@ nfsrv_findsession(uint8_t *sessionid) int nfsrv_destroysession(struct nfsrv_descript *nd, uint8_t *sessionid) { + struct nfssessionhash *shp; + struct nfsdsession *sep; int error, samesess; samesess = 0; + error = 0; if (!NFSBCMP(sessionid, nd->nd_sessionid, NFSX_V4SESSIONID)) { samesess = 1; if ((nd->nd_flag & ND_LASTOP) == 0) return (NFSERR_BADSESSION); } - error = nfsrv_freesession(NULL, sessionid); + shp = NFSSESSIONHASH(sessionid); + NFSLOCKSESSION(shp); + sep = nfsrv_findsession(sessionid); + if (sep != NULL) + sep->sess_crflags |= NFSV4CRSESS_DEFUNCT; + NFSUNLOCKSESSION(shp); + if (sep == NULL) + error = NFSERR_BADSESSION; if (error == 0 && samesess != 0) nd->nd_flag &= ~ND_HASSEQUENCE; return (error); --- fs/nfs/nfsproto.h.nodstsess 2018-05-29 18:33:37.179826000 -0400 +++ fs/nfs/nfsproto.h 2018-05-29 18:34:43.509040000 -0400 @@ -616,6 +616,9 @@ #define NFSV4CRSESS_CONNBACKCHAN 0x00000002 #define NFSV4CRSESS_CONNRDMA 0x00000004 +/* Fake flag for Create Session used internally. */ +#define NFSV4CRSESS_DEFUNCT 0x80000000 + /* Flags for Sequence */ #define NFSV4SEQ_CBPATHDOWN 0x00000001 #define NFSV4SEQ_CBGSSCONTEXPIRING 0x00000002