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