summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_subr.c
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 /sys/kern/vfs_subr.c
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.
Diffstat (limited to 'sys/kern/vfs_subr.c')
-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