1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software donated to Berkeley by 6 * Jan-Simon Pendry. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)null_subr.c 8.4 (Berkeley) 01/21/94 11 * 12 * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 13 */ 14 15 #include <sys/param.h> 16 #include <sys/systm.h> 17 #include <sys/time.h> 18 #include <sys/types.h> 19 #include <sys/vnode.h> 20 #include <sys/mount.h> 21 #include <sys/namei.h> 22 #include <sys/malloc.h> 23 #include <miscfs/nullfs/null.h> 24 25 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 26 #define NNULLNODECACHE 16 27 #define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1)) 28 29 /* 30 * Null layer cache: 31 * Each cache entry holds a reference to the lower vnode 32 * along with a pointer to the alias vnode. When an 33 * entry is added the lower vnode is VREF'd. When the 34 * alias is removed the lower vnode is vrele'd. 35 */ 36 37 /* 38 * Cache head 39 */ 40 struct null_node_cache { 41 struct null_node *ac_forw; 42 struct null_node *ac_back; 43 }; 44 45 static struct null_node_cache null_node_cache[NNULLNODECACHE]; 46 47 /* 48 * Initialise cache headers 49 */ 50 nullfs_init() 51 { 52 struct null_node_cache *ac; 53 #ifdef NULLFS_DIAGNOSTIC 54 printf("nullfs_init\n"); /* printed during system boot */ 55 #endif 56 57 for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) 58 ac->ac_forw = ac->ac_back = (struct null_node *) ac; 59 } 60 61 /* 62 * Compute hash list for given lower vnode 63 */ 64 static struct null_node_cache * 65 null_node_hash(lowervp) 66 struct vnode *lowervp; 67 { 68 69 return (&null_node_cache[NULL_NHASH(lowervp)]); 70 } 71 72 /* 73 * Return a VREF'ed alias for lower vnode if already exists, else 0. 74 */ 75 static struct vnode * 76 null_node_find(mp, lowervp) 77 struct mount *mp; 78 struct vnode *lowervp; 79 { 80 struct null_node_cache *hd; 81 struct null_node *a; 82 struct vnode *vp; 83 84 /* 85 * Find hash base, and then search the (two-way) linked 86 * list looking for a null_node structure which is referencing 87 * the lower vnode. If found, the increment the null_node 88 * reference count (but NOT the lower vnode's VREF counter). 89 */ 90 hd = null_node_hash(lowervp); 91 loop: 92 for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 93 if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 94 vp = NULLTOV(a); 95 /* 96 * We need vget for the VXLOCK 97 * stuff, but we don't want to lock 98 * the lower node. 99 */ 100 if (vget(vp, 0)) { 101 printf ("null_node_find: vget failed.\n"); 102 goto loop; 103 }; 104 return (vp); 105 } 106 } 107 108 return NULL; 109 } 110 111 112 /* 113 * Make a new null_node node. 114 * Vp is the alias vnode, lofsvp is the lower vnode. 115 * Maintain a reference to (lowervp). 116 */ 117 static int 118 null_node_alloc(mp, lowervp, vpp) 119 struct mount *mp; 120 struct vnode *lowervp; 121 struct vnode **vpp; 122 { 123 struct null_node_cache *hd; 124 struct null_node *xp; 125 struct vnode *othervp, *vp; 126 int error; 127 128 if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp)) 129 return (error); 130 vp = *vpp; 131 132 MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 133 vp->v_type = lowervp->v_type; 134 xp->null_vnode = vp; 135 vp->v_data = xp; 136 xp->null_lowervp = lowervp; 137 /* 138 * Before we insert our new node onto the hash chains, 139 * check to see if someone else has beaten us to it. 140 * (We could have slept in MALLOC.) 141 */ 142 if (othervp = null_node_find(lowervp)) { 143 FREE(xp, M_TEMP); 144 vp->v_type = VBAD; /* node is discarded */ 145 vp->v_usecount = 0; /* XXX */ 146 *vpp = othervp; 147 return 0; 148 }; 149 VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 150 hd = null_node_hash(lowervp); 151 insque(xp, hd); 152 return 0; 153 } 154 155 156 /* 157 * Try to find an existing null_node vnode refering 158 * to it, otherwise make a new null_node vnode which 159 * contains a reference to the lower vnode. 160 */ 161 int 162 null_node_create(mp, lowervp, newvpp) 163 struct mount *mp; 164 struct vnode *lowervp; 165 struct vnode **newvpp; 166 { 167 struct vnode *aliasvp; 168 169 if (aliasvp = null_node_find(mp, lowervp)) { 170 /* 171 * null_node_find has taken another reference 172 * to the alias vnode. 173 */ 174 #ifdef NULLFS_DIAGNOSTIC 175 vprint("null_node_create: exists", NULLTOV(ap)); 176 #endif 177 /* VREF(aliasvp); --- done in null_node_find */ 178 } else { 179 int error; 180 181 /* 182 * Get new vnode. 183 */ 184 #ifdef NULLFS_DIAGNOSTIC 185 printf("null_node_create: create new alias vnode\n"); 186 #endif 187 188 /* 189 * Make new vnode reference the null_node. 190 */ 191 if (error = null_node_alloc(mp, lowervp, &aliasvp)) 192 return error; 193 194 /* 195 * aliasvp is already VREF'd by getnewvnode() 196 */ 197 } 198 199 vrele(lowervp); 200 201 #ifdef DIAGNOSTIC 202 if (lowervp->v_usecount < 1) { 203 /* Should never happen... */ 204 vprint ("null_node_create: alias "); 205 vprint ("null_node_create: lower "); 206 printf ("null_node_create: lower has 0 usecount.\n"); 207 panic ("null_node_create: lower has 0 usecount."); 208 }; 209 #endif 210 211 #ifdef NULLFS_DIAGNOSTIC 212 vprint("null_node_create: alias", aliasvp); 213 vprint("null_node_create: lower", lowervp); 214 #endif 215 216 *newvpp = aliasvp; 217 return (0); 218 } 219 #ifdef NULLFS_DIAGNOSTIC 220 struct vnode * 221 null_checkvp(vp, fil, lno) 222 struct vnode *vp; 223 char *fil; 224 int lno; 225 { 226 struct null_node *a = VTONULL(vp); 227 #ifdef notyet 228 /* 229 * Can't do this check because vop_reclaim runs 230 * with a funny vop vector. 231 */ 232 if (vp->v_op != null_vnodeop_p) { 233 printf ("null_checkvp: on non-null-node\n"); 234 while (null_checkvp_barrier) /*WAIT*/ ; 235 panic("null_checkvp"); 236 }; 237 #endif 238 if (a->null_lowervp == NULL) { 239 /* Should never happen */ 240 int i; u_long *p; 241 printf("vp = %x, ZERO ptr\n", vp); 242 for (p = (u_long *) a, i = 0; i < 8; i++) 243 printf(" %x", p[i]); 244 printf("\n"); 245 /* wait for debugger */ 246 while (null_checkvp_barrier) /*WAIT*/ ; 247 panic("null_checkvp"); 248 } 249 if (a->null_lowervp->v_usecount < 1) { 250 int i; u_long *p; 251 printf("vp = %x, unref'ed lowervp\n", vp); 252 for (p = (u_long *) a, i = 0; i < 8; i++) 253 printf(" %x", p[i]); 254 printf("\n"); 255 /* wait for debugger */ 256 while (null_checkvp_barrier) /*WAIT*/ ; 257 panic ("null with unref'ed lowervp"); 258 }; 259 #ifdef notyet 260 printf("null %x/%d -> %x/%d [%s, %d]\n", 261 NULLTOV(a), NULLTOV(a)->v_usecount, 262 a->null_lowervp, a->null_lowervp->v_usecount, 263 fil, lno); 264 #endif 265 return a->null_lowervp; 266 } 267 #endif 268