summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfs
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2011-05-27 22:05:10 +0000
committerrmacklem <rmacklem@FreeBSD.org>2011-05-27 22:05:10 +0000
commit7d4b16f6f8f2a016827f64398c5a7f59247e56b3 (patch)
tree4ac25cf194121a23f96fba1eb360ebde0f255320 /sys/fs/nfs
parentaa5140b7ec861ac2939b1db8b6aa22e74a58a1d7 (diff)
downloadFreeBSD-src-7d4b16f6f8f2a016827f64398c5a7f59247e56b3.zip
FreeBSD-src-7d4b16f6f8f2a016827f64398c5a7f59247e56b3.tar.gz
Fix the new NFS client so that it handles NFSv4 state
correctly during a forced dismount. This required that the exclusive and shared (refcnt) sleep lock functions check for MNTK_UMOUNTF before sleeping, so that they won't block while nfscl_umount() is getting rid of the state. As such, a "struct mount *" argument was added to the locking functions. I believe the only remaining case where a forced dismount can get hung in the kernel is when a thread is already attempting to do a TCP connect to a dead server when the krpc client structure called nr_client is NULL. This will only happen just after a "mount -u" with options that force a new TCP connection is done, so it shouldn't be a problem in practice. MFC after: 2 weeks
Diffstat (limited to 'sys/fs/nfs')
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c19
-rw-r--r--sys/fs/nfs/nfs_var.h4
2 files changed, 18 insertions, 5 deletions
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index e725889..03b5786 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -1726,11 +1726,13 @@ nfsmout:
* Any usecnt must be decremented by calling nfsv4_relref() before
* calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
* be called in a loop.
- * The last argument is set to indicate if the call slept, iff not NULL.
+ * The isleptp argument is set to indicate if the call slept, iff not NULL
+ * and the mp argument indicates to check for a forced dismount, iff not
+ * NULL.
*/
APPLESTATIC int
nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
- void *mutex)
+ void *mutex, struct mount *mp)
{
if (isleptp)
@@ -1751,6 +1753,10 @@ nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
}
while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
+ if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
+ return (0);
+ }
lp->nfslock_lock |= NFSV4LOCK_WANTED;
if (isleptp)
*isleptp = 1;
@@ -1801,9 +1807,12 @@ nfsv4_relref(struct nfsv4lock *lp)
* not wait for threads that want the exclusive lock. If priority needs
* to be given to threads that need the exclusive lock, a call to nfsv4_lock()
* with the 2nd argument == 0 should be done before calling nfsv4_getref().
+ * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
+ * return without getting a refcnt for that case.
*/
APPLESTATIC void
-nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex)
+nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
+ struct mount *mp)
{
if (isleptp)
@@ -1813,12 +1822,16 @@ nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex)
* Wait for a lock held.
*/
while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
+ if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
+ return;
lp->nfslock_lock |= NFSV4LOCK_WANTED;
if (isleptp)
*isleptp = 1;
(void) nfsmsleep(&lp->nfslock_lock, mutex,
PZERO - 1, "nfsv4lck", NULL);
}
+ if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
+ return;
lp->nfslock_usecnt++;
}
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index d83d523..8ed60a7 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -247,10 +247,10 @@ int nfsv4_loadattr(struct nfsrv_descript *, vnode_t,
struct nfsv3_pathconf *, struct statfs *, struct nfsstatfs *,
struct nfsfsinfo *, NFSACL_T *,
int, int *, u_int32_t *, u_int32_t *, NFSPROC_T *, struct ucred *);
-int nfsv4_lock(struct nfsv4lock *, int, int *, void *);
+int nfsv4_lock(struct nfsv4lock *, int, int *, void *, struct mount *);
void nfsv4_unlock(struct nfsv4lock *, int);
void nfsv4_relref(struct nfsv4lock *);
-void nfsv4_getref(struct nfsv4lock *, int *, void *);
+void nfsv4_getref(struct nfsv4lock *, int *, void *, struct mount *);
int nfsv4_getref_nonblock(struct nfsv4lock *);
int nfsv4_testlock(struct nfsv4lock *);
int nfsrv_mtostr(struct nfsrv_descript *, char *, int);
OpenPOWER on IntegriCloud