summaryrefslogtreecommitdiff
path: root/sys/kern/vfs_subr.c
diff options
context:
space:
mode:
authorIan Dowse <iedowse@FreeBSD.org>2001-05-16 18:04:37 +0000
committerIan Dowse <iedowse@FreeBSD.org>2001-05-16 18:04:37 +0000
commit0864ef1e8a449b1533c7e0ea673e9614aaa9a81f (patch)
treed7aaca11b211abc1efdc147eb5280e6a31ca436e /sys/kern/vfs_subr.c
parent73cf2c3089f11d4b82c44eef06de12f8f86cc47e (diff)
Notes
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r--sys/kern/vfs_subr.c56
1 files changed, 45 insertions, 11 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index cf2ea29349e3..2f4dc8d95326 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -1627,10 +1627,22 @@ vdrop(vp)
/*
* Remove any vnodes in the vnode table belonging to mount point mp.
*
- * If MNT_NOFORCE is specified, there should not be any active ones,
+ * If FORCECLOSE is not specified, there should not be any active ones,
* return error if any are found (nb: this is a user error, not a
- * system error). If MNT_FORCE is specified, detach any active vnodes
+ * system error). If FORCECLOSE is specified, detach any active vnodes
* that are found.
+ *
+ * If WRITECLOSE is set, only flush out regular file vnodes open for
+ * writing.
+ *
+ * SKIPSYSTEM causes any vnodes marked VSYSTEM to be skipped.
+ *
+ * `rootrefs' specifies the base reference count for the root vnode
+ * of this filesystem. The root vnode is considered busy if its
+ * v_usecount exceeds this value. On a successful return, vflush()
+ * will call vrele() on the root vnode exactly rootrefs times.
+ * If the SKIPSYSTEM or WRITECLOSE flags are specified, rootrefs must
+ * be zero.
*/
#ifdef DIAGNOSTIC
static int busyprt = 0; /* print out busy vnodes */
@@ -1638,15 +1650,26 @@ SYSCTL_INT(_debug, OID_AUTO, busyprt, CTLFLAG_RW, &busyprt, 0, "");
#endif
int
-vflush(mp, skipvp, flags)
+vflush(mp, rootrefs, flags)
struct mount *mp;
- struct vnode *skipvp;
+ int rootrefs;
int flags;
{
struct proc *p = curproc; /* XXX */
- struct vnode *vp, *nvp;
- int busy = 0;
+ struct vnode *vp, *nvp, *rootvp = NULL;
+ int busy = 0, error;
+ if (rootrefs > 0) {
+ KASSERT((flags & (SKIPSYSTEM | WRITECLOSE)) == 0,
+ ("vflush: bad args"));
+ /*
+ * Get the filesystem root vnode. We can vput() it
+ * immediately, since with rootrefs > 0, it won't go away.
+ */
+ if ((error = VFS_ROOT(mp, &rootvp)) != 0)
+ return (error);
+ vput(rootvp);
+ }
mtx_lock(&mntvnode_mtx);
loop:
for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
@@ -1657,11 +1680,6 @@ loop:
if (vp->v_mount != mp)
goto loop;
nvp = LIST_NEXT(vp, v_mntvnodes);
- /*
- * Skip over a selected vnode.
- */
- if (vp == skipvp)
- continue;
mtx_lock(&vp->v_interlock);
/*
@@ -1717,8 +1735,24 @@ loop:
busy++;
}
mtx_unlock(&mntvnode_mtx);
+ if (rootrefs > 0 && (flags & FORCECLOSE) == 0) {
+ /*
+ * If just the root vnode is busy, and if its refcount
+ * is equal to `rootrefs', then go ahead and kill it.
+ */
+ mtx_lock(&rootvp->v_interlock);
+ KASSERT(busy > 0, ("vflush: not busy"));
+ KASSERT(rootvp->v_usecount >= rootrefs, ("vflush: rootrefs"));
+ if (busy == 1 && rootvp->v_usecount == rootrefs) {
+ vgonel(rootvp, p);
+ busy = 0;
+ } else
+ mtx_unlock(&rootvp->v_interlock);
+ }
if (busy)
return (EBUSY);
+ for (; rootrefs > 0; rootrefs--)
+ vrele(rootvp);
return (0);
}