nfscl: Fix two more cases for forced dismount

Although I was not able to cause a failure during testing, there
are places in nfscl_removedeleg() and nfscl_renamedeleg() where
I think a forced dismount could get hung.  This patch fixes those.

This patch only affects forced dismount and only if the NFSv4
server is issuing delegations to the client.

Found by code inspection.

MFC after:	2 weeks
This commit is contained in:
Rick Macklem 2021-11-05 15:33:19 -07:00
parent e2157cd000
commit f5d5164fb6

View File

@ -4669,6 +4669,7 @@ nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp)
struct nfsclowner *owp;
struct nfscllockowner *lp;
struct nfsmount *nmp;
struct mount *mp;
struct ucred *cred;
struct nfsnode *np;
int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept;
@ -4683,6 +4684,7 @@ nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp)
}
NFSUNLOCKMNT(nmp);
np = VTONFS(vp);
mp = nmp->nm_mountp;
NFSLOCKCLSTATE();
/*
* Loop around waiting for:
@ -4709,8 +4711,13 @@ nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp)
igotlock = 0;
}
dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
(void) nfsmsleep(&dp->nfsdl_rwlock,
NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
msleep(&dp->nfsdl_rwlock, NFSCLSTATEMUTEXPTR, PZERO,
"nfscld", hz);
if (NFSCL_FORCEDISM(mp)) {
dp->nfsdl_flags &= ~NFSCLDL_DELEGRET;
NFSUNLOCKCLSTATE();
return (0);
}
continue;
}
needsrecall = 0;
@ -4733,7 +4740,14 @@ nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp)
islept = 0;
while (!igotlock) {
igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
&islept, NFSCLSTATEMUTEXPTR, NULL);
&islept, NFSCLSTATEMUTEXPTR, mp);
if (NFSCL_FORCEDISM(mp)) {
dp->nfsdl_flags &= ~NFSCLDL_DELEGRET;
if (igotlock)
nfsv4_unlock(&clp->nfsc_lock, 0);
NFSUNLOCKCLSTATE();
return (0);
}
if (islept)
break;
}
@ -4774,6 +4788,7 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
struct nfsclowner *owp;
struct nfscllockowner *lp;
struct nfsmount *nmp;
struct mount *mp;
struct ucred *cred;
struct nfsnode *np;
int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept;
@ -4789,6 +4804,7 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
return (retcnt);
}
NFSUNLOCKMNT(nmp);
mp = nmp->nm_mountp;
NFSLOCKCLSTATE();
/*
* Loop around waiting for:
@ -4816,8 +4832,15 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
igotlock = 0;
}
dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
(void) nfsmsleep(&dp->nfsdl_rwlock,
NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
msleep(&dp->nfsdl_rwlock, NFSCLSTATEMUTEXPTR, PZERO,
"nfscld", hz);
if (NFSCL_FORCEDISM(mp)) {
dp->nfsdl_flags &= ~NFSCLDL_DELEGRET;
NFSUNLOCKCLSTATE();
*gotfdp = 0;
*gottdp = 0;
return (0);
}
continue;
}
needsrecall = 0;
@ -4840,7 +4863,16 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
islept = 0;
while (!igotlock) {
igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
&islept, NFSCLSTATEMUTEXPTR, NULL);
&islept, NFSCLSTATEMUTEXPTR, mp);
if (NFSCL_FORCEDISM(mp)) {
dp->nfsdl_flags &= ~NFSCLDL_DELEGRET;
if (igotlock)
nfsv4_unlock(&clp->nfsc_lock, 0);
NFSUNLOCKCLSTATE();
*gotfdp = 0;
*gottdp = 0;
return (0);
}
if (islept)
break;
}
@ -4877,8 +4909,14 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
*/
if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
(void) nfsmsleep(&dp->nfsdl_rwlock,
NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
msleep(&dp->nfsdl_rwlock, NFSCLSTATEMUTEXPTR, PZERO,
"nfscld", hz);
if (NFSCL_FORCEDISM(mp)) {
NFSUNLOCKCLSTATE();
*gotfdp = 0;
*gottdp = 0;
return (0);
}
continue;
}
LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {