From 58572fc05152f723f068bae5657c3379e7b3eb8d Mon Sep 17 00:00:00 2001 From: Jan-Simon Pendry Date: Fri, 11 Feb 1994 02:38:14 -0800 Subject: [PATCH] cleanup & lint SCCS-vsn: sys/miscfs/union/union.h 2.2 SCCS-vsn: sys/miscfs/union/union_subr.c 2.2 SCCS-vsn: sys/miscfs/union/union_vnops.c 2.2 SCCS-vsn: sys/miscfs/union/union_vfsops.c 2.2 --- usr/src/sys/miscfs/union/union.h | 13 +- usr/src/sys/miscfs/union/union_subr.c | 234 ++++++++++++++++++------ usr/src/sys/miscfs/union/union_vfsops.c | 3 +- usr/src/sys/miscfs/union/union_vnops.c | 31 +--- 4 files changed, 193 insertions(+), 88 deletions(-) diff --git a/usr/src/sys/miscfs/union/union.h b/usr/src/sys/miscfs/union/union.h index 8041fb77a2..8ac2158156 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 2.1 (Berkeley) %G% + * @(#)union.h 2.2 (Berkeley) %G% */ struct union_args { @@ -42,7 +42,7 @@ struct union_mount { * A cache of vnode references */ struct union_node { - struct union_node *un_next; /* Hash chain */ + LIST_ENTRY(union_node) un_cache; /* Hash chain */ struct vnode *un_vnode; /* Back pointer */ struct vnode *un_uppervp; /* overlaying object */ struct vnode *un_lowervp; /* underlying object */ @@ -61,13 +61,6 @@ struct union_node { #define UN_ULOCK 0x04 /* Upper node is locked */ #define UN_KLOCK 0x08 /* Keep upper node locked on vput */ -#define LOCKUVP(un) \ - (((un)->un_flags & UN_ULOCK) ? \ - (0) : \ - (((un)->un_flags |= UN_ULOCK), VOP_LOCK((un)->un_uppervp))) -#define UNLOCKUVP(un) \ - ((un)->un_flags &= ~UN_ULOCK) - extern int union_allocvp __P((struct vnode **, struct mount *, struct vnode *, struct vnode *, struct componentname *, struct vnode *, @@ -82,6 +75,8 @@ extern int union_cn_close __P((struct vnode *, int, struct ucred *, struct proc *)); extern void union_removed_upper __P((struct union_node *un)); extern struct vnode *union_lowervp __P((struct vnode *)); +extern void union_newlower __P((struct union_node *, struct vnode *)); +extern void union_newupper __P((struct union_node *, struct vnode *)); #define MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data)) #define VTOUNION(vp) ((struct union_node *)(vp)->v_data) diff --git a/usr/src/sys/miscfs/union/union_subr.c b/usr/src/sys/miscfs/union/union_subr.c index 3319a34853..161d5869a6 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 2.1 (Berkeley) %G% + * @(#)union_subr.c 2.2 (Berkeley) %G% */ #include @@ -20,35 +20,139 @@ #include #include #include +#include #include "union.h" /**/ #ifdef DIAGNOSTIC #include #endif -static struct union_node *unhead; -static int unvplock; +/* must be power of two, otherwise change UNION_HASH() */ +#define NHASH 32 + +/* unsigned int ... */ +#define UNION_HASH(u, l) \ + (((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1)) + +static LIST_HEAD(unhead, union_node) unhead[NHASH]; +static int unvplock[NHASH]; int union_init() { + int i; + + for (i = 0; i < NHASH; i++) + LIST_INIT(&unhead[i]); + bzero((caddr_t) unvplock, sizeof(unvplock)); +} + +static int +union_list_lock(ix) + int ix; +{ + + if (unvplock[ix] & UN_LOCKED) { + unvplock[ix] |= UN_WANT; + sleep((caddr_t) &unvplock[ix], PINOD); + return (1); + } - unhead = 0; - unvplock = 0; + unvplock[ix] |= UN_LOCKED; + + return (0); } static void -union_remlist(un) +union_list_unlock(ix) + int ix; +{ + + unvplock[ix] &= ~UN_LOCKED; + + if (unvplock[ix] & UN_WANT) { + unvplock[ix] &= ~UN_WANT; + wakeup((caddr_t) &unvplock[ix]); + } +} + +void +union_updatevp(un, uppervp, lowervp) struct union_node *un; + struct vnode *uppervp; + struct vnode *lowervp; { - struct union_node **unpp; + int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); + int nhash = UNION_HASH(uppervp, lowervp); - for (unpp = &unhead; *unpp != 0; unpp = &(*unpp)->un_next) { - if (*unpp == un) { - *unpp = un->un_next; - break; + if (ohash != nhash) { + /* + * Ensure locking is ordered from lower to higher + * to avoid deadlocks. + */ + if (nhash < ohash) { + int t = ohash; + ohash = nhash; + nhash = t; + } + + while (union_list_lock(ohash)) + continue; + + while (union_list_lock(nhash)) + continue; + + LIST_REMOVE(un, un_cache); + union_list_unlock(ohash); + } else { + while (union_list_lock(nhash)) + continue; + } + + if (un->un_lowervp != lowervp) { + if (un->un_lowervp) { + vrele(un->un_lowervp); + if (un->un_path) { + free(un->un_path, M_TEMP); + un->un_path = 0; + } + if (un->un_dirvp) { + vrele(un->un_dirvp); + un->un_dirvp = NULLVP; + } } + un->un_lowervp = lowervp; + } + + if (un->un_uppervp != uppervp) { + if (un->un_uppervp) + vrele(un->un_uppervp); + + un->un_uppervp = uppervp; } + + if (ohash != nhash) + LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); + + union_list_unlock(nhash); +} + +void +union_newlower(un, lowervp) + struct union_node *un; + struct vnode *lowervp; +{ + + union_updatevp(un, un->un_uppervp, lowervp); +} + +void +union_newupper(un, uppervp) + struct union_node *un; + struct vnode *uppervp; +{ + + union_updatevp(un, uppervp, un->un_lowervp); } /* @@ -95,27 +199,62 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) int error; struct union_node *un; struct union_node **pp; - struct vnode *xlowervp = 0; + struct vnode *xlowervp = NULLVP; + int hash; + int try; - if (uppervp == 0 && lowervp == 0) + if (uppervp == NULLVP && lowervp == NULLVP) panic("union: unidentifiable allocation"); if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { xlowervp = lowervp; - lowervp = 0; + lowervp = NULLVP; } loop: - for (un = unhead; un != 0; un = un->un_next) { - if ((un->un_lowervp == lowervp || - un->un_lowervp == 0) && - (un->un_uppervp == uppervp || - un->un_uppervp == 0) && - (UNIONTOV(un)->v_mount == mp)) { - if (vget(UNIONTOV(un), 0)) - goto loop; + for (try = 0; try < 3; try++) { + switch (try) { + case 0: + if (lowervp == NULLVP) + continue; + hash = UNION_HASH(uppervp, lowervp); break; + + case 1: + if (uppervp == NULLVP) + continue; + hash = UNION_HASH(uppervp, NULLVP); + break; + + case 2: + if (lowervp == NULLVP) + continue; + hash = UNION_HASH(NULLVP, lowervp); + break; + } + + while (union_list_lock(hash)) + continue; + + for (un = unhead[hash].lh_first; un != 0; + un = un->un_cache.le_next) { + if ((un->un_lowervp == lowervp || + un->un_lowervp == NULLVP) && + (un->un_uppervp == uppervp || + un->un_uppervp == NULLVP) && + (UNIONTOV(un)->v_mount == mp)) { + if (vget(UNIONTOV(un), 0)) { + union_list_unlock(hash); + goto loop; + } + break; + } } + + union_list_unlock(hash); + + if (un) + break; } if (un) { @@ -169,9 +308,7 @@ loop: * Save information about the upper layer. */ if (uppervp != un->un_uppervp) { - if (un->un_uppervp) - vrele(un->un_uppervp); - un->un_uppervp = uppervp; + union_newupper(un, uppervp); } else if (uppervp) { vrele(uppervp); } @@ -188,12 +325,7 @@ loop: * might need. */ if (lowervp != un->un_lowervp) { - if (un->un_lowervp) { - vrele(un->un_lowervp); - free(un->un_path, M_TEMP); - vrele(un->un_dirvp); - } - un->un_lowervp = lowervp; + union_newlower(un, lowervp); if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) { un->un_hash = cnp->cn_hash; @@ -216,12 +348,10 @@ loop: * otherwise lock the vp list while we call getnewvnode * since that can block. */ - if (unvplock & UN_LOCKED) { - unvplock |= UN_WANT; - sleep((caddr_t) &unvplock, PINOD); + hash = UNION_HASH(uppervp, lowervp); + + if (union_list_lock(hash)) goto loop; - } - unvplock |= UN_LOCKED; error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); if (error) { @@ -246,7 +376,6 @@ loop: (*vpp)->v_type = lowervp->v_type; un = VTOUNION(*vpp); un->un_vnode = *vpp; - un->un_next = 0; un->un_uppervp = uppervp; un->un_lowervp = lowervp; un->un_openl = 0; @@ -272,21 +401,13 @@ loop: un->un_dirvp = 0; } - /* add to union vnode list */ - for (pp = &unhead; *pp; pp = &(*pp)->un_next) - continue; - *pp = un; + LIST_INSERT_HEAD(&unhead[hash], un, un_cache); if (xlowervp) vrele(xlowervp); out: - unvplock &= ~UN_LOCKED; - - if (unvplock & UN_WANT) { - unvplock &= ~UN_WANT; - wakeup((caddr_t) &unvplock); - } + union_list_unlock(hash); return (error); } @@ -297,10 +418,20 @@ union_freevp(vp) { struct union_node *un = VTOUNION(vp); - union_remlist(un); + LIST_REMOVE(un, un_cache); + + if (un->un_uppervp) + vrele(un->un_uppervp); + if (un->un_lowervp) + vrele(un->un_lowervp); + if (un->un_dirvp) + vrele(un->un_dirvp); + if (un->un_path) + free(un->un_path, M_TEMP); FREE(vp->v_data, M_TEMP); vp->v_data = 0; + return (0); } @@ -579,11 +710,10 @@ union_removed_upper(un) { if (un->un_flags & UN_ULOCK) { un->un_flags &= ~UN_ULOCK; - vput(un->un_uppervp); - } else { - vrele(un->un_uppervp); + VOP_UNLOCK(un->un_uppervp); } - un->un_uppervp = NULLVP; + + union_newupper(un, NULLVP); } struct vnode * diff --git a/usr/src/sys/miscfs/union/union_vfsops.c b/usr/src/sys/miscfs/union/union_vfsops.c index 0df9f551ea..3a49fd8edc 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 2.1 (Berkeley) %G% + * @(#)union_vfsops.c 2.2 (Berkeley) %G% */ /* @@ -25,6 +25,7 @@ #include #include #include +#include #include "union.h" /* diff --git a/usr/src/sys/miscfs/union/union_vnops.c b/usr/src/sys/miscfs/union/union_vnops.c index 9a2e2483bd..8bf9a559e4 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 2.1 (Berkeley) %G% + * @(#)union_vnops.c 2.2 (Berkeley) %G% */ #include @@ -22,6 +22,7 @@ #include #include #include +#include #include "union.h" static int @@ -394,7 +395,7 @@ union_open(ap) return (error); /* at this point, uppervp is locked */ - un->un_uppervp = vp; /* XXX */ + union_newupper(un, vp); un->un_flags |= UN_ULOCK; /* @@ -1085,31 +1086,9 @@ union_reclaim(ap) struct vnode *a_vp; } */ *ap; { - struct vnode *vp = ap->a_vp; - struct union_node *un = VTOUNION(vp); - struct vnode *uppervp = un->un_uppervp; - struct vnode *lowervp = un->un_lowervp; - struct vnode *dirvp = un->un_dirvp; - char *path = un->un_path; - /* - * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p, - * so we can't call VOPs on ourself. - */ - /* After this assignment, this node will not be re-used. */ - un->un_uppervp = NULLVP; - un->un_lowervp = NULLVP; - un->un_dirvp = NULLVP; - un->un_path = NULL; - union_freevp(vp); - if (uppervp) - vrele(uppervp); - if (lowervp) - vrele(lowervp); - if (dirvp) - vrele(dirvp); - if (path) - free(path, M_TEMP); + union_freevp(ap->a_vp); + return (0); } -- 2.20.1