diff options
author | kib <kib@FreeBSD.org> | 2008-08-28 09:08:15 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2008-08-28 09:08:15 +0000 |
commit | dd53532f9375b0bc12ccefe8249b0f02d0ea09c4 (patch) | |
tree | 1740ebbfcc389d01aac99fdfef5ed8409f0312c4 /sys/kern/vfs_subr.c | |
parent | 4946f9aaa73e6c3e3942d8676601902b707f2659 (diff) | |
download | FreeBSD-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
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r-- | sys/kern/vfs_subr.c | 25 |
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 |