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
This commit is contained in:
Konstantin Belousov 2006-09-18 15:35:22 +00:00
parent 81ae4b8da9
commit 4dec8579bd

View File

@ -1102,16 +1102,6 @@ unmount(td, uap)
return ((uap->flags & MNT_BYFSID) ? ENOENT : EINVAL);
}
/*
* 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.
*/
@ -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);