diff options
author | Edward Tomasz Napierala <trasz@FreeBSD.org> | 2016-07-07 09:03:57 +0000 |
---|---|---|
committer | Edward Tomasz Napierala <trasz@FreeBSD.org> | 2016-07-07 09:03:57 +0000 |
commit | debc480e037b7337cc27dd1200d64ac55eea0644 (patch) | |
tree | 595990c3c63580feac383e70c62f36197568ff07 /sys/kern/vfs_mount.c | |
parent | af625dc998ce3224c05ce266562da7a33904ac2e (diff) | |
download | src-debc480e037b7337cc27dd1200d64ac55eea0644.tar.gz src-debc480e037b7337cc27dd1200d64ac55eea0644.zip |
Notes
Diffstat (limited to 'sys/kern/vfs_mount.c')
-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 1f4592f79548..247714f07cb4 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; |