summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2003-12-16 17:05:05 +0000
committerjeff <jeff@FreeBSD.org>2003-12-16 17:05:05 +0000
commitaa712bc6e42a435add89c314511c2cba31f0ea8c (patch)
tree41eccb906bc9cc5892475c97976cf16c3dcfad9c
parent6bf44828f03e0c4f12bfe3bfbc56f68e90da8737 (diff)
downloadFreeBSD-src-aa712bc6e42a435add89c314511c2cba31f0ea8c.zip
FreeBSD-src-aa712bc6e42a435add89c314511c2cba31f0ea8c.tar.gz
- When doing a forced unmount, VFS attempts to keep VCHR vnodes valid by
reassigning their v_ops field to specfs, detaching from the mountpoint, etc. However, this is not sufficient. If we vclean() the vnode the pages owned by the vnode are lost, potentially while buffers reference them. Implement parts of vclean() seperately in vgonechrl() so that the pages and bufs associated with a device vnode are not destroyed while in use.
-rw-r--r--sys/kern/vfs_subr.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 3c612ce..901a59c 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -2726,7 +2726,34 @@ vgonechrl(struct vnode *vp, struct thread *td)
{
ASSERT_VI_LOCKED(vp, "vgonechrl");
vx_lock(vp);
- vclean(vp, 0, td);
+ /*
+ * This is a custom version of vclean() which does not tearm down
+ * the bufs or vm objects held by this vnode. This allows filesystems
+ * to continue using devices which were discovered via another
+ * filesystem that has been unmounted.
+ */
+ if (vp->v_usecount != 0) {
+ v_incr_usecount(vp, 1);
+ /*
+ * Ensure that no other activity can occur while the
+ * underlying object is being cleaned out.
+ */
+ VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, td);
+ /*
+ * Any other processes trying to obtain this lock must first
+ * wait for VXLOCK to clear, then call the new lock operation.
+ */
+ VOP_UNLOCK(vp, 0, td);
+ vp->v_vnlock = &vp->v_lock;
+ vp->v_tag = "orphanchr";
+ vp->v_op = spec_vnodeop_p;
+ if (vp->v_mount != NULL)
+ insmntque(vp, (struct mount *)0);
+ cache_purge(vp);
+ vrele(vp);
+ VI_LOCK(vp);
+ } else
+ vclean(vp, 0, td);
vp->v_op = spec_vnodeop_p;
vx_unlock(vp);
VI_UNLOCK(vp);
OpenPOWER on IntegriCloud