summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authortrasz <trasz@FreeBSD.org>2016-07-07 09:03:57 +0000
committertrasz <trasz@FreeBSD.org>2016-07-07 09:03:57 +0000
commitaea1562f16d3c164b2aa8e81aba14f422c17f30c (patch)
tree595990c3c63580feac383e70c62f36197568ff07 /sys/kern
parent85b925bd283d447cb8bf245b2e216ee9e3e31dcf (diff)
downloadFreeBSD-src-aea1562f16d3c164b2aa8e81aba14f422c17f30c.zip
FreeBSD-src-aea1562f16d3c164b2aa8e81aba14f422c17f30c.tar.gz
Add new unmount(2) flag, MNT_NONBUSY, to check whether there are
any open vnodes before proceeding. Make autounmound(8) use this flag. Without it, even an unsuccessfull unmount causes filesystem flush, which interferes with normal operation. Reviewed by: kib@ Approved by: re (gjb@) MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D7047
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_mount.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index 1f4592f..247714f 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -1205,6 +1205,28 @@ sys_unmount(struct thread *td, struct unmount_args *uap)
}
/*
+ * Return error if any of the vnodes, ignoring the root vnode
+ * and the syncer vnode, have non-zero usecount.
+ */
+static int
+vfs_check_usecounts(struct mount *mp)
+{
+ struct vnode *vp, *mvp;
+
+ MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
+ if ((vp->v_vflag & VV_ROOT) == 0 && vp->v_type != VNON &&
+ vp->v_usecount != 0) {
+ VI_UNLOCK(vp);
+ MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
+ return (EBUSY);
+ }
+ VI_UNLOCK(vp);
+ }
+
+ return (0);
+}
+
+/*
* Do the actual filesystem unmount.
*/
int
@@ -1260,6 +1282,21 @@ dounmount(struct mount *mp, int flags, struct thread *td)
return (EBUSY);
}
mp->mnt_kern_flag |= MNTK_UNMOUNT | MNTK_NOINSMNTQ;
+ if (flags & MNT_NONBUSY) {
+ MNT_IUNLOCK(mp);
+ error = vfs_check_usecounts(mp);
+ MNT_ILOCK(mp);
+ if (error != 0) {
+ mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_NOINSMNTQ);
+ MNT_IUNLOCK(mp);
+ if (coveredvp != NULL) {
+ VOP_UNLOCK(coveredvp, 0);
+ vdrop(coveredvp);
+ }
+ vn_finished_write(mp);
+ return (error);
+ }
+ }
/* Allow filesystems to detect that a forced unmount is in progress. */
if (flags & MNT_FORCE) {
mp->mnt_kern_flag |= MNTK_UNMOUNTF;
OpenPOWER on IntegriCloud