aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_mount.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2006-09-18 15:35:22 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2006-09-18 15:35:22 +0000
commit4dec8579bdbf913fb76395edfc6c6b47af53c32b (patch)
tree7dcbe559c7085c5cf0357d6e47c34d1c11407b1d /sys/kern/vfs_mount.c
parent81ae4b8da9920ccfb697984dbb2e8751573d183a (diff)
downloadsrc-4dec8579bdbf913fb76395edfc6c6b47af53c32b.tar.gz
src-4dec8579bdbf913fb76395edfc6c6b47af53c32b.zip
Fix the race while waiting for coveredvp lock during unmount. The vnode may
be recycled during the sleep, wrap the vn_lock with vhold/vdrop. Check that coveredvp still points to the same mp after sleep (needed because sleep dropped Giant). Move check for user rights for unmount after coveredvp lock is obtained. Tested by: Peter Holm Reviewed by: tegge Approved by: kan (mentor) MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=162407
Diffstat (limited to 'sys/kern/vfs_mount.c')
-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);