summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/coda/coda_vfsops.c2
-rw-r--r--sys/fs/cd9660/cd9660_vfsops.c2
-rw-r--r--sys/fs/coda/coda_vfsops.c2
-rw-r--r--sys/fs/devfs/devfs_vfsops.c14
-rw-r--r--sys/fs/fdescfs/fdesc_vfsops.c16
-rw-r--r--sys/fs/hpfs/hpfs_vfsops.c2
-rw-r--r--sys/fs/msdosfs/msdosfs_vfsops.c4
-rw-r--r--sys/fs/ntfs/ntfs_vfsops.c6
-rw-r--r--sys/fs/nullfs/null_vfsops.c25
-rw-r--r--sys/fs/nwfs/nwfs_vfsops.c25
-rw-r--r--sys/fs/portalfs/portal_vfsops.c14
-rw-r--r--sys/fs/smbfs/smbfs_vfsops.c17
-rw-r--r--sys/fs/umapfs/umap_vfsops.c17
-rw-r--r--sys/fs/unionfs/union_vfsops.c30
-rw-r--r--sys/gnu/ext2fs/ext2_vfsops.c4
-rw-r--r--sys/gnu/fs/ext2fs/ext2_vfsops.c4
-rw-r--r--sys/isofs/cd9660/cd9660_vfsops.c2
-rw-r--r--sys/kern/vfs_subr.c56
-rw-r--r--sys/miscfs/fdesc/fdesc_vfsops.c16
-rw-r--r--sys/miscfs/nullfs/null_vfsops.c25
-rw-r--r--sys/miscfs/portal/portal_vfsops.c14
-rw-r--r--sys/miscfs/umapfs/umap_vfsops.c17
-rw-r--r--sys/miscfs/union/union_vfsops.c30
-rw-r--r--sys/msdosfs/msdosfs_vfsops.c4
-rw-r--r--sys/nfs/nfs_vfsops.c32
-rw-r--r--sys/nfsclient/nfs_vfsops.c32
-rw-r--r--sys/ntfs/ntfs_vfsops.c6
-rw-r--r--sys/nwfs/nwfs_vfsops.c25
-rw-r--r--sys/sys/vnode.h2
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c6
30 files changed, 118 insertions, 333 deletions
diff --git a/sys/coda/coda_vfsops.c b/sys/coda/coda_vfsops.c
index a640cf4..8bcd36f 100644
--- a/sys/coda/coda_vfsops.c
+++ b/sys/coda/coda_vfsops.c
@@ -259,7 +259,7 @@ coda_unmount(vfsp, mntflags, p)
active = coda_kill(vfsp, NOT_DOWNCALL);
mi->mi_rootvp->v_flag &= ~VROOT;
- error = vflush(mi->mi_vfsp, NULLVP, FORCECLOSE);
+ error = vflush(mi->mi_vfsp, 0, FORCECLOSE);
printf("coda_unmount: active = %d, vflush active %d\n", active, error);
error = 0;
/* I'm going to take this out to allow lookups to go through. I'm
diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c
index a569c53..0b42933 100644
--- a/sys/fs/cd9660/cd9660_vfsops.c
+++ b/sys/fs/cd9660/cd9660_vfsops.c
@@ -537,7 +537,7 @@ cd9660_unmount(mp, mntflags, p)
if (mntinvalbuf(mp))
return EBUSY;
#endif
- if ((error = vflush(mp, NULLVP, flags)))
+ if ((error = vflush(mp, 0, flags)))
return (error);
isomp = VFSTOISOFS(mp);
diff --git a/sys/fs/coda/coda_vfsops.c b/sys/fs/coda/coda_vfsops.c
index a640cf4..8bcd36f 100644
--- a/sys/fs/coda/coda_vfsops.c
+++ b/sys/fs/coda/coda_vfsops.c
@@ -259,7 +259,7 @@ coda_unmount(vfsp, mntflags, p)
active = coda_kill(vfsp, NOT_DOWNCALL);
mi->mi_rootvp->v_flag &= ~VROOT;
- error = vflush(mi->mi_vfsp, NULLVP, FORCECLOSE);
+ error = vflush(mi->mi_vfsp, 0, FORCECLOSE);
printf("coda_unmount: active = %d, vflush active %d\n", active, error);
error = 0;
/* I'm going to take this out to allow lookups to go through. I'm
diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c
index 6ab9cf1..2d1aa90 100644
--- a/sys/fs/devfs/devfs_vfsops.c
+++ b/sys/fs/devfs/devfs_vfsops.c
@@ -118,26 +118,16 @@ devfs_unmount(mp, mntflags, p)
{
int error;
int flags = 0;
- struct vnode *rootvp;
struct devfs_mount *fmp;
- error = devfs_root(mp, &rootvp);
- if (error)
- return (error);
fmp = VFSTODEVFS(mp);
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- if (rootvp->v_usecount > 2) {
- vrele(rootvp);
- return (EBUSY);
- }
- error = vflush(mp, rootvp, flags);
+ /* There is 1 extra root vnode reference from devfs_mount(). */
+ error = vflush(mp, 1, flags);
if (error)
return (error);
devfs_purge(fmp->dm_rootdir);
- vput(rootvp);
- vrele(rootvp);
- vgone(rootvp);
mp->mnt_data = 0;
lockdestroy(&fmp->dm_lock);
free(fmp, M_DEVFS);
diff --git a/sys/fs/fdescfs/fdesc_vfsops.c b/sys/fs/fdescfs/fdesc_vfsops.c
index 900e1de..a758bb8 100644
--- a/sys/fs/fdescfs/fdesc_vfsops.c
+++ b/sys/fs/fdescfs/fdesc_vfsops.c
@@ -114,7 +114,6 @@ fdesc_unmount(mp, mntflags, p)
{
int error;
int flags = 0;
- struct vnode *rootvp = VFSTOFDESC(mp)->f_root;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
@@ -123,21 +122,14 @@ fdesc_unmount(mp, mntflags, p)
* Clear out buffer cache. I don't think we
* ever get anything cached at this level at the
* moment, but who knows...
+ *
+ * There is 1 extra root vnode reference corresponding
+ * to f_root.
*/
- if (rootvp->v_usecount > 1)
- return (EBUSY);
- if ((error = vflush(mp, rootvp, flags)) != 0)
+ if ((error = vflush(mp, 1, flags)) != 0)
return (error);
/*
- * Release reference on underlying root vnode
- */
- vrele(rootvp);
- /*
- * And blow it away for future re-use
- */
- vgone(rootvp);
- /*
* Finally, throw away the fdescmount structure
*/
free(mp->mnt_data, M_FDESCMNT); /* XXX */
diff --git a/sys/fs/hpfs/hpfs_vfsops.c b/sys/fs/hpfs/hpfs_vfsops.c
index ec68f86..46e197d 100644
--- a/sys/fs/hpfs/hpfs_vfsops.c
+++ b/sys/fs/hpfs/hpfs_vfsops.c
@@ -477,7 +477,7 @@ hpfs_unmount(
dprintf(("hpfs_unmount: vflushing...\n"));
- error = vflush(mp,NULLVP,flags);
+ error = vflush(mp, 0, flags);
if (error) {
printf("hpfs_unmount: vflush failed: %d\n",error);
return (error);
diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index 1d9b131..abaeb7f 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -251,7 +251,7 @@ msdosfs_mount(mp, path, data, ndp, p)
flags = WRITECLOSE;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
- error = vflush(mp, NULLVP, flags);
+ error = vflush(mp, 0, flags);
}
if (!error && (mp->mnt_flag & MNT_RELOAD))
/* not yet implemented */
@@ -749,7 +749,7 @@ msdosfs_unmount(mp, mntflags, p)
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- error = vflush(mp, NULLVP, flags);
+ error = vflush(mp, 0, flags);
if (error)
return error;
pmp = VFSTOMSDOSFS(mp);
diff --git a/sys/fs/ntfs/ntfs_vfsops.c b/sys/fs/ntfs/ntfs_vfsops.c
index b6fde8e..526decd 100644
--- a/sys/fs/ntfs/ntfs_vfsops.c
+++ b/sys/fs/ntfs/ntfs_vfsops.c
@@ -603,7 +603,7 @@ out1:
for(i=0;i<NTFS_SYSNODESNUM;i++)
if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
- if (vflush(mp,NULLVP,0))
+ if (vflush(mp, 0, 0))
dprintf(("ntfs_mountfs: vflush failed\n"));
out:
@@ -651,7 +651,7 @@ ntfs_unmount(
flags |= FORCECLOSE;
dprintf(("ntfs_unmount: vflushing...\n"));
- error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
+ error = vflush(mp, 0, flags | SKIPSYSTEM);
if (error) {
printf("ntfs_unmount: vflush failed: %d\n",error);
return (error);
@@ -667,7 +667,7 @@ ntfs_unmount(
if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
/* vflush system vnodes */
- error = vflush(mp,NULLVP,flags);
+ error = vflush(mp, 0, flags);
if (error)
printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c
index dfaefe3..8573398 100644
--- a/sys/fs/nullfs/null_vfsops.c
+++ b/sys/fs/nullfs/null_vfsops.c
@@ -229,7 +229,6 @@ nullfs_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- struct vnode *vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
void *mntdata;
int error;
int flags = 0;
@@ -239,31 +238,11 @@ nullfs_unmount(mp, mntflags, p)
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- error = VFS_ROOT(mp, &vp);
- if (error)
- return (error);
- if (vp->v_usecount > 2) {
- NULLFSDEBUG("nullfs_unmount: rootvp is busy(%d)\n",
- vp->v_usecount);
- vput(vp);
- return (EBUSY);
- }
- error = vflush(mp, vp, flags);
+ /* There is 1 extra root vnode reference (nullm_rootvp). */
+ error = vflush(mp, 1, flags);
if (error)
return (error);
-#ifdef NULLFS_DEBUG
- vprint("alias root of lower", vp);
-#endif
- vput(vp);
- /*
- * Release reference on underlying root vnode
- */
- vrele(vp);
- /*
- * And blow it away for future re-use
- */
- vgone(vp);
/*
* Finally, throw away the null_mount structure
*/
diff --git a/sys/fs/nwfs/nwfs_vfsops.c b/sys/fs/nwfs/nwfs_vfsops.c
index c9084ef..c978722 100644
--- a/sys/fs/nwfs/nwfs_vfsops.c
+++ b/sys/fs/nwfs/nwfs_vfsops.c
@@ -237,35 +237,16 @@ nwfs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
struct nwmount *nmp = VFSTONWFS(mp);
struct ncp_conn *conn;
- struct vnode *vp;
int error, flags;
NCPVODEBUG("nwfs_unmount: flags=%04x\n",mntflags);
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- error = VFS_ROOT(mp,&vp);
- if (error) return (error);
- if (vp->v_usecount > 2) {
- printf("nwfs_unmount: usecnt=%d\n",vp->v_usecount);
- vput(vp);
- return (EBUSY);
- }
- error = vflush(mp, vp, flags);
- if (error) {
- vput(vp);
+ /* There is 1 extra root vnode reference from nwfs_mount(). */
+ error = vflush(mp, 1, flags);
+ if (error)
return (error);
- }
- /*
- * There are two reference counts and one lock to get rid of here.
- */
- NCPVODEBUG("v_use: %d\n",vp->v_usecount);
- vput(vp);
- NCPVODEBUG("v_use after vput: %d\n",vp->v_usecount);
- vrele(vp);
- NCPVODEBUG("v_use after vrele: %d\n",vp->v_usecount);
- vgone(vp);
- NCPVODEBUG("v_gone finished !!!!\n");
conn = NWFSTOCONN(nmp);
ncp_conn_puthandle(nmp->connh,NULL,0);
if (ncp_conn_lock(conn,p,p->p_ucred,NCPM_WRITE | NCPM_EXECUTE) == 0) {
diff --git a/sys/fs/portalfs/portal_vfsops.c b/sys/fs/portalfs/portal_vfsops.c
index 5146456..423cd38 100644
--- a/sys/fs/portalfs/portal_vfsops.c
+++ b/sys/fs/portalfs/portal_vfsops.c
@@ -155,7 +155,6 @@ portal_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- struct vnode *rootvp = VFSTOPORTAL(mp)->pm_root;
int error, flags = 0;
@@ -172,21 +171,12 @@ portal_unmount(mp, mntflags, p)
if (mntinvalbuf(mp, 1))
return (EBUSY);
#endif
- if (rootvp->v_usecount > 1)
- return (EBUSY);
- error = vflush(mp, rootvp, flags);
+ /* There is 1 extra root vnode reference (pm_root). */
+ error = vflush(mp, 1, flags);
if (error)
return (error);
/*
- * Release reference on underlying root vnode
- */
- vrele(rootvp);
- /*
- * And blow it away for future re-use
- */
- vgone(rootvp);
- /*
* Shutdown the socket. This will cause the select in the
* daemon to wake up, and then the accept will get ECONNABORTED
* which it interprets as a request to go and bury itself.
diff --git a/sys/fs/smbfs/smbfs_vfsops.c b/sys/fs/smbfs/smbfs_vfsops.c
index c0f9ee1..b5196c0 100644
--- a/sys/fs/smbfs/smbfs_vfsops.c
+++ b/sys/fs/smbfs/smbfs_vfsops.c
@@ -254,7 +254,6 @@ static int
smbfs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
struct smbmount *smp = VFSTOSMBFS(mp);
- struct vnode *vp;
struct smb_cred scred;
int error, flags;
@@ -262,22 +261,10 @@ smbfs_unmount(struct mount *mp, int mntflags, struct proc *p)
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- error = VFS_ROOT(mp, &vp);
+ /* There is 1 extra root vnode reference from smbfs_mount(). */
+ error = vflush(mp, 1, flags);
if (error)
- return (error);
- if (vp->v_usecount > 2) {
- printf("smbfs_unmount: usecnt=%d\n", vp->v_usecount);
- vput(vp);
- return EBUSY;
- }
- error = vflush(mp, vp, flags);
- if (error) {
- vput(vp);
return error;
- }
- vput(vp);
- vrele(vp);
- vgone(vp);
smb_makescred(&scred, p, p->p_ucred);
smb_share_put(smp->sm_share, &scred);
mp->mnt_data = (qaddr_t)0;
diff --git a/sys/fs/umapfs/umap_vfsops.c b/sys/fs/umapfs/umap_vfsops.c
index e86467d..280ded9 100644
--- a/sys/fs/umapfs/umap_vfsops.c
+++ b/sys/fs/umapfs/umap_vfsops.c
@@ -260,7 +260,6 @@ umapfs_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- struct vnode *umapm_rootvp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
int error;
int flags = 0;
@@ -281,23 +280,11 @@ umapfs_unmount(mp, mntflags, p)
if (mntinvalbuf(mp, 1))
return (EBUSY);
#endif
- if (umapm_rootvp->v_usecount > 1)
- return (EBUSY);
- error = vflush(mp, umapm_rootvp, flags);
+ /* There is 1 extra root vnode reference (umapm_rootvp). */
+ error = vflush(mp, 1, flags);
if (error)
return (error);
-#ifdef DEBUG
- vprint("alias root of lower", umapm_rootvp);
-#endif
- /*
- * Release reference on underlying root vnode
- */
- vrele(umapm_rootvp);
- /*
- * And blow it away for future re-use
- */
- vgone(umapm_rootvp);
/*
* Finally, throw away the umap_mount structure
*/
diff --git a/sys/fs/unionfs/union_vfsops.c b/sys/fs/unionfs/union_vfsops.c
index 5018f09..d38f31e 100644
--- a/sys/fs/unionfs/union_vfsops.c
+++ b/sys/fs/unionfs/union_vfsops.c
@@ -307,7 +307,6 @@ union_unmount(mp, mntflags, p)
struct proc *p;
{
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
- struct vnode *um_rootvp;
int error;
int freeing;
int flags = 0;
@@ -317,9 +316,6 @@ union_unmount(mp, mntflags, p)
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- if ((error = union_root(mp, &um_rootvp)) != 0)
- return (error);
-
/*
* Keep flushing vnodes from the mount list.
* This is needed because of the un_pvp held
@@ -329,14 +325,13 @@ union_unmount(mp, mntflags, p)
* (d) times, where (d) is the maximum tree depth
* in the filesystem.
*/
- for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) {
+ for (freeing = 0; (error = vflush(mp, 0, flags)) != 0;) {
struct vnode *vp;
int n;
/* count #vnodes held on mount list */
- for (n = 0, vp = LIST_FIRST(&mp->mnt_vnodelist);
- vp != NULLVP;
- vp = LIST_NEXT(vp, v_mntvnodes))
+ n = 0;
+ LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes)
n++;
/* if this is unchanged then stop */
@@ -347,15 +342,10 @@ union_unmount(mp, mntflags, p)
freeing = n;
}
- /* At this point the root vnode should have a single reference */
- if (um_rootvp->v_usecount > 1) {
- vput(um_rootvp);
- return (EBUSY);
- }
+ /* If the most recent vflush failed, the filesystem is still busy. */
+ if (error)
+ return (error);
-#ifdef DEBUG
- vprint("union root", um_rootvp);
-#endif
/*
* Discard references to upper and lower target vnodes.
*/
@@ -364,14 +354,6 @@ union_unmount(mp, mntflags, p)
vrele(um->um_uppervp);
crfree(um->um_cred);
/*
- * Release reference on underlying root vnode
- */
- vput(um_rootvp);
- /*
- * And blow it away for future re-use
- */
- vgone(um_rootvp);
- /*
* Finally, throw away the union_mount structure
*/
free(mp->mnt_data, M_UNIONFSMNT); /* XXX */
diff --git a/sys/gnu/ext2fs/ext2_vfsops.c b/sys/gnu/ext2fs/ext2_vfsops.c
index 5f7118e..05bb202 100644
--- a/sys/gnu/ext2fs/ext2_vfsops.c
+++ b/sys/gnu/ext2fs/ext2_vfsops.c
@@ -823,7 +823,7 @@ ext2_flushfiles(mp, flags, p)
ump = VFSTOUFS(mp);
#if QUOTA
if (mp->mnt_flag & MNT_QUOTA) {
- if ((error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) != 0)
+ if ((error = vflush(mp, 0, SKIPSYSTEM|flags)) != 0)
return (error);
for (i = 0; i < MAXQUOTAS; i++) {
if (ump->um_quotas[i] == NULLVP)
@@ -836,7 +836,7 @@ ext2_flushfiles(mp, flags, p)
*/
}
#endif
- error = vflush(mp, NULLVP, flags);
+ error = vflush(mp, 0, flags);
return (error);
}
diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c
index 5f7118e..05bb202 100644
--- a/sys/gnu/fs/ext2fs/ext2_vfsops.c
+++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c
@@ -823,7 +823,7 @@ ext2_flushfiles(mp, flags, p)
ump = VFSTOUFS(mp);
#if QUOTA
if (mp->mnt_flag & MNT_QUOTA) {
- if ((error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) != 0)
+ if ((error = vflush(mp, 0, SKIPSYSTEM|flags)) != 0)
return (error);
for (i = 0; i < MAXQUOTAS; i++) {
if (ump->um_quotas[i] == NULLVP)
@@ -836,7 +836,7 @@ ext2_flushfiles(mp, flags, p)
*/
}
#endif
- error = vflush(mp, NULLVP, flags);
+ error = vflush(mp, 0, flags);
return (error);
}
diff --git a/sys/isofs/cd9660/cd9660_vfsops.c b/sys/isofs/cd9660/cd9660_vfsops.c
index a569c53..0b42933 100644
--- a/sys/isofs/cd9660/cd9660_vfsops.c
+++ b/sys/isofs/cd9660/cd9660_vfsops.c
@@ -537,7 +537,7 @@ cd9660_unmount(mp, mntflags, p)
if (mntinvalbuf(mp))
return EBUSY;
#endif
- if ((error = vflush(mp, NULLVP, flags)))
+ if ((error = vflush(mp, 0, flags)))
return (error);
isomp = VFSTOISOFS(mp);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index cf2ea29..2f4dc8d 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);
}
diff --git a/sys/miscfs/fdesc/fdesc_vfsops.c b/sys/miscfs/fdesc/fdesc_vfsops.c
index 900e1de..a758bb8 100644
--- a/sys/miscfs/fdesc/fdesc_vfsops.c
+++ b/sys/miscfs/fdesc/fdesc_vfsops.c
@@ -114,7 +114,6 @@ fdesc_unmount(mp, mntflags, p)
{
int error;
int flags = 0;
- struct vnode *rootvp = VFSTOFDESC(mp)->f_root;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
@@ -123,21 +122,14 @@ fdesc_unmount(mp, mntflags, p)
* Clear out buffer cache. I don't think we
* ever get anything cached at this level at the
* moment, but who knows...
+ *
+ * There is 1 extra root vnode reference corresponding
+ * to f_root.
*/
- if (rootvp->v_usecount > 1)
- return (EBUSY);
- if ((error = vflush(mp, rootvp, flags)) != 0)
+ if ((error = vflush(mp, 1, flags)) != 0)
return (error);
/*
- * Release reference on underlying root vnode
- */
- vrele(rootvp);
- /*
- * And blow it away for future re-use
- */
- vgone(rootvp);
- /*
* Finally, throw away the fdescmount structure
*/
free(mp->mnt_data, M_FDESCMNT); /* XXX */
diff --git a/sys/miscfs/nullfs/null_vfsops.c b/sys/miscfs/nullfs/null_vfsops.c
index dfaefe3..8573398 100644
--- a/sys/miscfs/nullfs/null_vfsops.c
+++ b/sys/miscfs/nullfs/null_vfsops.c
@@ -229,7 +229,6 @@ nullfs_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- struct vnode *vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
void *mntdata;
int error;
int flags = 0;
@@ -239,31 +238,11 @@ nullfs_unmount(mp, mntflags, p)
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- error = VFS_ROOT(mp, &vp);
- if (error)
- return (error);
- if (vp->v_usecount > 2) {
- NULLFSDEBUG("nullfs_unmount: rootvp is busy(%d)\n",
- vp->v_usecount);
- vput(vp);
- return (EBUSY);
- }
- error = vflush(mp, vp, flags);
+ /* There is 1 extra root vnode reference (nullm_rootvp). */
+ error = vflush(mp, 1, flags);
if (error)
return (error);
-#ifdef NULLFS_DEBUG
- vprint("alias root of lower", vp);
-#endif
- vput(vp);
- /*
- * Release reference on underlying root vnode
- */
- vrele(vp);
- /*
- * And blow it away for future re-use
- */
- vgone(vp);
/*
* Finally, throw away the null_mount structure
*/
diff --git a/sys/miscfs/portal/portal_vfsops.c b/sys/miscfs/portal/portal_vfsops.c
index 5146456..423cd38 100644
--- a/sys/miscfs/portal/portal_vfsops.c
+++ b/sys/miscfs/portal/portal_vfsops.c
@@ -155,7 +155,6 @@ portal_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- struct vnode *rootvp = VFSTOPORTAL(mp)->pm_root;
int error, flags = 0;
@@ -172,21 +171,12 @@ portal_unmount(mp, mntflags, p)
if (mntinvalbuf(mp, 1))
return (EBUSY);
#endif
- if (rootvp->v_usecount > 1)
- return (EBUSY);
- error = vflush(mp, rootvp, flags);
+ /* There is 1 extra root vnode reference (pm_root). */
+ error = vflush(mp, 1, flags);
if (error)
return (error);
/*
- * Release reference on underlying root vnode
- */
- vrele(rootvp);
- /*
- * And blow it away for future re-use
- */
- vgone(rootvp);
- /*
* Shutdown the socket. This will cause the select in the
* daemon to wake up, and then the accept will get ECONNABORTED
* which it interprets as a request to go and bury itself.
diff --git a/sys/miscfs/umapfs/umap_vfsops.c b/sys/miscfs/umapfs/umap_vfsops.c
index e86467d..280ded9 100644
--- a/sys/miscfs/umapfs/umap_vfsops.c
+++ b/sys/miscfs/umapfs/umap_vfsops.c
@@ -260,7 +260,6 @@ umapfs_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- struct vnode *umapm_rootvp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
int error;
int flags = 0;
@@ -281,23 +280,11 @@ umapfs_unmount(mp, mntflags, p)
if (mntinvalbuf(mp, 1))
return (EBUSY);
#endif
- if (umapm_rootvp->v_usecount > 1)
- return (EBUSY);
- error = vflush(mp, umapm_rootvp, flags);
+ /* There is 1 extra root vnode reference (umapm_rootvp). */
+ error = vflush(mp, 1, flags);
if (error)
return (error);
-#ifdef DEBUG
- vprint("alias root of lower", umapm_rootvp);
-#endif
- /*
- * Release reference on underlying root vnode
- */
- vrele(umapm_rootvp);
- /*
- * And blow it away for future re-use
- */
- vgone(umapm_rootvp);
/*
* Finally, throw away the umap_mount structure
*/
diff --git a/sys/miscfs/union/union_vfsops.c b/sys/miscfs/union/union_vfsops.c
index 5018f09..d38f31e 100644
--- a/sys/miscfs/union/union_vfsops.c
+++ b/sys/miscfs/union/union_vfsops.c
@@ -307,7 +307,6 @@ union_unmount(mp, mntflags, p)
struct proc *p;
{
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
- struct vnode *um_rootvp;
int error;
int freeing;
int flags = 0;
@@ -317,9 +316,6 @@ union_unmount(mp, mntflags, p)
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- if ((error = union_root(mp, &um_rootvp)) != 0)
- return (error);
-
/*
* Keep flushing vnodes from the mount list.
* This is needed because of the un_pvp held
@@ -329,14 +325,13 @@ union_unmount(mp, mntflags, p)
* (d) times, where (d) is the maximum tree depth
* in the filesystem.
*/
- for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) {
+ for (freeing = 0; (error = vflush(mp, 0, flags)) != 0;) {
struct vnode *vp;
int n;
/* count #vnodes held on mount list */
- for (n = 0, vp = LIST_FIRST(&mp->mnt_vnodelist);
- vp != NULLVP;
- vp = LIST_NEXT(vp, v_mntvnodes))
+ n = 0;
+ LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes)
n++;
/* if this is unchanged then stop */
@@ -347,15 +342,10 @@ union_unmount(mp, mntflags, p)
freeing = n;
}
- /* At this point the root vnode should have a single reference */
- if (um_rootvp->v_usecount > 1) {
- vput(um_rootvp);
- return (EBUSY);
- }
+ /* If the most recent vflush failed, the filesystem is still busy. */
+ if (error)
+ return (error);
-#ifdef DEBUG
- vprint("union root", um_rootvp);
-#endif
/*
* Discard references to upper and lower target vnodes.
*/
@@ -364,14 +354,6 @@ union_unmount(mp, mntflags, p)
vrele(um->um_uppervp);
crfree(um->um_cred);
/*
- * Release reference on underlying root vnode
- */
- vput(um_rootvp);
- /*
- * And blow it away for future re-use
- */
- vgone(um_rootvp);
- /*
* Finally, throw away the union_mount structure
*/
free(mp->mnt_data, M_UNIONFSMNT); /* XXX */
diff --git a/sys/msdosfs/msdosfs_vfsops.c b/sys/msdosfs/msdosfs_vfsops.c
index 1d9b131..abaeb7f 100644
--- a/sys/msdosfs/msdosfs_vfsops.c
+++ b/sys/msdosfs/msdosfs_vfsops.c
@@ -251,7 +251,7 @@ msdosfs_mount(mp, path, data, ndp, p)
flags = WRITECLOSE;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
- error = vflush(mp, NULLVP, flags);
+ error = vflush(mp, 0, flags);
}
if (!error && (mp->mnt_flag & MNT_RELOAD))
/* not yet implemented */
@@ -749,7 +749,7 @@ msdosfs_unmount(mp, mntflags, p)
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- error = vflush(mp, NULLVP, flags);
+ error = vflush(mp, 0, flags);
if (error)
return error;
pmp = VFSTOMSDOSFS(mp);
diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c
index d5e8972..3c76ed5 100644
--- a/sys/nfs/nfs_vfsops.c
+++ b/sys/nfs/nfs_vfsops.c
@@ -953,8 +953,6 @@ nfs_unmount(mp, mntflags, p)
struct proc *p;
{
register struct nfsmount *nmp;
- struct nfsnode *np;
- struct vnode *vp;
int error, flags = 0;
if (mntflags & MNT_FORCE)
@@ -962,36 +960,20 @@ nfs_unmount(mp, mntflags, p)
nmp = VFSTONFS(mp);
/*
* Goes something like this..
- * - Check for activity on the root vnode (other than ourselves).
- * - Call vflush() to clear out vnodes for this file system,
- * except for the root vnode.
- * - Decrement reference on the vnode representing remote root.
+ * - Call vflush() to clear out vnodes for this file system
* - Close the socket
* - Free up the data structures
*/
/*
- * We need to decrement the ref. count on the nfsnode representing
- * the remote root. See comment in mountnfs(). The VFS unmount()
- * has done vput on this vnode, otherwise we would get deadlock!
- */
- error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
- if (error)
- return(error);
- vp = NFSTOV(np);
- if (vp->v_usecount > 2) {
- vput(vp);
- return (EBUSY);
- }
-
- /*
* Must handshake with nqnfs_clientd() if it is active.
*/
nmp->nm_state |= NFSSTA_DISMINPROG;
while (nmp->nm_inprog != NULLVP)
(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
- error = vflush(mp, vp, flags);
+
+ /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
+ error = vflush(mp, 1, flags);
if (error) {
- vput(vp);
nmp->nm_state &= ~NFSSTA_DISMINPROG;
return (error);
}
@@ -1003,12 +985,6 @@ nfs_unmount(mp, mntflags, p)
if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
nmp->nm_state |= NFSSTA_DISMNT;
- /*
- * There are two reference counts and one lock to get rid of here.
- */
- vput(vp);
- vrele(vp);
- vgone(vp);
nfs_disconnect(nmp);
FREE(nmp->nm_nam, M_SONAME);
diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c
index d5e8972..3c76ed5 100644
--- a/sys/nfsclient/nfs_vfsops.c
+++ b/sys/nfsclient/nfs_vfsops.c
@@ -953,8 +953,6 @@ nfs_unmount(mp, mntflags, p)
struct proc *p;
{
register struct nfsmount *nmp;
- struct nfsnode *np;
- struct vnode *vp;
int error, flags = 0;
if (mntflags & MNT_FORCE)
@@ -962,36 +960,20 @@ nfs_unmount(mp, mntflags, p)
nmp = VFSTONFS(mp);
/*
* Goes something like this..
- * - Check for activity on the root vnode (other than ourselves).
- * - Call vflush() to clear out vnodes for this file system,
- * except for the root vnode.
- * - Decrement reference on the vnode representing remote root.
+ * - Call vflush() to clear out vnodes for this file system
* - Close the socket
* - Free up the data structures
*/
/*
- * We need to decrement the ref. count on the nfsnode representing
- * the remote root. See comment in mountnfs(). The VFS unmount()
- * has done vput on this vnode, otherwise we would get deadlock!
- */
- error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
- if (error)
- return(error);
- vp = NFSTOV(np);
- if (vp->v_usecount > 2) {
- vput(vp);
- return (EBUSY);
- }
-
- /*
* Must handshake with nqnfs_clientd() if it is active.
*/
nmp->nm_state |= NFSSTA_DISMINPROG;
while (nmp->nm_inprog != NULLVP)
(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
- error = vflush(mp, vp, flags);
+
+ /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
+ error = vflush(mp, 1, flags);
if (error) {
- vput(vp);
nmp->nm_state &= ~NFSSTA_DISMINPROG;
return (error);
}
@@ -1003,12 +985,6 @@ nfs_unmount(mp, mntflags, p)
if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
nmp->nm_state |= NFSSTA_DISMNT;
- /*
- * There are two reference counts and one lock to get rid of here.
- */
- vput(vp);
- vrele(vp);
- vgone(vp);
nfs_disconnect(nmp);
FREE(nmp->nm_nam, M_SONAME);
diff --git a/sys/ntfs/ntfs_vfsops.c b/sys/ntfs/ntfs_vfsops.c
index b6fde8e..526decd 100644
--- a/sys/ntfs/ntfs_vfsops.c
+++ b/sys/ntfs/ntfs_vfsops.c
@@ -603,7 +603,7 @@ out1:
for(i=0;i<NTFS_SYSNODESNUM;i++)
if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
- if (vflush(mp,NULLVP,0))
+ if (vflush(mp, 0, 0))
dprintf(("ntfs_mountfs: vflush failed\n"));
out:
@@ -651,7 +651,7 @@ ntfs_unmount(
flags |= FORCECLOSE;
dprintf(("ntfs_unmount: vflushing...\n"));
- error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
+ error = vflush(mp, 0, flags | SKIPSYSTEM);
if (error) {
printf("ntfs_unmount: vflush failed: %d\n",error);
return (error);
@@ -667,7 +667,7 @@ ntfs_unmount(
if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
/* vflush system vnodes */
- error = vflush(mp,NULLVP,flags);
+ error = vflush(mp, 0, flags);
if (error)
printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
diff --git a/sys/nwfs/nwfs_vfsops.c b/sys/nwfs/nwfs_vfsops.c
index c9084ef..c978722 100644
--- a/sys/nwfs/nwfs_vfsops.c
+++ b/sys/nwfs/nwfs_vfsops.c
@@ -237,35 +237,16 @@ nwfs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
struct nwmount *nmp = VFSTONWFS(mp);
struct ncp_conn *conn;
- struct vnode *vp;
int error, flags;
NCPVODEBUG("nwfs_unmount: flags=%04x\n",mntflags);
flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- error = VFS_ROOT(mp,&vp);
- if (error) return (error);
- if (vp->v_usecount > 2) {
- printf("nwfs_unmount: usecnt=%d\n",vp->v_usecount);
- vput(vp);
- return (EBUSY);
- }
- error = vflush(mp, vp, flags);
- if (error) {
- vput(vp);
+ /* There is 1 extra root vnode reference from nwfs_mount(). */
+ error = vflush(mp, 1, flags);
+ if (error)
return (error);
- }
- /*
- * There are two reference counts and one lock to get rid of here.
- */
- NCPVODEBUG("v_use: %d\n",vp->v_usecount);
- vput(vp);
- NCPVODEBUG("v_use after vput: %d\n",vp->v_usecount);
- vrele(vp);
- NCPVODEBUG("v_use after vrele: %d\n",vp->v_usecount);
- vgone(vp);
- NCPVODEBUG("v_gone finished !!!!\n");
conn = NWFSTOCONN(nmp);
ncp_conn_puthandle(nmp->connh,NULL,0);
if (ncp_conn_lock(conn,p,p->p_ucred,NCPM_WRITE | NCPM_EXECUTE) == 0) {
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index cba084c..e530d4a 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -579,7 +579,7 @@ void vdrop __P((struct vnode *));
int vfinddev __P((dev_t dev, enum vtype type, struct vnode **vpp));
void vfs_add_vnodeops __P((const void *));
void vfs_rm_vnodeops __P((const void *));
-int vflush __P((struct mount *mp, struct vnode *skipvp, int flags));
+int vflush __P((struct mount *mp, int rootrefs, int flags));
int vget __P((struct vnode *vp, int lockflag, struct proc *p));
void vgone __P((struct vnode *vp));
void vgonel __P((struct vnode *vp, struct proc *p));
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 04ba155..fd77a17 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -898,7 +898,7 @@ ffs_flushfiles(mp, flags, p)
#ifdef QUOTA
if (mp->mnt_flag & MNT_QUOTA) {
int i;
- error = vflush(mp, NULLVP, SKIPSYSTEM|flags);
+ error = vflush(mp, 0, SKIPSYSTEM|flags);
if (error)
return (error);
for (i = 0; i < MAXQUOTAS; i++) {
@@ -913,7 +913,7 @@ ffs_flushfiles(mp, flags, p)
}
#endif
if (ump->um_devvp->v_flag & VCOPYONWRITE) {
- if ((error = vflush(mp, NULL, SKIPSYSTEM | flags)) != 0)
+ if ((error = vflush(mp, 0, SKIPSYSTEM | flags)) != 0)
return (error);
ffs_snapshot_unmount(mp);
/*
@@ -924,7 +924,7 @@ ffs_flushfiles(mp, flags, p)
/*
* Flush all the files.
*/
- if ((error = vflush(mp, NULL, flags)) != 0)
+ if ((error = vflush(mp, 0, flags)) != 0)
return (error);
/*
* Flush filesystem metadata.
OpenPOWER on IntegriCloud