Index: sys/miscfs/union/union.h =================================================================== RCS file: /cvs/src/sys/miscfs/union/Attic/union.h,v retrieving revision 1.17 diff -u -r1.17 union.h --- sys/miscfs/union/union.h 29 Dec 1999 04:54:48 -0000 1.17 +++ sys/miscfs/union/union.h 31 May 2003 20:16:02 -0000 @@ -119,7 +119,8 @@ struct componentname *, struct vnode *, struct vnode *, int)); extern int union_freevp __P((struct vnode *)); -extern struct vnode *union_dircache __P((struct vnode *, struct proc *)); +extern struct vnode *union_dircache_get(struct vnode *, struct proc *); +extern void union_dircache_free(struct union_node *); extern int union_copyup __P((struct union_node *, int, struct ucred *, struct proc *)); extern int union_dowhiteout __P((struct union_node *, struct ucred *, @@ -144,6 +145,9 @@ #define LOWERVP(vp) (VTOUNION(vp)->un_lowervp) #define UPPERVP(vp) (VTOUNION(vp)->un_uppervp) #define OTHERVP(vp) (UPPERVP(vp) ? UPPERVP(vp) : LOWERVP(vp)) + +MALLOC_DECLARE(M_UNPATH); +MALLOC_DECLARE(M_UNDCACHE); #define UDEBUG(x) if (uniondebug) printf x #define UDEBUG_ENABLED 1 Index: sys/miscfs/union/union_subr.c =================================================================== RCS file: /cvs/src/sys/miscfs/union/Attic/union_subr.c,v retrieving revision 1.43.2.2 diff -u -r1.43.2.2 union_subr.c --- sys/miscfs/union/union_subr.c 25 Dec 2001 01:44:45 -0000 1.43.2.2 +++ sys/miscfs/union/union_subr.c 31 May 2003 23:34:07 -0000 @@ -183,7 +183,7 @@ if (un->un_lowervp) { vrele(un->un_lowervp); if (un->un_path) { - free(un->un_path, M_TEMP); + free(un->un_path, M_UNPATH); un->un_path = 0; } } @@ -500,7 +500,7 @@ union_newlower(un, lowervp); if (cnp && (lowervp != NULLVP)) { un->un_path = malloc(cnp->cn_namelen+1, - M_TEMP, M_WAITOK); + M_UNPATH, M_WAITOK); bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); un->un_path[cnp->cn_namelen] = '\0'; @@ -578,11 +578,11 @@ un->un_pvp = dvp; /* only parent dir in new allocation */ if (dvp != NULLVP) VREF(dvp); - un->un_dircache = 0; + un->un_dircache = NULL; un->un_openl = 0; if (cnp && (lowervp != NULLVP)) { - un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); + un->un_path = malloc(cnp->cn_namelen+1, M_UNPATH, M_WAITOK); bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); un->un_path[cnp->cn_namelen] = '\0'; } else { @@ -630,7 +630,7 @@ un->un_dirvp = NULL; } if (un->un_path) { - free(un->un_path, M_TEMP); + free(un->un_path, M_UNPATH); un->un_path = NULL; } @@ -1143,12 +1143,8 @@ * the union node from cache, so that it will not be referrenced. */ union_newupper(un, NULLVP); - 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_dircache != NULL) + union_dircache_free(un); if (un->un_flags & UN_CACHED) { un->un_flags &= ~UN_CACHED; @@ -1180,6 +1176,19 @@ return (0); } +/* + * union_dircache_r - construct a directory cache + * + * This function has two modes of operation. If vppp is NULL, it increments + * *cntp by the number of elements that the directory cache would contain. + * Otherwise, it recursively populates the array of pointers pointed to by + * *vppp with references to vp's upper and lower vnodes, leaving *vpp pointing + * just beyond the last position filled. In the latter mode of operation, + * *cntp should be set to one greater than the number of elements in the *vpp + * array. + * + * Yes, this is all very ugly and ought to be replaced with something better. + */ static void union_dircache_r(vp, vppp, cntp) struct vnode *vp; @@ -1197,31 +1206,31 @@ } else { (*cntp)++; } - - return; + } else { + 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); } - - 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, p) +union_dircache_get(vp, p) struct vnode *vp; struct proc *p; { int cnt; struct vnode *nvp; struct vnode **vpp; - struct vnode **dircache; + struct vnode **dircache, **newdircache; struct union_node *un; int error; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - dircache = VTOUNION(vp)->un_dircache; + un = VTOUNION(vp); + dircache = un->un_dircache; + newdircache = NULL; nvp = NULLVP; @@ -1229,8 +1238,8 @@ cnt = 0; union_dircache_r(vp, 0, &cnt); cnt++; - dircache = malloc(cnt * sizeof(struct vnode *), - M_TEMP, M_WAITOK); + newdircache = dircache = malloc(cnt * sizeof(struct vnode *), + M_UNDCACHE, M_WAITOK); vpp = dircache; union_dircache_r(vp, &vpp, &cnt); *vpp = NULLVP; @@ -1238,7 +1247,7 @@ } else { vpp = dircache; do { - if (*vpp++ == VTOUNION(vp)->un_uppervp) + if (*vpp++ == un->un_uppervp) break; } while (*vpp != NULLVP); } @@ -1254,15 +1263,35 @@ if (error) goto out; - VTOUNION(vp)->un_dircache = 0; - un = VTOUNION(nvp); - un->un_dircache = dircache; + un->un_dircache = NULL; + VTOUNION(nvp)->un_dircache = dircache; + newdircache = NULL; out: + /* + * If we allocated a new dircache and couldn't attach + * it to a new vp, free the resources we allocated. + */ + if (newdircache) { + for (vpp = newdircache; *vpp != NULLVP; vpp++) + vrele(*vpp); + free(newdircache, M_UNDCACHE); + } VOP_UNLOCK(vp, 0, p); return (nvp); } +void +union_dircache_free(struct union_node *un) +{ + struct vnode **vpp; + + for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) + vrele(*vpp); + free(un->un_dircache, M_UNDCACHE); + un->un_dircache = NULL; +} + /* * Guarentee coherency with the VM cache by invalidating any clean VM pages * associated with this write and updating any dirty VM pages. Since our @@ -1308,7 +1337,7 @@ if ((*vp)->v_op == union_vnodeop_p) { struct vnode *lvp; - lvp = union_dircache(*vp, p); + lvp = union_dircache_get(*vp, p); if (lvp != NULLVP) { struct vattr va; @@ -1319,7 +1348,7 @@ error = VOP_GETATTR(*vp, &va, fp->f_cred, p); if (va.va_flags & OPAQUE) { vput(lvp); - lvp = NULL; + lvp = NULLVP; } } Index: sys/miscfs/union/union_vfsops.c =================================================================== RCS file: /cvs/src/sys/miscfs/union/Attic/union_vfsops.c,v retrieving revision 1.39.2.2 diff -u -r1.39.2.2 union_vfsops.c --- sys/miscfs/union/union_vfsops.c 25 Oct 2001 19:18:53 -0000 1.39.2.2 +++ sys/miscfs/union/union_vfsops.c 28 May 2003 06:19:12 -0000 @@ -54,6 +54,8 @@ #include #include +MALLOC_DEFINE(M_UNPATH, "unpath", "UNION path component"); +MALLOC_DEFINE(M_UNDCACHE, "undcac", "UNION directory cache"); static MALLOC_DEFINE(M_UNIONFSMNT, "UNION mount", "UNION mount structure"); extern int union_init __P((struct vfsconf *)); Index: sys/miscfs/union/union_vnops.c =================================================================== RCS file: /cvs/src/sys/miscfs/union/Attic/union_vnops.c,v retrieving revision 1.72 diff -u -r1.72 union_vnops.c --- sys/miscfs/union/union_vnops.c 15 Dec 1999 23:02:14 -0000 1.72 +++ sys/miscfs/union/union_vnops.c 31 May 2003 17:09:36 -0000 @@ -672,9 +672,22 @@ struct vnode *uppervp; int error = EOPNOTSUPP; - if ((uppervp = union_lock_upper(un, cnp->cn_proc)) != NULLVP) { - error = VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags); - union_unlock_upper(uppervp, cnp->cn_proc); + switch (ap->a_flags) { + case LOOKUP: + /* + * Our upper layer supports whiteout entries, so we can, too. + */ + error = 0; + break; + case CREATE: + case DELETE: + if ((uppervp = union_lock_upper(un, cnp->cn_proc)) != NULLVP) { + error = VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags); + union_unlock_upper(uppervp, cnp->cn_proc); + } + break; + default: + panic("union_whiteout: unknown op"); } return(error); } @@ -1711,12 +1724,8 @@ * That's too much work for now. */ - 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_dircache != 0) + union_dircache_free(un); #if 0 if ((un->un_flags & UN_ULOCK) && un->un_uppervp) {