1 /* 2 * Copyright (c) 1992 The Regents of the University of California 3 * Copyright (c) 1990, 1992 Jan-Simon Pendry 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 * @(#)lofs_subr.c 1.2 (Berkeley) 6/18/92 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 <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 return (&null_node_cache[NULL_NHASH(lowervp)]); 70 } 71 72 /* 73 * Make a new null_node node. 74 * Vp is the alias vnode, lofsvp is the lower vnode. 75 * Maintain a reference to (lowervp). 76 */ 77 static void 78 null_node_alloc(vp, lowervp) 79 struct vnode *vp; 80 struct vnode *lowervp; 81 { 82 struct null_node_cache *hd; 83 struct null_node *a; 84 85 #ifdef NULLFS_DIAGNOSTIC 86 printf("null_node_alloc(%x, %x)\n", vp, lowervp); 87 #endif 88 89 MALLOC(a, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 90 vp->v_type = lowervp->v_type; 91 a->null_vnode = vp; 92 vp->v_data = a; 93 VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 94 a->null_lowervp = lowervp; 95 hd = null_node_hash(lowervp); 96 insque(a, hd); 97 98 #ifdef NULLFS_DIAGNOSTIC 99 vprint("null_node_alloc vp", vp); 100 vprint("null_node_alloc lowervp", lowervp); 101 #endif 102 } 103 104 #ifdef NULLFS_DIAGNOSTIC 105 /* 106 * NEEDSWORK: The ability to set lowervp to null here 107 * implies that one can never count on lowervp staying null 108 * (even if vp is locked). This seems quite bad. Think 109 * about these things. 110 */ 111 void 112 null_node_flushmp (mp) 113 struct mount *mp; 114 { 115 struct null_node_cache *ac; 116 int i = 0; 117 struct null_node *roota; 118 119 printf("null_node_flushmp (%x)\n", mp); 120 121 roota = VTONULL(MOUNTTONULLMOUNT(mp)->nullm_rootvp); 122 123 for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) { 124 struct null_node *a = ac->ac_forw; 125 while (a != (struct null_node *) ac) { 126 if (a != roota && NULLTOV(a)->v_mount == mp) { 127 struct vnode *vp = a->null_lowervp; 128 if (vp) { 129 a->null_lowervp = 0; 130 vprint("null_flushmp: would vrele", vp); 131 /*vrele(vp);*/ 132 i++; 133 } 134 } 135 a = a->null_forw; 136 } 137 } 138 if (i > 0) 139 printf("null_node: vrele'd %d aliases\n", i); 140 } 141 #endif 142 143 /* 144 * XXX - this should go elsewhere. 145 * Just like vget, but with no lock at the end. 146 */ 147 int 148 vget_nolock(vp) 149 register struct vnode *vp; 150 { 151 extern struct vnode *vfreeh, **vfreet; 152 register struct vnode *vq; 153 154 if (vp->v_flag & VXLOCK) { 155 vp->v_flag |= VXWANT; 156 sleep((caddr_t)vp, PINOD); 157 return (1); 158 } 159 if (vp->v_usecount == 0) { 160 if (vq = vp->v_freef) 161 vq->v_freeb = vp->v_freeb; 162 else 163 vfreet = vp->v_freeb; 164 *vp->v_freeb = vq; 165 vp->v_freef = NULL; 166 vp->v_freeb = NULL; 167 } 168 VREF(vp); 169 /* VOP_LOCK(vp); */ 170 return (0); 171 } 172 173 174 /* 175 * Return a VREF'ed alias for lower vnode if already exists, else 0. 176 */ 177 static struct vnode * 178 null_node_find(mp, lowervp) 179 struct mount *mp; 180 struct vnode *lowervp; 181 { 182 struct null_node_cache *hd; 183 struct null_node *a; 184 struct vnode *vp; 185 186 #ifdef NULLFS_DIAGNOSTIC 187 printf("null_node_find(mp = %x, lower = %x)\n", mp, lowervp); 188 #endif 189 190 /* 191 * Find hash base, and then search the (two-way) linked 192 * list looking for a null_node structure which is referencing 193 * the lower vnode. If found, the increment the null_node 194 * reference count (but NOT the lower vnode's VREF counter). 195 */ 196 hd = null_node_hash(lowervp); 197 loop: 198 for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 199 if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 200 #ifdef NULLFS_DIAGNOSTIC 201 printf("null_node_find(%x): found (%x,%x)->%x\n", 202 lowervp, mp, NULLTOV(a), lowervp); 203 #endif 204 vp = NULLTOV(a); 205 /* 206 * NEEDSWORK: Don't call the normal vget, 207 * it will do a VOP_LOCK which is bypassed 208 * and will lock against ourselves. 209 * Unfortunately, we need vget for the VXLOCK 210 * stuff. 211 */ 212 if (vget_nolock(vp)) { 213 printf ("null_node_find: vget failed.\n"); 214 goto loop; 215 }; 216 return (vp); 217 } 218 } 219 220 #ifdef NULLFS_DIAGNOSTIC 221 printf("null_node_find(%x, %x): NOT found\n", mp, lowervp); 222 #endif 223 224 return NULL; 225 } 226 227 #if 1 228 int null_node_create_barrier = 1; 229 #endif 230 231 /* 232 * Try to find an existing null_node vnode refering 233 * to it, otherwise make a new null_node vnode which 234 * contains a reference to the lower vnode. 235 */ 236 int 237 null_node_create(mp, lowervp, newvpp) 238 struct mount *mp; 239 struct vnode *lowervp; 240 struct vnode **newvpp; 241 { 242 struct vnode *aliasvp; 243 244 if (aliasvp = null_node_find(mp, lowervp)) { 245 /* 246 * null_node_find has taken another reference 247 * to the alias vnode. 248 */ 249 #ifdef NULLFS_DIAGNOSTIC 250 vprint("null_node_create: exists", NULLTOV(ap)); 251 #endif 252 /* VREF(aliasvp); --- done in null_node_find */ 253 } else { 254 int error; 255 256 /* 257 * Get new vnode. 258 */ 259 #ifdef NULLFS_DIAGNOSTIC 260 printf("null_node_create: create new alias vnode\n"); 261 #endif 262 if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp)) 263 return (error); /* XXX: VT_NULL above */ 264 265 /* 266 * Make new vnode reference the null_node. 267 */ 268 null_node_alloc(aliasvp, lowervp); 269 270 /* 271 * aliasvp is already VREF'd by getnewvnode() 272 */ 273 } 274 275 vrele(lowervp); 276 277 if (lowervp->v_usecount < 1) { 278 vprint ("null_node_create: alias "); 279 vprint ("null_node_create: lower "); 280 printf ("null_node_create: lower has 0 usecount.\n"); 281 while (null_node_create_barrier) /* wait */ ; 282 panic ("null_node_create: lower has 0 usecount."); 283 }; 284 285 #ifdef NULLFS_DIAGNOSTIC 286 vprint("null_node_create: alias", aliasvp); 287 vprint("null_node_create: lower", lowervp); 288 #endif 289 290 *newvpp = aliasvp; 291 return (0); 292 } 293 #ifdef NULLFS_DIAGNOSTIC 294 int null_checkvp_barrier = 1; 295 struct vnode * 296 null_checkvp(vp, fil, lno) 297 struct vnode *vp; 298 char *fil; 299 int lno; 300 { 301 struct null_node *a = VTONULL(vp); 302 #if 0 303 /* 304 * Can't do this check because vop_reclaim runs 305 * with a funny vop vector. 306 */ 307 if (vp->v_op != null_vnodeop_p) { 308 printf ("null_checkvp: on non-null-node\n"); 309 while (null_checkvp_barrier) /*WAIT*/ ; 310 panic("null_checkvp"); 311 }; 312 #endif 313 if (a->null_lowervp == NULL) { 314 /* Should never happen */ 315 int i; u_long *p; 316 printf("vp = %x, ZERO ptr\n", vp); 317 for (p = (u_long *) a, i = 0; i < 8; i++) 318 printf(" %x", p[i]); 319 printf("\n"); 320 /* wait for debugger */ 321 while (null_checkvp_barrier) /*WAIT*/ ; 322 panic("null_checkvp"); 323 } 324 if (a->null_lowervp->v_usecount < 1) { 325 int i; u_long *p; 326 printf("vp = %x, unref'ed lowervp\n", vp); 327 for (p = (u_long *) a, i = 0; i < 8; i++) 328 printf(" %x", p[i]); 329 printf("\n"); 330 /* wait for debugger */ 331 while (null_checkvp_barrier) /*WAIT*/ ; 332 panic ("null with unref'ed lowervp"); 333 }; 334 #if 0 335 printf("null %x/%d -> %x/%d [%s, %d]\n", 336 NULLTOV(a), NULLTOV(a)->v_usecount, 337 a->null_lowervp, a->null_lowervp->v_usecount, 338 fil, lno); 339 #endif 340 return a->null_lowervp; 341 } 342 #endif 343