mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-04 09:09:56 +00:00
Change the second argument of vflush() to an integer that specifies
the number of references on the filesystem root vnode to be both expected and released. Many filesystems hold an extra reference on the filesystem root vnode, which must be accounted for when determining if the filesystem is busy and then released if it isn't busy. The old `skipvp' approach required individual filesystem xxx_unmount functions to re-implement much of vflush()'s logic to deal with the root vnode. All 9 filesystems that hold an extra reference on the root vnode got the logic wrong in the case of forced unmounts, so `umount -f' would always fail if there were any extra root vnode references. Fix this issue centrally in vflush(), now that we can. This commit also fixes a vnode reference leak in devfs, which could result in idle devfs filesystems that refuse to unmount. Reviewed by: phk, bp
This commit is contained in:
parent
73cf2c3089
commit
0864ef1e8a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=76688
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,20 +122,13 @@ 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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -603,7 +603,7 @@ ntfs_mountfs(devvp, mp, argsp, p)
|
||||
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);
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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) {
|
||||
|
@ -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,20 +171,11 @@ 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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
@ -363,14 +353,6 @@ union_unmount(mp, mntflags, p)
|
||||
vrele(um->um_lowervp);
|
||||
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
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 @@ vflush(mp, skipvp, flags)
|
||||
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 @@ vflush(mp, skipvp, flags)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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,20 +122,13 @@ 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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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,20 +171,11 @@ 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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
@ -363,14 +353,6 @@ union_unmount(mp, mntflags, p)
|
||||
vrele(um->um_lowervp);
|
||||
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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -603,7 +603,7 @@ ntfs_mountfs(devvp, mp, argsp, p)
|
||||
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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user