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