summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2003-10-05 00:02:41 +0000
committerjeff <jeff@FreeBSD.org>2003-10-05 00:02:41 +0000
commit8d72c437638263277c823c617471854787c92fc7 (patch)
tree50ba9fe704255e2ae8384bbc606376ae56c178ca /sys/kern
parent44ee8e221156e7d2f2a088fdea3361cdc9902479 (diff)
downloadFreeBSD-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.c75
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);
}
OpenPOWER on IntegriCloud