summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r--sys/kern/vfs_subr.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 7c7b2a5..3bc2341 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -1024,17 +1024,28 @@ int
insmntque1(struct vnode *vp, struct mount *mp,
void (*dtr)(struct vnode *, void *), void *dtr_arg)
{
+ int locked;
KASSERT(vp->v_mount == NULL,
("insmntque: vnode already on per mount vnode list"));
VNASSERT(mp != NULL, vp, ("Don't call insmntque(foo, NULL)"));
+#ifdef DEBUG_VFS_LOCKS
+ if (!VFS_NEEDSGIANT(mp))
+ ASSERT_VOP_ELOCKED(vp,
+ "insmntque: mp-safe fs and non-locked vp");
+#endif
MNT_ILOCK(mp);
if ((mp->mnt_kern_flag & MNTK_NOINSMNTQ) != 0 &&
- mp->mnt_nvnodelistsize == 0) {
- MNT_IUNLOCK(mp);
- if (dtr != NULL)
- dtr(vp, dtr_arg);
- return (EBUSY);
+ ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ mp->mnt_nvnodelistsize == 0)) {
+ locked = VOP_ISLOCKED(vp);
+ if (!locked || (locked == LK_EXCLUSIVE &&
+ (vp->v_vflag & VV_FORCEINSMQ) == 0)) {
+ MNT_IUNLOCK(mp);
+ if (dtr != NULL)
+ dtr(vp, dtr_arg);
+ return (EBUSY);
+ }
}
vp->v_mount = mp;
MNT_REF(mp);
@@ -3283,9 +3294,13 @@ vfs_allocate_syncvnode(struct mount *mp)
return (error);
}
vp->v_type = VNON;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ vp->v_vflag |= VV_FORCEINSMQ;
error = insmntque(vp, mp);
if (error != 0)
panic("vfs_allocate_syncvnode: insmntque failed");
+ vp->v_vflag &= ~VV_FORCEINSMQ;
+ VOP_UNLOCK(vp, 0);
/*
* Place the vnode onto the syncer worklist. We attempt to
* scatter them about on the list so that they will go off
OpenPOWER on IntegriCloud