summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-08-28 09:08:15 +0000
committerkib <kib@FreeBSD.org>2008-08-28 09:08:15 +0000
commitdd53532f9375b0bc12ccefe8249b0f02d0ea09c4 (patch)
tree1740ebbfcc389d01aac99fdfef5ed8409f0312c4
parent4946f9aaa73e6c3e3942d8676601902b707f2659 (diff)
downloadFreeBSD-src-dd53532f9375b0bc12ccefe8249b0f02d0ea09c4.zip
FreeBSD-src-dd53532f9375b0bc12ccefe8249b0f02d0ea09c4.tar.gz
Introduce the VV_FORCEINSMQ vnode flag. It instructs the insmnque() function
to ignore the unmounting and forces insertion of the vnode into the mount vnode list. Change insmntque() to fail when forced unmount is in progress and VV_FORCEINSMQ is not specified. Add an assertion to the insmntque(), requiring the vnode to be exclusively locked for mp-safe filesystems. Use the VV_FORCEINSMQ for the creation of the syncvnode. Tested by: pho Reviewed by: tegge MFC after: 1 month
-rw-r--r--sys/kern/vfs_subr.c25
-rw-r--r--sys/sys/vnode.h1
2 files changed, 21 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
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index b55114c..03a0a2e99 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -251,6 +251,7 @@ struct xvnode {
#define VV_NOKNOTE 0x0200 /* don't activate knotes on this vnode */
#define VV_DELETED 0x0400 /* should be removed */
#define VV_MD 0x0800 /* vnode backs the md device */
+#define VV_FORCEINSMQ 0x1000 /* force the insmntque to succeed */
/*
* Vnode attributes. A field value of VNOVAL represents a field whose value
OpenPOWER on IntegriCloud