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 a->null_isinactive = 0; 217 return (vp); 218 } 219 } 220 221 #ifdef NULLFS_DIAGNOSTIC 222 printf("null_node_find(%x, %x): NOT found\n", mp, lowervp); 223 #endif 224 225 return NULL; 226 } 227 228 #if 1 229 int null_node_create_barrier = 1; 230 #endif 231 232 /* 233 * Try to find an existing null_node vnode refering 234 * to it, otherwise make a new null_node vnode which 235 * contains a reference to the lower vnode. 236 */ 237 int 238 null_node_create(mp, lowervp, newvpp) 239 struct mount *mp; 240 struct vnode *lowervp; 241 struct vnode **newvpp; 242 { 243 struct vnode *aliasvp; 244 245 if (aliasvp = null_node_find(mp, lowervp)) { 246 /* 247 * null_node_find has taken another reference 248 * to the alias vnode. 249 */ 250 #ifdef NULLFS_DIAGNOSTIC 251 vprint("null_node_create: exists", NULLTOV(ap)); 252 #endif 253 /* VREF(aliasvp); --- done in null_node_find */ 254 } else { 255 int error; 256 257 /* 258 * Get new vnode. 259 */ 260 #ifdef NULLFS_DIAGNOSTIC 261 printf("null_node_create: create new alias vnode\n"); 262 #endif 263 if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp)) 264 return (error); /* XXX: VT_NULL above */ 265 266 /* 267 * Make new vnode reference the null_node. 268 */ 269 null_node_alloc(aliasvp, lowervp); 270 271 /* 272 * aliasvp is already VREF'd by getnewvnode() 273 */ 274 } 275 276 vrele(lowervp); 277 278 if (lowervp->v_usecount < 1) { 279 vprint ("null_node_create: alias "); 280 vprint ("null_node_create: lower "); 281 printf ("null_node_create: lower has 0 usecount.\n"); 282 while (null_node_create_barrier) /* wait */ ; 283 panic ("null_node_create: lower has 0 usecount."); 284 }; 285 286 #ifdef NULLFS_DIAGNOSTIC 287 vprint("null_node_create: alias", aliasvp); 288 vprint("null_node_create: lower", lowervp); 289 #endif 290 291 *newvpp = aliasvp; 292 return (0); 293 } 294 #ifdef NULLFS_DIAGNOSTIC 295 int null_checkvp_barrier = 1; 296 struct vnode * 297 null_checkvp(vp, fil, lno) 298 struct vnode *vp; 299 char *fil; 300 int lno; 301 { 302 struct null_node *a = VTONULL(vp); 303 #if 0 304 /* 305 * Can't do this check because vop_reclaim runs 306 * with a funny vop vector. 307 */ 308 if (vp->v_op != null_vnodeop_p) { 309 printf ("null_checkvp: on non-null-node\n"); 310 while (null_checkvp_barrier) /*WAIT*/ ; 311 panic("null_checkvp"); 312 }; 313 #endif 314 if (a->null_lowervp == NULL) { 315 /* Should never happen */ 316 int i; u_long *p; 317 printf("vp = %x, ZERO ptr\n", vp); 318 for (p = (u_long *) a, i = 0; i < 8; i++) 319 printf(" %x", p[i]); 320 printf("\n"); 321 /* wait for debugger */ 322 while (null_checkvp_barrier) /*WAIT*/ ; 323 panic("null_checkvp"); 324 } 325 if (a->null_lowervp->v_usecount < 1) { 326 int i; u_long *p; 327 printf("vp = %x, unref'ed lowervp\n", vp); 328 for (p = (u_long *) a, i = 0; i < 8; i++) 329 printf(" %x", p[i]); 330 printf("\n"); 331 /* wait for debugger */ 332 while (null_checkvp_barrier) /*WAIT*/ ; 333 panic ("null with unref'ed lowervp"); 334 }; 335 #if 0 336 printf("null %x/%d -> %x/%d [%s, %d]\n", 337 NULLTOV(a), NULLTOV(a)->v_usecount, 338 a->null_lowervp, a->null_lowervp->v_usecount, 339 fil, lno); 340 #endif 341 return a->null_lowervp; 342 } 343 #endif 344