diff options
author | jeff <jeff@FreeBSD.org> | 2003-10-05 00:02:41 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2003-10-05 00:02:41 +0000 |
commit | 8d72c437638263277c823c617471854787c92fc7 (patch) | |
tree | 50ba9fe704255e2ae8384bbc606376ae56c178ca /sys/kern | |
parent | 44ee8e221156e7d2f2a088fdea3361cdc9902479 (diff) | |
download | FreeBSD-src-8d72c437638263277c823c617471854787c92fc7.zip FreeBSD-src-8d72c437638263277c823c617471854787c92fc7.tar.gz |
- Move the xlock 'locking' code into vx_lock() and vx_unlock().
- Create a new function, vgonechrl(), which performs vgone for an in-use
character device. Move the code from vflush() that did this into
vgonechrl().
- Hold the xlock across the entirety of vgonel() and vgonechrl() so that
at no point will an invalid vnode exist on any list without XLOCK set.
- Move the xlock code out of vclean() now that it is in the vgone*()
functions.
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/vfs_subr.c | 75 |
1 files changed, 54 insertions, 21 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index aba67d7..e0c811e 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -86,6 +86,9 @@ static void vlruvp(struct vnode *vp); static int flushbuflist(struct buf *blist, int flags, struct vnode *vp, int slpflag, int slptimeo, int *errorp); static int vcanrecycle(struct vnode *vp, struct mount **vnmpp); +static void vx_lock(struct vnode *vp); +static void vx_unlock(struct vnode *vp); +static void vgonechrl(struct vnode *vp, struct thread *td); /* @@ -2426,14 +2429,10 @@ loop: * all other files, just kill them. */ if (flags & FORCECLOSE) { - if (vp->v_type != VCHR) { + if (vp->v_type != VCHR) vgonel(vp, td); - } else { - vclean(vp, 0, td); - VI_UNLOCK(vp); - vp->v_op = spec_vnodeop_p; - insmntque(vp, (struct mount *) 0); - } + else + vgonechrl(vp, td); mtx_lock(&mntvnode_mtx); continue; } @@ -2488,6 +2487,34 @@ vlruvp(struct vnode *vp) #endif } +static void +vx_lock(struct vnode *vp) +{ + ASSERT_VI_LOCKED(vp, "vx_lock"); + + /* + * Prevent the vnode from being recycled or brought into use while we + * clean it out. + */ + if (vp->v_iflag & VI_XLOCK) + panic("vclean: deadlock"); + vp->v_iflag |= VI_XLOCK; + vp->v_vxproc = curthread; +} + +static void +vx_unlock(struct vnode *vp) +{ + ASSERT_VI_LOCKED(vp, "vx_unlock"); + vp->v_iflag &= ~VI_XLOCK; + vp->v_vxproc = NULL; + if (vp->v_iflag & VI_XWANT) { + vp->v_iflag &= ~VI_XWANT; + wakeup(vp); + } +} + + /* * Disassociate the underlying filesystem from a vnode. */ @@ -2509,14 +2536,6 @@ vclean(vp, flags, td) v_incr_usecount(vp, 1); /* - * Prevent the vnode from being recycled or brought into use while we - * clean it out. - */ - if (vp->v_iflag & VI_XLOCK) - panic("vclean: deadlock"); - vp->v_iflag |= VI_XLOCK; - vp->v_vxproc = curthread; - /* * Even if the count is zero, the VOP_INACTIVE routine may still * have the object locked while it cleans it out. The VOP_LOCK * ensures that the VOP_INACTIVE routine is done with its work. @@ -2609,12 +2628,6 @@ vclean(vp, flags, td) if (vp->v_pollinfo != NULL) vn_pollgone(vp); vp->v_tag = "none"; - vp->v_iflag &= ~VI_XLOCK; - vp->v_vxproc = NULL; - if (vp->v_iflag & VI_XWANT) { - vp->v_iflag &= ~VI_XWANT; - wakeup(vp); - } } /* @@ -2697,6 +2710,24 @@ vgone(vp) } /* + * Disassociate a character device from the its underlying filesystem and + * attach it to spec. This is for use when the chr device is still active + * and the filesystem is going away. + */ +static void +vgonechrl(struct vnode *vp, struct thread *td) +{ + ASSERT_VI_LOCKED(vp, "vgonechrl"); + vx_lock(vp); + vclean(vp, 0, td); + VI_UNLOCK(vp); + insmntque(vp, (struct mount *) 0); + VI_LOCK(vp); + vp->v_op = spec_vnodeop_p; + vx_unlock(vp); + VI_UNLOCK(vp); +} +/* * vgone, with the vp interlock held. */ void @@ -2714,6 +2745,7 @@ vgonel(vp, td) msleep(vp, VI_MTX(vp), PINOD | PDROP, "vgone", 0); return; } + vx_lock(vp); /* * Clean out the filesystem specific data. @@ -2762,6 +2794,7 @@ vgonel(vp, td) } vp->v_type = VBAD; + vx_unlock(vp); VI_UNLOCK(vp); } |