From 825ff80fc6ddbcb46196ea7e91b19b21d4c08498 Mon Sep 17 00:00:00 2001 From: Jan-Simon Pendry Date: Sat, 10 Dec 1994 21:03:10 -0800 Subject: [PATCH 1/1] fix readdir for no-linear stacks SCCS-vsn: sys/miscfs/union/union.h 8.9 SCCS-vsn: sys/miscfs/union/union_subr.c 8.16 SCCS-vsn: sys/miscfs/union/union_vnops.c 8.22 SCCS-vsn: sys/miscfs/union/union_vfsops.c 8.13 --- usr/src/sys/miscfs/union/union.h | 5 +- usr/src/sys/miscfs/union/union_subr.c | 110 +++++++++++++++++++++--- usr/src/sys/miscfs/union/union_vfsops.c | 5 +- usr/src/sys/miscfs/union/union_vnops.c | 42 ++++++--- 4 files changed, 132 insertions(+), 30 deletions(-) diff --git a/usr/src/sys/miscfs/union/union.h b/usr/src/sys/miscfs/union/union.h index 1bcc9571e2..56b2b72b30 100644 --- a/usr/src/sys/miscfs/union/union.h +++ b/usr/src/sys/miscfs/union/union.h @@ -8,7 +8,7 @@ * * %sccs.include.redist.c% * - * @(#)union.h 8.8 (Berkeley) %G% + * @(#)union.h 8.9 (Berkeley) %G% */ struct union_args { @@ -53,6 +53,7 @@ struct union_node { int un_hash; /* saved un_path hash value */ int un_openl; /* # of opens on lowervp */ unsigned int un_flags; + struct vnode **un_dircache; /* cached union stack */ off_t un_uppersz; /* size of upper object */ off_t un_lowersz; /* size of lower object */ #ifdef DIAGNOSTIC @@ -69,7 +70,7 @@ struct union_node { extern int union_allocvp __P((struct vnode **, struct mount *, struct vnode *, struct vnode *, struct componentname *, struct vnode *, - struct vnode *)); + struct vnode *, int)); extern int union_copyfile __P((struct vnode *, struct vnode *, struct ucred *, struct proc *)); extern int union_copyup __P((struct union_node *, int, struct ucred *, diff --git a/usr/src/sys/miscfs/union/union_subr.c b/usr/src/sys/miscfs/union/union_subr.c index 0da28d4185..68e2bc8f6c 100644 --- a/usr/src/sys/miscfs/union/union_subr.c +++ b/usr/src/sys/miscfs/union/union_subr.c @@ -8,7 +8,7 @@ * * %sccs.include.redist.c% * - * @(#)union_subr.c 8.15 (Berkeley) %G% + * @(#)union_subr.c 8.16 (Berkeley) %G% */ #include @@ -239,7 +239,7 @@ union_newsize(vp, uppersz, lowersz) * the vnode free list. */ int -union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) +union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp, docache) struct vnode **vpp; struct mount *mp; struct vnode *undvp; /* parent union vnode */ @@ -247,6 +247,7 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) struct componentname *cnp; /* may be null */ struct vnode *uppervp; /* may be null */ struct vnode *lowervp; /* may be null */ + int docache; { int error; struct union_node *un; @@ -278,7 +279,9 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) } loop: - for (try = 0; try < 3; try++) { + if (!docache) { + un = 0; + } else for (try = 0; try < 3; try++) { switch (try) { case 0: if (lowervp == NULLVP) @@ -409,14 +412,16 @@ loop: return (0); } - /* - * otherwise lock the vp list while we call getnewvnode - * since that can block. - */ - hash = UNION_HASH(uppervp, lowervp); + if (docache) { + /* + * otherwise lock the vp list while we call getnewvnode + * since that can block. + */ + hash = UNION_HASH(uppervp, lowervp); - if (union_list_lock(hash)) - goto loop; + if (union_list_lock(hash)) + goto loop; + } error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); if (error) { @@ -449,6 +454,7 @@ loop: un->un_pvp = undvp; if (undvp != NULLVP) VREF(undvp); + un->un_dircache = 0; un->un_openl = 0; un->un_flags = UN_LOCKED; if (un->un_uppervp) @@ -472,14 +478,17 @@ loop: un->un_dirvp = 0; } - LIST_INSERT_HEAD(&unhead[hash], un, un_cache); - un->un_flags |= UN_CACHED; + if (docache) { + LIST_INSERT_HEAD(&unhead[hash], un, un_cache); + un->un_flags |= UN_CACHED; + } if (xlowervp) vrele(xlowervp); out: - union_list_unlock(hash); + if (docache) + union_list_unlock(hash); return (error); } @@ -923,6 +932,7 @@ union_removed_upper(un) } } +#if 0 struct vnode * union_lowervp(vp) struct vnode *vp; @@ -937,6 +947,7 @@ union_lowervp(vp) return (NULLVP); } +#endif /* * determine whether a whiteout is needed @@ -959,3 +970,76 @@ union_dowhiteout(un, cred, p) return (0); } + +static void +union_dircache_r(vp, vppp, cntp) + struct vnode *vp; + struct vnode ***vppp; + int *cntp; +{ + struct union_node *un; + + if (vp->v_op != union_vnodeop_p) { + if (vppp) { + VREF(vp); + *(*vppp)++ = vp; + if (--(*cntp) == 0) + panic("union: dircache table too small"); + } else { + (*cntp)++; + } + + return; + } + + un = VTOUNION(vp); + if (un->un_uppervp != NULLVP) + union_dircache_r(un->un_uppervp, vppp, cntp); + if (un->un_lowervp != NULLVP) + union_dircache_r(un->un_lowervp, vppp, cntp); +} + +struct vnode * +union_dircache(vp) + struct vnode *vp; +{ + int cnt; + struct vnode *nvp; + struct vnode **vpp; + struct vnode **dircache = VTOUNION(vp)->un_dircache; + struct union_node *un; + int error; + + if (dircache == 0) { + cnt = 0; + union_dircache_r(vp, 0, &cnt); + cnt++; + dircache = (struct vnode **) + malloc(cnt * sizeof(struct vnode *), + M_TEMP, M_WAITOK); + vpp = dircache; + union_dircache_r(vp, &vpp, &cnt); + *vpp = NULLVP; + vpp = dircache + 1; + } else { + vpp = dircache; + do { + if (*vpp++ == VTOUNION(vp)->un_uppervp) + break; + } while (*vpp != NULLVP); + } + + if (*vpp == NULLVP) + return (NULLVP); + + VOP_LOCK(*vpp); + VREF(*vpp); + error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0); + if (error) + return (NULLVP); + VTOUNION(vp)->un_dircache = 0; + un = VTOUNION(nvp); + un->un_dircache = dircache; + + return (nvp); +} diff --git a/usr/src/sys/miscfs/union/union_vfsops.c b/usr/src/sys/miscfs/union/union_vfsops.c index be5abd652e..3816b9ff66 100644 --- a/usr/src/sys/miscfs/union/union_vfsops.c +++ b/usr/src/sys/miscfs/union/union_vfsops.c @@ -8,7 +8,7 @@ * * %sccs.include.redist.c% * - * @(#)union_vfsops.c 8.12 (Berkeley) %G% + * @(#)union_vfsops.c 8.13 (Berkeley) %G% */ /* @@ -345,7 +345,8 @@ union_root(mp, vpp) (struct vnode *) 0, (struct componentname *) 0, um->um_uppervp, - um->um_lowervp); + um->um_lowervp, + 1); if (error) { if (!loselock) diff --git a/usr/src/sys/miscfs/union/union_vnops.c b/usr/src/sys/miscfs/union/union_vnops.c index 1709fc0c42..fe82e16b2c 100644 --- a/usr/src/sys/miscfs/union/union_vnops.c +++ b/usr/src/sys/miscfs/union/union_vnops.c @@ -8,7 +8,7 @@ * * %sccs.include.redist.c% * - * @(#)union_vnops.c 8.21 (Berkeley) %G% + * @(#)union_vnops.c 8.22 (Berkeley) %G% */ #include @@ -311,7 +311,7 @@ union_lookup(ap) VOP_UNLOCK(lowervp); error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, - uppervp, lowervp); + uppervp, lowervp, 1); if (error) { if (uppervp != NULLVP) @@ -342,11 +342,13 @@ union_create(ap) if (dvp != NULLVP) { int error; struct vnode *vp; + struct mount *mp; FIXUP(un); VREF(dvp); un->un_flags |= UN_KLOCK; + mp = ap->a_dvp->v_mount; vput(ap->a_dvp); error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap); if (error) @@ -354,12 +356,13 @@ union_create(ap) error = union_allocvp( ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, + mp, + NULLVP, NULLVP, ap->a_cnp, vp, - NULLVP); + NULLVP, + 1); if (error) vput(vp); return (error); @@ -401,11 +404,13 @@ union_mknod(ap) if (dvp != NULLVP) { int error; struct vnode *vp; + struct mount *mp; FIXUP(un); VREF(dvp); un->un_flags |= UN_KLOCK; + mp = ap->a_dvp->v_mount; vput(ap->a_dvp); error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap); if (error) @@ -414,12 +419,13 @@ union_mknod(ap) if (vp != NULLVP) { error = union_allocvp( ap->a_vpp, - ap->a_dvp->v_mount, - ap->a_dvp, + mp, + NULLVP, NULLVP, ap->a_cnp, vp, - NULLVP); + NULLVP, + 1); if (error) vput(vp); } @@ -614,9 +620,7 @@ union_getattr(ap) } if (vp != NULLVP) { - VOP_LOCK(vp); error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); - VOP_UNLOCK(vp); if (error) return (error); union_newsize(ap->a_vp, VNOVAL, vap->va_size); @@ -1059,10 +1063,12 @@ union_mkdir(ap) FIXUP(un); VREF(dvp); un->un_flags |= UN_KLOCK; - vput(ap->a_dvp); + VOP_UNLOCK(ap->a_dvp); error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); - if (error) + if (error) { + vrele(ap->a_dvp); return (error); + } error = union_allocvp( ap->a_vpp, @@ -1071,7 +1077,9 @@ union_mkdir(ap) NULLVP, ap->a_cnp, vp, - NULLVP); + NULLVP, + 1); + vrele(ap->a_dvp); if (error) vput(vp); return (error); @@ -1245,6 +1253,7 @@ union_inactive(ap) } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + struct vnode **vpp; /* * Do nothing (and _don't_ bypass). @@ -1266,6 +1275,13 @@ union_inactive(ap) panic("union: inactivating w/locked upper node"); #endif + if (un->un_dircache != 0) { + for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) + vrele(*vpp); + free(un->un_dircache, M_TEMP); + un->un_dircache = 0; + } + if ((un->un_flags & UN_CACHED) == 0) vgone(ap->a_vp); -- 2.20.1