diff options
author | rmacklem <rmacklem@FreeBSD.org> | 2013-09-01 23:02:59 +0000 |
---|---|---|
committer | rmacklem <rmacklem@FreeBSD.org> | 2013-09-01 23:02:59 +0000 |
commit | 8d06f831a7fd6d823c0aff22030a780f8b8fd05e (patch) | |
tree | d7581118dafcc5b29d5d01d4bb41cb2114a97168 /sys/fs/nfsclient/nfs_clvfsops.c | |
parent | 09ec5c277c487bd53321f3f207be7a596ea08f65 (diff) | |
download | FreeBSD-src-8d06f831a7fd6d823c0aff22030a780f8b8fd05e.zip FreeBSD-src-8d06f831a7fd6d823c0aff22030a780f8b8fd05e.tar.gz |
Forced dismounts of NFS mounts can fail when thread(s) are stuck
waiting for an RPC reply from the server while holding the mount
point busy (mnt_lockref incremented). This happens because dounmount()
msleep()s waiting for mnt_lockref to become 0, before calling
VFS_UNMOUNT(). This patch adds a new VFS operation called VFS_PURGE(),
which the NFS client implements as purging RPCs in progress. Making
this call before checking mnt_lockref fixes the problem, by ensuring
that the VOP_xxx() calls will fail and unbusy the mount point.
Reported by: sbruno
Reviewed by: kib
MFC after: 2 weeks
Diffstat (limited to 'sys/fs/nfsclient/nfs_clvfsops.c')
-rw-r--r-- | sys/fs/nfsclient/nfs_clvfsops.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index 863c418..4a180c5 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -120,6 +120,7 @@ static vfs_root_t nfs_root; static vfs_statfs_t nfs_statfs; static vfs_sync_t nfs_sync; static vfs_sysctl_t nfs_sysctl; +static vfs_purge_t nfs_purge; /* * nfs vfs operations. @@ -134,6 +135,7 @@ static struct vfsops nfs_vfsops = { .vfs_uninit = ncl_uninit, .vfs_unmount = nfs_unmount, .vfs_sysctl = nfs_sysctl, + .vfs_purge = nfs_purge, }; VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY); @@ -1676,6 +1678,19 @@ nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) } /* + * Purge any RPCs in progress, so that they will all return errors. + * This allows dounmount() to continue as far as VFS_UNMOUNT() for a + * forced dismount. + */ +static void +nfs_purge(struct mount *mp) +{ + struct nfsmount *nmp = VFSTONFS(mp); + + newnfs_nmcancelreqs(nmp); +} + +/* * Extract the information needed by the nlm from the nfs vnode. */ static void |