aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/vfs_mount.c38
1 files changed, 26 insertions, 12 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index 34275c189a56..486c8a1460e7 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -1103,16 +1103,6 @@ unmount(td, uap)
}
/*
- * Only privileged root, or (if MNT_USER is set) the user that did the
- * original mount is permitted to unmount this filesystem.
- */
- error = vfs_suser(mp, td);
- if (error) {
- mtx_unlock(&Giant);
- return (error);
- }
-
- /*
* Don't allow unmounting the root filesystem.
*/
if (mp->mnt_flag & MNT_ROOTFS) {
@@ -1139,8 +1129,32 @@ dounmount(mp, flags, td)
mtx_assert(&Giant, MA_OWNED);
- if ((coveredvp = mp->mnt_vnodecovered) != NULL)
- vn_lock(coveredvp, LK_EXCLUSIVE | LK_RETRY, td);
+ if ((coveredvp = mp->mnt_vnodecovered) != NULL) {
+ VI_LOCK(coveredvp);
+ vholdl(coveredvp);
+ error = vn_lock(coveredvp, LK_EXCLUSIVE | LK_INTERLOCK, td);
+ vdrop(coveredvp);
+ /*
+ * Check for mp being unmounted while waiting for the
+ * covered vnode lock.
+ */
+ if (error)
+ return (error);
+ if (coveredvp->v_mountedhere != mp) {
+ VOP_UNLOCK(coveredvp, 0, td);
+ return (EBUSY);
+ }
+ }
+ /*
+ * Only privileged root, or (if MNT_USER is set) the user that did the
+ * original mount is permitted to unmount this filesystem.
+ */
+ error = vfs_suser(mp, td);
+ if (error) {
+ VOP_UNLOCK(coveredvp, 0, td);
+ return (error);
+ }
+
MNT_ILOCK(mp);
if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
MNT_IUNLOCK(mp);