summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2016-06-22 09:10:52 +0000
committerkib <kib@FreeBSD.org>2016-06-22 09:10:52 +0000
commit7e5b45f1a4d56b26af6cdae84793f42f6463e6b4 (patch)
treedc74da49111f7e881ff25ac981eefdaac46ab265
parent8d8c417dfc0789f578cde79405001265c773afc0 (diff)
downloadFreeBSD-src-7e5b45f1a4d56b26af6cdae84793f42f6463e6b4.zip
FreeBSD-src-7e5b45f1a4d56b26af6cdae84793f42f6463e6b4.tar.gz
MFC r301929:
Do not assume that we own the use reference on the covered vnode until we set MNTK_UNMOUNT flag on the mp.
-rw-r--r--sys/kern/vfs_mount.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index 3ca995f..f5f522e 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -1222,7 +1222,6 @@ dounmount(struct mount *mp, int flags, struct thread *td)
VI_LOCK(coveredvp);
vholdl(coveredvp);
vn_lock(coveredvp, LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY);
- vdrop(coveredvp);
/*
* Check for mp being unmounted while waiting for the
* covered vnode lock.
@@ -1230,18 +1229,22 @@ dounmount(struct mount *mp, int flags, struct thread *td)
if (coveredvp->v_mountedhere != mp ||
coveredvp->v_mountedhere->mnt_gen != mnt_gen_r) {
VOP_UNLOCK(coveredvp, 0);
+ vdrop(coveredvp);
vfs_rel(mp);
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 != 0) {
- if (coveredvp)
+ if (coveredvp != NULL) {
VOP_UNLOCK(coveredvp, 0);
+ vdrop(coveredvp);
+ }
vfs_rel(mp);
return (error);
}
@@ -1251,8 +1254,10 @@ dounmount(struct mount *mp, int flags, struct thread *td)
if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 ||
!TAILQ_EMPTY(&mp->mnt_uppers)) {
MNT_IUNLOCK(mp);
- if (coveredvp)
+ if (coveredvp != NULL) {
VOP_UNLOCK(coveredvp, 0);
+ vdrop(coveredvp);
+ }
vn_finished_write(mp);
return (EBUSY);
}
@@ -1285,6 +1290,16 @@ dounmount(struct mount *mp, int flags, struct thread *td)
if (mp->mnt_flag & MNT_EXPUBLIC)
vfs_setpublicfs(NULL, NULL, NULL);
+ /*
+ * From now, we can claim that the use reference on the
+ * coveredvp is ours, and the ref can be released only by
+ * successfull unmount by us, or left for later unmount
+ * attempt. The previously acquired hold reference is no
+ * longer needed to protect the vnode from reuse.
+ */
+ if (coveredvp != NULL)
+ vdrop(coveredvp);
+
vfs_msync(mp, MNT_WAIT);
MNT_ILOCK(mp);
async_flag = mp->mnt_flag & MNT_ASYNC;
OpenPOWER on IntegriCloud