svn commit: r255136 - in head/sys: fs/nfsclient kern sys
Rick Macklem
rmacklem at FreeBSD.org
Sun Sep 1 23:03:00 UTC 2013
Author: rmacklem
Date: Sun Sep 1 23:02:59 2013
New Revision: 255136
URL: http://svnweb.freebsd.org/changeset/base/255136
Log:
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
Modified:
head/sys/fs/nfsclient/nfs_clvfsops.c
head/sys/kern/vfs_mount.c
head/sys/sys/mount.h
Modified: head/sys/fs/nfsclient/nfs_clvfsops.c
==============================================================================
--- head/sys/fs/nfsclient/nfs_clvfsops.c Sun Sep 1 22:30:24 2013 (r255135)
+++ head/sys/fs/nfsclient/nfs_clvfsops.c Sun Sep 1 23:02:59 2013 (r255136)
@@ -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 o
}
/*
+ * 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
Modified: head/sys/kern/vfs_mount.c
==============================================================================
--- head/sys/kern/vfs_mount.c Sun Sep 1 22:30:24 2013 (r255135)
+++ head/sys/kern/vfs_mount.c Sun Sep 1 23:02:59 2013 (r255136)
@@ -1269,8 +1269,16 @@ dounmount(mp, flags, td)
}
mp->mnt_kern_flag |= MNTK_UNMOUNT | MNTK_NOINSMNTQ;
/* Allow filesystems to detect that a forced unmount is in progress. */
- if (flags & MNT_FORCE)
+ if (flags & MNT_FORCE) {
mp->mnt_kern_flag |= MNTK_UNMOUNTF;
+ MNT_IUNLOCK(mp);
+ /*
+ * Must be done after setting MNTK_UNMOUNTF and before
+ * waiting for mnt_lockref to become 0.
+ */
+ VFS_PURGE(mp);
+ MNT_ILOCK(mp);
+ }
error = 0;
if (mp->mnt_lockref) {
mp->mnt_kern_flag |= MNTK_DRAINING;
Modified: head/sys/sys/mount.h
==============================================================================
--- head/sys/sys/mount.h Sun Sep 1 22:30:24 2013 (r255135)
+++ head/sys/sys/mount.h Sun Sep 1 23:02:59 2013 (r255136)
@@ -609,6 +609,7 @@ typedef int vfs_sysctl_t(struct mount *m
struct sysctl_req *req);
typedef void vfs_susp_clean_t(struct mount *mp);
typedef void vfs_notify_lowervp_t(struct mount *mp, struct vnode *lowervp);
+typedef void vfs_purge_t(struct mount *mp);
struct vfsops {
vfs_mount_t *vfs_mount;
@@ -628,6 +629,7 @@ struct vfsops {
vfs_susp_clean_t *vfs_susp_clean;
vfs_notify_lowervp_t *vfs_reclaim_lowervp;
vfs_notify_lowervp_t *vfs_unlink_lowervp;
+ vfs_purge_t *vfs_purge;
vfs_mount_t *vfs_spare[6]; /* spares for ABI compat */
};
@@ -757,6 +759,14 @@ vfs_statfs_t __vfs_statfs;
} \
} while (0)
+#define VFS_PURGE(MP) do { \
+ if (*(MP)->mnt_op->vfs_purge != NULL) { \
+ VFS_PROLOGUE(MP); \
+ (*(MP)->mnt_op->vfs_purge)(MP); \
+ VFS_EPILOGUE(MP); \
+ } \
+} while (0)
+
#define VFS_KNOTE_LOCKED(vp, hint) do \
{ \
if (((vp)->v_vflag & VV_NOKNOTE) == 0) \
More information about the svn-src-all
mailing list