154751Sjohnh /* 254751Sjohnh * Copyright (c) 1992 The Regents of the University of California 354751Sjohnh * Copyright (c) 1990, 1992 Jan-Simon Pendry 454751Sjohnh * All rights reserved. 554751Sjohnh * 654751Sjohnh * This code is derived from software donated to Berkeley by 754751Sjohnh * Jan-Simon Pendry. 854751Sjohnh * 954751Sjohnh * %sccs.include.redist.c% 1054751Sjohnh * 1154751Sjohnh * @(#)lofs_subr.c 1.2 (Berkeley) 6/18/92 1254751Sjohnh * 1354751Sjohnh * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 1454751Sjohnh */ 1554751Sjohnh 1654751Sjohnh #include <sys/param.h> 1754751Sjohnh #include <sys/systm.h> 1854751Sjohnh #include <sys/time.h> 1954751Sjohnh #include <sys/types.h> 2054751Sjohnh #include <sys/vnode.h> 2154751Sjohnh #include <sys/mount.h> 2254751Sjohnh #include <sys/namei.h> 2354751Sjohnh #include <sys/malloc.h> 2454893Sheideman #include <nullfs/null.h> 2554751Sjohnh 2654751Sjohnh #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 2754754Sjohnh #define NNULLNODECACHE 16 2854754Sjohnh #define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1)) 2954751Sjohnh 3054751Sjohnh /* 3154754Sjohnh * Null layer cache: 32*54938Sheideman * Each cache entry holds a reference to the lower vnode 3354751Sjohnh * along with a pointer to the alias vnode. When an 34*54938Sheideman * entry is added the lower vnode is VREF'd. When the 35*54938Sheideman * alias is removed the lower vnode is vrele'd. 3654751Sjohnh */ 3754751Sjohnh 3854751Sjohnh /* 3954751Sjohnh * Cache head 4054751Sjohnh */ 4154754Sjohnh struct null_node_cache { 4254754Sjohnh struct null_node *ac_forw; 4354754Sjohnh struct null_node *ac_back; 4454751Sjohnh }; 4554751Sjohnh 4654754Sjohnh static struct null_node_cache null_node_cache[NNULLNODECACHE]; 4754751Sjohnh 4854751Sjohnh /* 4954751Sjohnh * Initialise cache headers 5054751Sjohnh */ 5154754Sjohnh nullfs_init() 5254751Sjohnh { 5354754Sjohnh struct null_node_cache *ac; 5454754Sjohnh #ifdef NULLFS_DIAGNOSTIC 5554754Sjohnh printf("nullfs_init\n"); /* printed during system boot */ 5654751Sjohnh #endif 5754751Sjohnh 5854754Sjohnh for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) 5954754Sjohnh ac->ac_forw = ac->ac_back = (struct null_node *) ac; 6054751Sjohnh } 6154751Sjohnh 6254751Sjohnh /* 63*54938Sheideman * Compute hash list for given lower vnode 6454751Sjohnh */ 6554754Sjohnh static struct null_node_cache * 66*54938Sheideman null_node_hash(lowervp) 67*54938Sheideman struct vnode *lowervp; 6854751Sjohnh { 69*54938Sheideman return (&null_node_cache[NULL_NHASH(lowervp)]); 7054751Sjohnh } 7154751Sjohnh 7254751Sjohnh /* 7354754Sjohnh * Make a new null_node node. 74*54938Sheideman * Vp is the alias vnode, lofsvp is the lower vnode. 75*54938Sheideman * Maintain a reference to (lowervp). 7654751Sjohnh */ 7754751Sjohnh static void 78*54938Sheideman null_node_alloc(vp, lowervp) 7954751Sjohnh struct vnode *vp; 80*54938Sheideman struct vnode *lowervp; 8154751Sjohnh { 8254754Sjohnh struct null_node_cache *hd; 8354754Sjohnh struct null_node *a; 8454751Sjohnh 8554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 86*54938Sheideman printf("null_node_alloc(%x, %x)\n", vp, lowervp); 8754751Sjohnh #endif 8854751Sjohnh 8954754Sjohnh MALLOC(a, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 90*54938Sheideman vp->v_type = lowervp->v_type; 9154754Sjohnh a->null_vnode = vp; 9254751Sjohnh vp->v_data = a; 93*54938Sheideman VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 94*54938Sheideman a->null_lowervp = lowervp; 95*54938Sheideman hd = null_node_hash(lowervp); 9654751Sjohnh insque(a, hd); 9754751Sjohnh 9854754Sjohnh #ifdef NULLFS_DIAGNOSTIC 99*54938Sheideman vprint("null_node_alloc vp", vp); 100*54938Sheideman vprint("null_node_alloc lowervp", lowervp); 10154751Sjohnh #endif 10254751Sjohnh } 10354751Sjohnh 10454754Sjohnh #ifdef NULLFS_DIAGNOSTIC 10554766Sjohnh /* 10654766Sjohnh * NEEDSWORK: The ability to set lowervp to null here 10754766Sjohnh * implies that one can never count on lowervp staying null 10854766Sjohnh * (even if vp is locked). This seems quite bad. Think 10954766Sjohnh * about these things. 11054766Sjohnh */ 11154751Sjohnh void 11254754Sjohnh null_node_flushmp (mp) 11354751Sjohnh struct mount *mp; 11454751Sjohnh { 11554754Sjohnh struct null_node_cache *ac; 11654751Sjohnh int i = 0; 11754754Sjohnh struct null_node *roota; 11854751Sjohnh 11954754Sjohnh printf("null_node_flushmp (%x)\n", mp); 12054751Sjohnh 121*54938Sheideman roota = VTONULL(MOUNTTONULLMOUNT(mp)->nullm_rootvp); 12254751Sjohnh 12354754Sjohnh for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) { 12454754Sjohnh struct null_node *a = ac->ac_forw; 12554754Sjohnh while (a != (struct null_node *) ac) { 126*54938Sheideman if (a != roota && NULLTOV(a)->v_mount == mp) { 12754754Sjohnh struct vnode *vp = a->null_lowervp; 12854751Sjohnh if (vp) { 12954754Sjohnh a->null_lowervp = 0; 130*54938Sheideman vprint("null_flushmp: would vrele", vp); 13154751Sjohnh /*vrele(vp);*/ 13254751Sjohnh i++; 13354751Sjohnh } 13454751Sjohnh } 13554754Sjohnh a = a->null_forw; 13654751Sjohnh } 13754751Sjohnh } 13854751Sjohnh if (i > 0) 13954754Sjohnh printf("null_node: vrele'd %d aliases\n", i); 14054751Sjohnh } 14154751Sjohnh #endif 14254751Sjohnh 14354751Sjohnh /* 144*54938Sheideman * XXX - this should go elsewhere. 145*54938Sheideman * Just like vget, but with no lock at the end. 14654751Sjohnh */ 147*54938Sheideman int 148*54938Sheideman vget_nolock(vp) 149*54938Sheideman register struct vnode *vp; 150*54938Sheideman { 151*54938Sheideman extern struct vnode *vfreeh, **vfreet; 152*54938Sheideman register struct vnode *vq; 153*54938Sheideman 154*54938Sheideman if (vp->v_flag & VXLOCK) { 155*54938Sheideman vp->v_flag |= VXWANT; 156*54938Sheideman sleep((caddr_t)vp, PINOD); 157*54938Sheideman return (1); 158*54938Sheideman } 159*54938Sheideman if (vp->v_usecount == 0) { 160*54938Sheideman if (vq = vp->v_freef) 161*54938Sheideman vq->v_freeb = vp->v_freeb; 162*54938Sheideman else 163*54938Sheideman vfreet = vp->v_freeb; 164*54938Sheideman *vp->v_freeb = vq; 165*54938Sheideman vp->v_freef = NULL; 166*54938Sheideman vp->v_freeb = NULL; 167*54938Sheideman } 168*54938Sheideman VREF(vp); 169*54938Sheideman /* VOP_LOCK(vp); */ 170*54938Sheideman return (0); 171*54938Sheideman } 172*54938Sheideman 173*54938Sheideman 174*54938Sheideman /* 175*54938Sheideman * Return a VREF'ed alias for lower vnode if already exists, else 0. 176*54938Sheideman */ 177*54938Sheideman static struct vnode * 178*54938Sheideman null_node_find(mp, lowervp) 17954751Sjohnh struct mount *mp; 180*54938Sheideman struct vnode *lowervp; 18154751Sjohnh { 18254754Sjohnh struct null_node_cache *hd; 18354754Sjohnh struct null_node *a; 184*54938Sheideman struct vnode *vp; 18554751Sjohnh 18654754Sjohnh #ifdef NULLFS_DIAGNOSTIC 187*54938Sheideman printf("null_node_find(mp = %x, lower = %x)\n", mp, lowervp); 18854751Sjohnh #endif 18954751Sjohnh 19054751Sjohnh /* 19154751Sjohnh * Find hash base, and then search the (two-way) linked 19254754Sjohnh * list looking for a null_node structure which is referencing 193*54938Sheideman * the lower vnode. If found, the increment the null_node 194*54938Sheideman * reference count (but NOT the lower vnode's VREF counter). 19554751Sjohnh */ 196*54938Sheideman hd = null_node_hash(lowervp); 197*54938Sheideman loop: 19854754Sjohnh for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 199*54938Sheideman if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 20054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 20154754Sjohnh printf("null_node_find(%x): found (%x,%x)->%x\n", 202*54938Sheideman lowervp, mp, NULLTOV(a), lowervp); 20354751Sjohnh #endif 204*54938Sheideman vp = NULLTOV(a); 205*54938Sheideman /* 206*54938Sheideman * NEEDSWORK: Don't call the normal vget, 207*54938Sheideman * it will do a VOP_LOCK which is bypassed 208*54938Sheideman * and will lock against ourselves. 209*54938Sheideman * Unfortunately, we need vget for the VXLOCK 210*54938Sheideman * stuff. 211*54938Sheideman */ 212*54938Sheideman if (vget_nolock(vp)) { 213*54938Sheideman printf ("null_node_find: vget failed.\n"); 214*54938Sheideman goto loop; 215*54938Sheideman }; 216*54938Sheideman return (vp); 21754751Sjohnh } 21854751Sjohnh } 21954751Sjohnh 22054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 221*54938Sheideman printf("null_node_find(%x, %x): NOT found\n", mp, lowervp); 22254751Sjohnh #endif 22354751Sjohnh 224*54938Sheideman return NULL; 22554751Sjohnh } 22654751Sjohnh 227*54938Sheideman #if 1 228*54938Sheideman int null_node_create_barrier = 1; 229*54938Sheideman #endif 230*54938Sheideman 23154766Sjohnh /* 23254766Sjohnh * Try to find an existing null_node vnode refering 23354766Sjohnh * to it, otherwise make a new null_node vnode which 234*54938Sheideman * contains a reference to the lower vnode. 23554766Sjohnh */ 23654766Sjohnh int 237*54938Sheideman null_node_create(mp, lowervp, newvpp) 23854751Sjohnh struct mount *mp; 239*54938Sheideman struct vnode *lowervp; 24054751Sjohnh struct vnode **newvpp; 24154751Sjohnh { 24254751Sjohnh struct vnode *aliasvp; 24354751Sjohnh 244*54938Sheideman if (aliasvp = null_node_find(mp, lowervp)) { 24554751Sjohnh /* 246*54938Sheideman * null_node_find has taken another reference 247*54938Sheideman * to the alias vnode. 24854751Sjohnh */ 24954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 250*54938Sheideman vprint("null_node_create: exists", NULLTOV(ap)); 25154751Sjohnh #endif 252*54938Sheideman /* VREF(aliasvp); --- done in null_node_find */ 25354751Sjohnh } else { 25454751Sjohnh int error; 25554751Sjohnh 25654751Sjohnh /* 25754751Sjohnh * Get new vnode. 25854751Sjohnh */ 25954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 260*54938Sheideman printf("null_node_create: create new alias vnode\n"); 26154751Sjohnh #endif 26254754Sjohnh if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp)) 263*54938Sheideman return (error); /* XXX: VT_NULL above */ 26454751Sjohnh 26554751Sjohnh /* 26654754Sjohnh * Make new vnode reference the null_node. 26754751Sjohnh */ 268*54938Sheideman null_node_alloc(aliasvp, lowervp); 26954751Sjohnh 27054751Sjohnh /* 27154751Sjohnh * aliasvp is already VREF'd by getnewvnode() 27254751Sjohnh */ 27354751Sjohnh } 27454751Sjohnh 275*54938Sheideman vrele(lowervp); 27654751Sjohnh 277*54938Sheideman if (lowervp->v_usecount < 1) { 278*54938Sheideman vprint ("null_node_create: alias "); 279*54938Sheideman vprint ("null_node_create: lower "); 280*54938Sheideman printf ("null_node_create: lower has 0 usecount.\n"); 281*54938Sheideman while (null_node_create_barrier) /* wait */ ; 282*54938Sheideman panic ("null_node_create: lower has 0 usecount."); 283*54938Sheideman }; 284*54938Sheideman 28554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 286*54938Sheideman vprint("null_node_create: alias", aliasvp); 287*54938Sheideman vprint("null_node_create: lower", lowervp); 28854751Sjohnh #endif 28954751Sjohnh 29054751Sjohnh *newvpp = aliasvp; 29154751Sjohnh return (0); 29254751Sjohnh } 29354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 294*54938Sheideman int null_checkvp_barrier = 1; 29554751Sjohnh struct vnode * 29654754Sjohnh null_checkvp(vp, fil, lno) 29754751Sjohnh struct vnode *vp; 29854751Sjohnh char *fil; 29954751Sjohnh int lno; 30054751Sjohnh { 301*54938Sheideman struct null_node *a = VTONULL(vp); 302*54938Sheideman #if 0 303*54938Sheideman /* 304*54938Sheideman * Can't do this check because vop_reclaim runs 305*54938Sheideman * with a funny vop vector. 306*54938Sheideman */ 307*54938Sheideman if (vp->v_op != null_vnodeop_p) { 308*54938Sheideman printf ("null_checkvp: on non-null-node\n"); 309*54938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 310*54938Sheideman panic("null_checkvp"); 311*54938Sheideman }; 312*54938Sheideman #endif 313*54938Sheideman if (a->null_lowervp == NULL) { 31454766Sjohnh /* Should never happen */ 31554751Sjohnh int i; u_long *p; 31654751Sjohnh printf("vp = %x, ZERO ptr\n", vp); 31754751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++) 31854751Sjohnh printf(" %x", p[i]); 31954751Sjohnh printf("\n"); 320*54938Sheideman /* wait for debugger */ 321*54938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 32254754Sjohnh panic("null_checkvp"); 32354751Sjohnh } 324*54938Sheideman if (a->null_lowervp->v_usecount < 1) { 325*54938Sheideman int i; u_long *p; 326*54938Sheideman printf("vp = %x, unref'ed lowervp\n", vp); 327*54938Sheideman for (p = (u_long *) a, i = 0; i < 8; i++) 328*54938Sheideman printf(" %x", p[i]); 329*54938Sheideman printf("\n"); 330*54938Sheideman /* wait for debugger */ 331*54938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 332*54938Sheideman panic ("null with unref'ed lowervp"); 333*54938Sheideman }; 334*54938Sheideman #if 0 335*54938Sheideman printf("null %x/%d -> %x/%d [%s, %d]\n", 336*54938Sheideman NULLTOV(a), NULLTOV(a)->v_usecount, 33754766Sjohnh a->null_lowervp, a->null_lowervp->v_usecount, 33854751Sjohnh fil, lno); 339*54938Sheideman #endif 34054754Sjohnh return a->null_lowervp; 34154751Sjohnh } 34254751Sjohnh #endif 343