diff --git a/sys/miscfs/union/union.h b/sys/miscfs/union/union.h index d2ab479ec930..2c8ab1f97215 100644 --- a/sys/miscfs/union/union.h +++ b/sys/miscfs/union/union.h @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)union.h 8.5 (Berkeley) 5/17/94 - * $Id: union.h,v 1.2 1994/06/15 23:07:58 mycroft Exp $ + * $Id: union.h,v 1.3 1994/06/17 15:21:33 mycroft Exp $ */ struct union_args { @@ -75,6 +75,7 @@ struct union_node { struct vnode *un_uppervp; /* overlaying object */ struct vnode *un_lowervp; /* underlying object */ struct vnode *un_dirvp; /* Parent dir of uppervp */ + struct vnode *un_pvp; /* Parent vnode */ char *un_path; /* saved component name */ int un_hash; /* saved un_path hash value */ int un_openl; /* # of opens on lowervp */ diff --git a/sys/miscfs/union/union_subr.c b/sys/miscfs/union/union_subr.c index 222046ab6646..c104cfecf350 100644 --- a/sys/miscfs/union/union_subr.c +++ b/sys/miscfs/union/union_subr.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)union_subr.c 8.9 (Berkeley) 5/17/94 - * $Id: union_subr.c,v 1.2 1994/06/15 23:07:59 mycroft Exp $ + * $Id: union_subr.c,v 1.3 1994/06/17 15:21:35 mycroft Exp $ */ #include @@ -131,8 +131,8 @@ union_updatevp(un, uppervp, lowervp) if (ohash != nhash || !docache) { if (un->un_flags & UN_CACHED) { - LIST_REMOVE(un, un_cache); un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); } } @@ -265,7 +265,7 @@ int union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) struct vnode **vpp; struct mount *mp; - struct vnode *undvp; + struct vnode *undvp; /* parent union vnode */ struct vnode *dvp; /* may be null */ struct componentname *cnp; /* may be null */ struct vnode *uppervp; /* may be null */ @@ -470,6 +470,9 @@ loop: un->un_uppersz = VNOVAL; un->un_lowervp = lowervp; un->un_lowersz = VNOVAL; + un->un_pvp = undvp; + if (undvp != NULLVP) + VREF(undvp); un->un_openl = 0; un->un_flags = UN_LOCKED; if (un->un_uppervp) @@ -512,10 +515,12 @@ union_freevp(vp) struct union_node *un = VTOUNION(vp); if (un->un_flags & UN_CACHED) { - LIST_REMOVE(un, un_cache); un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); } + if (un->un_pvp != NULLVP) + vrele(un->un_pvp); if (un->un_uppervp != NULLVP) vrele(un->un_uppervp); if (un->un_lowervp != NULLVP) @@ -861,12 +866,16 @@ void union_removed_upper(un) struct union_node *un; { + if (un->un_flags & UN_ULOCK) { un->un_flags &= ~UN_ULOCK; VOP_UNLOCK(un->un_uppervp); } - union_newupper(un, NULLVP); + if (un->un_flags & UN_CACHED) { + un->un_flags &= ~UN_CACHED; + LIST_REMOVE(un, un_cache); + } } struct vnode * diff --git a/sys/miscfs/union/union_vfsops.c b/sys/miscfs/union/union_vfsops.c index 42ad47ede0b5..b6b319dd80a2 100644 --- a/sys/miscfs/union/union_vfsops.c +++ b/sys/miscfs/union/union_vfsops.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)union_vfsops.c 8.10 (Berkeley) 5/24/94 - * $Id: union_vfsops.c,v 1.2 1994/06/15 23:08:02 mycroft Exp $ + * $Id: union_vfsops.c,v 1.3 1994/06/17 15:21:37 mycroft Exp $ */ /* @@ -297,6 +297,7 @@ union_unmount(mp, mntflags, p) struct union_mount *um = MOUNTTOUNIONMOUNT(mp); struct vnode *um_rootvp; int error; + int freeing; int flags = 0; extern int doforce; @@ -318,17 +319,48 @@ union_unmount(mp, mntflags, p) if (error = union_root(mp, &um_rootvp)) return (error); + + /* + * Keep flushing vnodes from the mount list. + * This is needed because of the un_pvp held + * reference to the parent vnode. + * If more vnodes have been freed on a given pass, + * the try again. The loop will iterate at most + * (d) times, where (d) is the maximum tree depth + * in the filesystem. + */ + for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) { + struct vnode *vp; + int n; + + /* count #vnodes held on mount list */ + for (n = 0, vp = mp->mnt_vnodelist.lh_first; + vp != NULLVP; + vp = vp->v_mntvnodes.le_next) + n++; + + /* if this is unchanged then stop */ + if (n == freeing) + break; + + /* otherwise try once more time */ + freeing = n; + } + + /* At this point the root vnode should have a single reference */ if (um_rootvp->v_usecount > 1) { vput(um_rootvp); return (EBUSY); } +#ifdef notneeded if (error = vflush(mp, um_rootvp, flags)) { vput(um_rootvp); return (error); } +#endif #ifdef UNION_DIAGNOSTIC - vprint("alias root of lower", um_rootvp); + vprint("union root", um_rootvp); #endif /* * Discard references to upper and lower target vnodes. diff --git a/sys/miscfs/union/union_vnops.c b/sys/miscfs/union/union_vnops.c index 329290c90fd4..171c4367a418 100644 --- a/sys/miscfs/union/union_vnops.c +++ b/sys/miscfs/union/union_vnops.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)union_vnops.c 8.15 (Berkeley) 6/4/94 - * $Id: union_vnops.c,v 1.2 1994/06/15 23:08:04 mycroft Exp $ + * $Id: union_vnops.c,v 1.3 1994/06/17 15:21:39 mycroft Exp $ */ #include @@ -241,6 +241,14 @@ union_lookup(ap) } } else { lerror = ENOENT; + if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) { + lowervp = LOWERVP(dun->un_pvp); + if (lowervp != NULLVP) { + VREF(lowervp); + VOP_LOCK(lowervp); + lerror = 0; + } + } } if (!lockparent) @@ -597,7 +605,7 @@ union_getattr(ap) if ((vap != ap->a_vap) && (vap->va_type == VDIR)) ap->a_vap->va_nlink += vap->va_nlink; - vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; + ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; return (0); }