1*65934Spendry /* 2*65934Spendry * Copyright (c) 1994 Jan-Simon Pendry 3*65934Spendry * Copyright (c) 1994 4*65934Spendry * The Regents of the University of California. All rights reserved. 5*65934Spendry * 6*65934Spendry * This code is derived from software contributed to Berkeley by 7*65934Spendry * Jan-Simon Pendry. 8*65934Spendry * 9*65934Spendry * %sccs.include.redist.c% 10*65934Spendry * 11*65934Spendry * @(#)union_subr.c 1.1 (Berkeley) 01/28/94 12*65934Spendry */ 13*65934Spendry 14*65934Spendry #include <sys/param.h> 15*65934Spendry #include <sys/systm.h> 16*65934Spendry #include <sys/time.h> 17*65934Spendry #include <sys/kernel.h> 18*65934Spendry #include <sys/vnode.h> 19*65934Spendry #include <sys/namei.h> 20*65934Spendry #include <sys/malloc.h> 21*65934Spendry #include "union.h" /*<miscfs/union/union.h>*/ 22*65934Spendry 23*65934Spendry static struct union_node *unhead; 24*65934Spendry static int unvplock; 25*65934Spendry 26*65934Spendry int 27*65934Spendry union_init() 28*65934Spendry { 29*65934Spendry 30*65934Spendry unhead = 0; 31*65934Spendry unvplock = 0; 32*65934Spendry } 33*65934Spendry 34*65934Spendry /* 35*65934Spendry * allocate a union_node/vnode pair. the vnode is 36*65934Spendry * referenced and locked. 37*65934Spendry * 38*65934Spendry * all union_nodes are maintained on a singly-linked 39*65934Spendry * list. new nodes are only allocated when they cannot 40*65934Spendry * be found on this list. entries on the list are 41*65934Spendry * removed when the vfs reclaim entry is called. 42*65934Spendry * 43*65934Spendry * a single lock is kept for the entire list. this is 44*65934Spendry * needed because the getnewvnode() function can block 45*65934Spendry * waiting for a vnode to become free, in which case there 46*65934Spendry * may be more than one process trying to get the same 47*65934Spendry * vnode. this lock is only taken if we are going to 48*65934Spendry * call getnewvnode, since the kernel itself is single-threaded. 49*65934Spendry * 50*65934Spendry * if an entry is found on the list, then call vget() to 51*65934Spendry * take a reference. this is done because there may be 52*65934Spendry * zero references to it and so it needs to removed from 53*65934Spendry * the vnode free list. 54*65934Spendry */ 55*65934Spendry int 56*65934Spendry union_allocvp(vpp, mp, dvp, cnp, uppervp, lowervp) 57*65934Spendry struct vnode **vpp; 58*65934Spendry struct mount *mp; 59*65934Spendry struct vnode *dvp; /* may be null */ 60*65934Spendry struct componentname *cnp; /* may be null */ 61*65934Spendry struct vnode *uppervp; /* may be null */ 62*65934Spendry struct vnode *lowervp; /* may be null */ 63*65934Spendry { 64*65934Spendry int error; 65*65934Spendry struct union_node *un; 66*65934Spendry struct union_node **pp; 67*65934Spendry 68*65934Spendry loop: 69*65934Spendry for (un = unhead; un != 0; un = un->un_next) { 70*65934Spendry if ((un->un_lowervp == lowervp || 71*65934Spendry un->un_lowervp == 0) && 72*65934Spendry (un->un_uppervp == uppervp || 73*65934Spendry un->un_uppervp == 0) && 74*65934Spendry (UNIONTOV(un)->v_mount == mp)) { 75*65934Spendry if (vget(un->un_vnode, 1)) 76*65934Spendry goto loop; 77*65934Spendry un->un_lowervp = lowervp; 78*65934Spendry un->un_uppervp = uppervp; 79*65934Spendry *vpp = un->un_vnode; 80*65934Spendry return (0); 81*65934Spendry } 82*65934Spendry } 83*65934Spendry 84*65934Spendry /* 85*65934Spendry * otherwise lock the vp list while we call getnewvnode 86*65934Spendry * since that can block. 87*65934Spendry */ 88*65934Spendry if (unvplock & UN_LOCKED) { 89*65934Spendry unvplock |= UN_WANT; 90*65934Spendry sleep((caddr_t) &unvplock, PINOD); 91*65934Spendry goto loop; 92*65934Spendry } 93*65934Spendry unvplock |= UN_LOCKED; 94*65934Spendry 95*65934Spendry error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); 96*65934Spendry if (error) 97*65934Spendry goto out; 98*65934Spendry 99*65934Spendry MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), 100*65934Spendry M_TEMP, M_WAITOK); 101*65934Spendry 102*65934Spendry un = VTOUNION(*vpp); 103*65934Spendry un->un_next = 0; 104*65934Spendry un->un_dirvp = dvp; 105*65934Spendry un->un_uppervp = uppervp; 106*65934Spendry un->un_lowervp = lowervp; 107*65934Spendry un->un_vnode = *vpp; 108*65934Spendry un->un_flags = 0; 109*65934Spendry if (cnp) { 110*65934Spendry un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); 111*65934Spendry bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); 112*65934Spendry un->un_path[cnp->cn_namelen] = '\0'; 113*65934Spendry } else { 114*65934Spendry un->un_path = 0; 115*65934Spendry } 116*65934Spendry 117*65934Spendry #ifdef DIAGNOSTIC 118*65934Spendry un->un_pid = 0; 119*65934Spendry #endif 120*65934Spendry 121*65934Spendry /* add to union vnode list */ 122*65934Spendry for (pp = &unhead; *pp; pp = &(*pp)->un_next) 123*65934Spendry continue; 124*65934Spendry *pp = un; 125*65934Spendry 126*65934Spendry out: 127*65934Spendry unvplock &= ~UN_LOCKED; 128*65934Spendry 129*65934Spendry if (unvplock & UN_WANT) { 130*65934Spendry unvplock &= ~UN_WANT; 131*65934Spendry wakeup((caddr_t) &unvplock); 132*65934Spendry } 133*65934Spendry 134*65934Spendry if (un) 135*65934Spendry VOP_LOCK(UNIONTOV(un)); 136*65934Spendry 137*65934Spendry return (error); 138*65934Spendry } 139*65934Spendry 140*65934Spendry int 141*65934Spendry union_freevp(vp) 142*65934Spendry struct vnode *vp; 143*65934Spendry { 144*65934Spendry struct union_node **unpp; 145*65934Spendry struct union_node *un = VTOUNION(vp); 146*65934Spendry 147*65934Spendry for (unpp = &unhead; *unpp != 0; unpp = &(*unpp)->un_next) { 148*65934Spendry if (*unpp == un) { 149*65934Spendry *unpp = un->un_next; 150*65934Spendry break; 151*65934Spendry } 152*65934Spendry } 153*65934Spendry 154*65934Spendry if (un->un_path) 155*65934Spendry FREE(un->un_path, M_TEMP); 156*65934Spendry 157*65934Spendry FREE(vp->v_data, M_TEMP); 158*65934Spendry vp->v_data = 0; 159*65934Spendry return (0); 160*65934Spendry } 161