mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-31 12:56:10 +01:00
dounmount(9): temporarily enable recursion for the covered vnode lock
For some complex nullfs mount configurations, it is possible to get the covered vnode lock for the mount shared with some inside-mount vnode lock. Then at unmount time, vflush() would recurse on the covered vnode lock when reclaiming the vnode. Work around it, by temprorarily allowing recursion on the covered vnode lock. Disable recursion after the unmount if it was not enabled before. PR: 297174 Reviewed by: jah Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D58567
This commit is contained in:
1 parent
1d97ad676d
commit
9f5c4ef328
1 file changed
+26
-3
+26
-3
@@ -1880,7 +1880,8 @@ vfs_check_usecounts(struct mount *mp)
|
||||
}
|
||||
|
||||
static void
|
||||
dounmount_cleanup(struct mount *mp, struct vnode *coveredvp, int mntkflags)
|
||||
dounmount_cleanup(struct mount *mp, struct vnode *coveredvp, int mntkflags,
|
||||
bool disablerec)
|
||||
{
|
||||
|
||||
mtx_assert(MNT_MTX(mp), MA_OWNED);
|
||||
@@ -1892,6 +1893,8 @@ dounmount_cleanup(struct mount *mp, struct vnode *coveredvp, int mntkflags)
|
||||
vfs_op_exit_locked(mp);
|
||||
MNT_IUNLOCK(mp);
|
||||
if (coveredvp != NULL) {
|
||||
if (disablerec)
|
||||
VN_LOCK_DREC(coveredvp);
|
||||
VOP_UNLOCK(coveredvp);
|
||||
vdrop(coveredvp);
|
||||
}
|
||||
@@ -2193,6 +2196,7 @@ dounmount(struct mount *mp, uint64_t flags, struct thread *td)
|
||||
uint64_t async_flag;
|
||||
int mnt_gen_r;
|
||||
unsigned int retries;
|
||||
bool coveredrec;
|
||||
|
||||
KASSERT((flags & MNT_DEFERRED) == 0 ||
|
||||
(flags & (MNT_RECURSE | MNT_FORCE)) == (MNT_RECURSE | MNT_FORCE),
|
||||
@@ -2301,6 +2305,7 @@ dounmount(struct mount *mp, uint64_t flags, struct thread *td)
|
||||
if ((flags & MNT_DEFERRED) != 0)
|
||||
vfs_ref(mp);
|
||||
|
||||
coveredrec = false;
|
||||
if ((coveredvp = mp->mnt_vnodecovered) != NULL) {
|
||||
mnt_gen_r = mp->mnt_gen;
|
||||
VI_LOCK(coveredvp);
|
||||
@@ -2317,6 +2322,19 @@ dounmount(struct mount *mp, uint64_t flags, struct thread *td)
|
||||
vfs_rel(mp);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
/*
|
||||
* For some complex nullfs mount configurations, it is
|
||||
* possible to get the covered vnode lock for the
|
||||
* mount shared with some inside-mount vnode lock.
|
||||
* Then at unmount time, vflush() would recurse on the
|
||||
* covered vnode lock when reclaiming the vnode.
|
||||
*
|
||||
* To work around it, temprorarily allow recursion for
|
||||
* the covered vnode lock.
|
||||
*/
|
||||
coveredrec = VN_LOCK_CANREC(coveredvp);
|
||||
VN_LOCK_AREC(coveredvp);
|
||||
}
|
||||
|
||||
vfs_op_enter(mp);
|
||||
@@ -2326,7 +2344,7 @@ dounmount(struct mount *mp, uint64_t flags, struct thread *td)
|
||||
if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 ||
|
||||
(mp->mnt_flag & MNT_UPDATE) != 0 ||
|
||||
!TAILQ_EMPTY(&mp->mnt_uppers)) {
|
||||
dounmount_cleanup(mp, coveredvp, 0);
|
||||
dounmount_cleanup(mp, coveredvp, 0, !coveredrec);
|
||||
return (EBUSY);
|
||||
}
|
||||
mp->mnt_kern_flag |= MNTK_UNMOUNT;
|
||||
@@ -2339,7 +2357,8 @@ dounmount(struct mount *mp, uint64_t flags, struct thread *td)
|
||||
MNT_ILOCK(mp);
|
||||
if (error != 0) {
|
||||
vn_seqc_write_end(coveredvp);
|
||||
dounmount_cleanup(mp, coveredvp, MNTK_UNMOUNT);
|
||||
dounmount_cleanup(mp, coveredvp, MNTK_UNMOUNT,
|
||||
!coveredrec);
|
||||
if (rootvp != NULL) {
|
||||
vn_seqc_write_end(rootvp);
|
||||
vrele(rootvp);
|
||||
@@ -2425,6 +2444,8 @@ dounmount(struct mount *mp, uint64_t flags, struct thread *td)
|
||||
MNT_IUNLOCK(mp);
|
||||
if (coveredvp) {
|
||||
vn_seqc_write_end(coveredvp);
|
||||
if (!coveredrec)
|
||||
VN_LOCK_DREC(coveredvp);
|
||||
VOP_UNLOCK(coveredvp);
|
||||
vdrop(coveredvp);
|
||||
}
|
||||
@@ -2445,6 +2466,8 @@ dounmount(struct mount *mp, uint64_t flags, struct thread *td)
|
||||
coveredvp->v_mountedhere = NULL;
|
||||
vn_seqc_write_end_locked(coveredvp);
|
||||
VI_UNLOCK(coveredvp);
|
||||
if (!coveredrec)
|
||||
VN_LOCK_DREC(coveredvp);
|
||||
VOP_UNLOCK(coveredvp);
|
||||
vdrop(coveredvp);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user