fix readdir for no-linear stacks
authorJan-Simon Pendry <pendry@ucbvax.Berkeley.EDU>
Sun, 11 Dec 1994 05:03:10 +0000 (21:03 -0800)
committerJan-Simon Pendry <pendry@ucbvax.Berkeley.EDU>
Sun, 11 Dec 1994 05:03:10 +0000 (21:03 -0800)
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
usr/src/sys/miscfs/union/union_subr.c
usr/src/sys/miscfs/union/union_vfsops.c
usr/src/sys/miscfs/union/union_vnops.c

index 1bcc957..56b2b72 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union.h     8.8 (Berkeley) %G%
+ *     @(#)union.h     8.9 (Berkeley) %G%
  */
 
 struct union_args {
  */
 
 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;
        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
        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 *,
 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 *,
 extern int union_copyfile __P((struct vnode *, struct vnode *,
                                        struct ucred *, struct proc *));
 extern int union_copyup __P((struct union_node *, int, struct ucred *,
index 0da28d4..68e2bc8 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union_subr.c        8.15 (Berkeley) %G%
+ *     @(#)union_subr.c        8.16 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -239,7 +239,7 @@ union_newsize(vp, uppersz, lowersz)
  * the vnode free list.
  */
 int
  * 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 */
        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 */
        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;
 {
        int error;
        struct union_node *un;
@@ -278,7 +279,9 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
        }
 
 loop:
        }
 
 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)
                switch (try) {
                case 0:
                        if (lowervp == NULLVP)
@@ -409,14 +412,16 @@ loop:
                return (0);
        }
 
                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) {
 
        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_pvp = undvp;
        if (undvp != NULLVP)
                VREF(undvp);
+       un->un_dircache = 0;
        un->un_openl = 0;
        un->un_flags = UN_LOCKED;
        if (un->un_uppervp)
        un->un_openl = 0;
        un->un_flags = UN_LOCKED;
        if (un->un_uppervp)
@@ -472,14 +478,17 @@ loop:
                un->un_dirvp = 0;
        }
 
                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:
 
        if (xlowervp)
                vrele(xlowervp);
 
 out:
-       union_list_unlock(hash);
+       if (docache)
+               union_list_unlock(hash);
 
        return (error);
 }
 
        return (error);
 }
@@ -923,6 +932,7 @@ union_removed_upper(un)
        }
 }
 
        }
 }
 
+#if 0
 struct vnode *
 union_lowervp(vp)
        struct vnode *vp;
 struct vnode *
 union_lowervp(vp)
        struct vnode *vp;
@@ -937,6 +947,7 @@ union_lowervp(vp)
 
        return (NULLVP);
 }
 
        return (NULLVP);
 }
+#endif
 
 /*
  * determine whether a whiteout is needed
 
 /*
  * determine whether a whiteout is needed
@@ -959,3 +970,76 @@ union_dowhiteout(un, cred, p)
 
        return (0);
 }
 
        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);
+}
index be5abd6..3816b9f 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %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,
                              (struct vnode *) 0,
                              (struct componentname *) 0,
                              um->um_uppervp,
-                             um->um_lowervp);
+                             um->um_lowervp,
+                             1);
 
        if (error) {
                if (!loselock)
 
        if (error) {
                if (!loselock)
index 1709fc0..fe82e16 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union_vnops.c       8.21 (Berkeley) %G%
+ *     @(#)union_vnops.c       8.22 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -311,7 +311,7 @@ union_lookup(ap)
                VOP_UNLOCK(lowervp);
 
        error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
                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)
 
        if (error) {
                if (uppervp != NULLVP)
@@ -342,11 +342,13 @@ union_create(ap)
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
+               struct mount *mp;
 
                FIXUP(un);
 
                VREF(dvp);
                un->un_flags |= UN_KLOCK;
 
                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)
                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,
 
                error = union_allocvp(
                                ap->a_vpp,
-                               ap->a_dvp->v_mount,
-                               ap->a_dvp,
+                               mp,
+                               NULLVP,
                                NULLVP,
                                ap->a_cnp,
                                vp,
                                NULLVP,
                                ap->a_cnp,
                                vp,
-                               NULLVP);
+                               NULLVP,
+                               1);
                if (error)
                        vput(vp);
                return (error);
                if (error)
                        vput(vp);
                return (error);
@@ -401,11 +404,13 @@ union_mknod(ap)
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
+               struct mount *mp;
 
                FIXUP(un);
 
                VREF(dvp);
                un->un_flags |= UN_KLOCK;
 
                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)
                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,
                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,
                                        ap->a_cnp,
                                        vp,
-                                       NULLVP);
+                                       NULLVP,
+                                       1);
                        if (error)
                                vput(vp);
                }
                        if (error)
                                vput(vp);
                }
@@ -614,9 +620,7 @@ union_getattr(ap)
        }
 
        if (vp != NULLVP) {
        }
 
        if (vp != NULLVP) {
-               VOP_LOCK(vp);
                error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
                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);
                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;
                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);
                error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap);
-               if (error)
+               if (error) {
+                       vrele(ap->a_dvp);
                        return (error);
                        return (error);
+               }
 
                error = union_allocvp(
                                ap->a_vpp,
 
                error = union_allocvp(
                                ap->a_vpp,
@@ -1071,7 +1077,9 @@ union_mkdir(ap)
                                NULLVP,
                                ap->a_cnp,
                                vp,
                                NULLVP,
                                ap->a_cnp,
                                vp,
-                               NULLVP);
+                               NULLVP,
+                               1);
+               vrele(ap->a_dvp);
                if (error)
                        vput(vp);
                return (error);
                if (error)
                        vput(vp);
                return (error);
@@ -1245,6 +1253,7 @@ union_inactive(ap)
        } */ *ap;
 {
        struct union_node *un = VTOUNION(ap->a_vp);
        } */ *ap;
 {
        struct union_node *un = VTOUNION(ap->a_vp);
+       struct vnode **vpp;
 
        /*
         * Do nothing (and _don't_ bypass).
 
        /*
         * Do nothing (and _don't_ bypass).
@@ -1266,6 +1275,13 @@ union_inactive(ap)
                panic("union: inactivating w/locked upper node");
 #endif
 
                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);
 
        if ((un->un_flags & UN_CACHED) == 0)
                vgone(ap->a_vp);