diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2006-09-18 15:35:22 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2006-09-18 15:35:22 +0000 |
commit | 4dec8579bdbf913fb76395edfc6c6b47af53c32b (patch) | |
tree | 7dcbe559c7085c5cf0357d6e47c34d1c11407b1d /sys/kern/vfs_mount.c | |
parent | 81ae4b8da9920ccfb697984dbb2e8751573d183a (diff) | |
download | src-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.c | 38 |
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); |