aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2021-11-05 22:33:19 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2021-11-05 22:33:19 +0000
commitf5d5164fb607ab9c51c52ace4ec241f6cac7cc5c (patch)
tree3452e72899775d0ec832017c9bfe258252aef9b5
parente2157cd0000f6dbb6465d7a885f2dcfd4d3596cb (diff)
downloadsrc-f5d5164fb607ab9c51c52ace4ec241f6cac7cc5c.tar.gz
src-f5d5164fb607ab9c51c52ace4ec241f6cac7cc5c.zip
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
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index 42233ea7cf9d..1df8530d0e39 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -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) {