diff options
author | trasz <trasz@FreeBSD.org> | 2016-07-07 09:03:57 +0000 |
---|---|---|
committer | trasz <trasz@FreeBSD.org> | 2016-07-07 09:03:57 +0000 |
commit | aea1562f16d3c164b2aa8e81aba14f422c17f30c (patch) | |
tree | 595990c3c63580feac383e70c62f36197568ff07 /sys/kern | |
parent | 85b925bd283d447cb8bf245b2e216ee9e3e31dcf (diff) | |
download | FreeBSD-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.c | 37 |
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; |