diff options
author | jeff <jeff@FreeBSD.org> | 2003-12-16 17:05:05 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2003-12-16 17:05:05 +0000 |
commit | aa712bc6e42a435add89c314511c2cba31f0ea8c (patch) | |
tree | 41eccb906bc9cc5892475c97976cf16c3dcfad9c /sys/kern/vfs_subr.c | |
parent | 6bf44828f03e0c4f12bfe3bfbc56f68e90da8737 (diff) | |
download | FreeBSD-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.c | 29 |
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); |