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: 3254938Sheideman * Each cache entry holds a reference to the lower vnode 3354751Sjohnh * along with a pointer to the alias vnode. When an 3454938Sheideman * entry is added the lower vnode is VREF'd. When the 3554938Sheideman * 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 /* 6354938Sheideman * Compute hash list for given lower vnode 6454751Sjohnh */ 6554754Sjohnh static struct null_node_cache * 6654938Sheideman null_node_hash(lowervp) 6754938Sheideman struct vnode *lowervp; 6854751Sjohnh { 69*54951Sheideman 7054938Sheideman return (&null_node_cache[NULL_NHASH(lowervp)]); 7154751Sjohnh } 7254751Sjohnh 7354751Sjohnh 7454766Sjohnh /* 7554938Sheideman * XXX - this should go elsewhere. 7654938Sheideman * Just like vget, but with no lock at the end. 7754751Sjohnh */ 7854938Sheideman int 7954938Sheideman vget_nolock(vp) 8054938Sheideman register struct vnode *vp; 8154938Sheideman { 8254938Sheideman extern struct vnode *vfreeh, **vfreet; 8354938Sheideman register struct vnode *vq; 8454938Sheideman 8554938Sheideman if (vp->v_flag & VXLOCK) { 8654938Sheideman vp->v_flag |= VXWANT; 8754938Sheideman sleep((caddr_t)vp, PINOD); 8854938Sheideman return (1); 8954938Sheideman } 9054938Sheideman if (vp->v_usecount == 0) { 9154938Sheideman if (vq = vp->v_freef) 9254938Sheideman vq->v_freeb = vp->v_freeb; 9354938Sheideman else 9454938Sheideman vfreet = vp->v_freeb; 9554938Sheideman *vp->v_freeb = vq; 9654938Sheideman vp->v_freef = NULL; 9754938Sheideman vp->v_freeb = NULL; 9854938Sheideman } 9954938Sheideman VREF(vp); 10054938Sheideman /* VOP_LOCK(vp); */ 10154938Sheideman return (0); 10254938Sheideman } 10354938Sheideman 10454938Sheideman 10554938Sheideman /* 10654938Sheideman * Return a VREF'ed alias for lower vnode if already exists, else 0. 10754938Sheideman */ 10854938Sheideman static struct vnode * 10954938Sheideman null_node_find(mp, lowervp) 11054751Sjohnh struct mount *mp; 11154938Sheideman struct vnode *lowervp; 11254751Sjohnh { 11354754Sjohnh struct null_node_cache *hd; 11454754Sjohnh struct null_node *a; 11554938Sheideman struct vnode *vp; 11654751Sjohnh 11754751Sjohnh /* 11854751Sjohnh * Find hash base, and then search the (two-way) linked 11954754Sjohnh * list looking for a null_node structure which is referencing 12054938Sheideman * the lower vnode. If found, the increment the null_node 12154938Sheideman * reference count (but NOT the lower vnode's VREF counter). 12254751Sjohnh */ 12354938Sheideman hd = null_node_hash(lowervp); 12454938Sheideman loop: 12554754Sjohnh for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 12654938Sheideman if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 12754938Sheideman vp = NULLTOV(a); 12854938Sheideman /* 129*54951Sheideman * We need vget for the VXLOCK 130*54951Sheideman * stuff, but we don't want to lock 131*54951Sheideman * the lower node. 13254938Sheideman */ 13354938Sheideman if (vget_nolock(vp)) { 13454938Sheideman printf ("null_node_find: vget failed.\n"); 13554938Sheideman goto loop; 13654938Sheideman }; 13754938Sheideman return (vp); 13854751Sjohnh } 13954751Sjohnh } 14054751Sjohnh 14154938Sheideman return NULL; 14254751Sjohnh } 14354751Sjohnh 14454938Sheideman 14554766Sjohnh /* 146*54951Sheideman * Make a new null_node node. 147*54951Sheideman * Vp is the alias vnode, lofsvp is the lower vnode. 148*54951Sheideman * Maintain a reference to (lowervp). 149*54951Sheideman */ 150*54951Sheideman static int 151*54951Sheideman null_node_alloc(mp, lowervp, vpp) 152*54951Sheideman struct mount *mp; 153*54951Sheideman struct vnode *lowervp; 154*54951Sheideman struct vnode **vpp; 155*54951Sheideman { 156*54951Sheideman struct null_node_cache *hd; 157*54951Sheideman struct null_node *xp; 158*54951Sheideman struct vnode *othervp, *vp; 159*54951Sheideman int error; 160*54951Sheideman 161*54951Sheideman if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, vpp)) 162*54951Sheideman return (error); /* XXX: VT_NULL above */ 163*54951Sheideman vp = *vpp; 164*54951Sheideman 165*54951Sheideman MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 166*54951Sheideman vp->v_type = lowervp->v_type; 167*54951Sheideman xp->null_vnode = vp; 168*54951Sheideman vp->v_data = xp; 169*54951Sheideman xp->null_lowervp = lowervp; 170*54951Sheideman /* 171*54951Sheideman * Before we insert our new node onto the hash chains, 172*54951Sheideman * check to see if someone else has beaten us to it. 173*54951Sheideman * (We could have slept in MALLOC.) 174*54951Sheideman */ 175*54951Sheideman if (othervp = null_node_find(lowervp)) { 176*54951Sheideman FREE(xp, M_TEMP); 177*54951Sheideman vp->v_type = VBAD; /* node is discarded */ 178*54951Sheideman vp->v_usecount = 0; /* XXX */ 179*54951Sheideman *vpp = othervp; 180*54951Sheideman return 0; 181*54951Sheideman }; 182*54951Sheideman VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 183*54951Sheideman hd = null_node_hash(lowervp); 184*54951Sheideman insque(xp, hd); 185*54951Sheideman return 0; 186*54951Sheideman } 187*54951Sheideman 188*54951Sheideman 189*54951Sheideman /* 19054766Sjohnh * Try to find an existing null_node vnode refering 19154766Sjohnh * to it, otherwise make a new null_node vnode which 19254938Sheideman * contains a reference to the lower vnode. 19354766Sjohnh */ 19454766Sjohnh int 19554938Sheideman null_node_create(mp, lowervp, newvpp) 19654751Sjohnh struct mount *mp; 19754938Sheideman struct vnode *lowervp; 19854751Sjohnh struct vnode **newvpp; 19954751Sjohnh { 20054751Sjohnh struct vnode *aliasvp; 20154751Sjohnh 20254938Sheideman if (aliasvp = null_node_find(mp, lowervp)) { 20354751Sjohnh /* 20454938Sheideman * null_node_find has taken another reference 20554938Sheideman * to the alias vnode. 20654751Sjohnh */ 20754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 20854938Sheideman vprint("null_node_create: exists", NULLTOV(ap)); 20954751Sjohnh #endif 21054938Sheideman /* VREF(aliasvp); --- done in null_node_find */ 21154751Sjohnh } else { 21254751Sjohnh int error; 21354751Sjohnh 21454751Sjohnh /* 21554751Sjohnh * Get new vnode. 21654751Sjohnh */ 21754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21854938Sheideman printf("null_node_create: create new alias vnode\n"); 21954751Sjohnh #endif 22054751Sjohnh 22154751Sjohnh /* 22254754Sjohnh * Make new vnode reference the null_node. 22354751Sjohnh */ 224*54951Sheideman if (error = null_node_alloc(mp, lowervp, &aliasvp)) 225*54951Sheideman return error; 22654751Sjohnh 22754751Sjohnh /* 22854751Sjohnh * aliasvp is already VREF'd by getnewvnode() 22954751Sjohnh */ 23054751Sjohnh } 23154751Sjohnh 23254938Sheideman vrele(lowervp); 23354751Sjohnh 234*54951Sheideman #ifdef DIAGNOSTIC 23554938Sheideman if (lowervp->v_usecount < 1) { 236*54951Sheideman /* Should never happen... */ 23754938Sheideman vprint ("null_node_create: alias "); 23854938Sheideman vprint ("null_node_create: lower "); 23954938Sheideman printf ("null_node_create: lower has 0 usecount.\n"); 24054938Sheideman panic ("null_node_create: lower has 0 usecount."); 24154938Sheideman }; 242*54951Sheideman #endif 24354938Sheideman 24454754Sjohnh #ifdef NULLFS_DIAGNOSTIC 24554938Sheideman vprint("null_node_create: alias", aliasvp); 24654938Sheideman vprint("null_node_create: lower", lowervp); 24754751Sjohnh #endif 24854751Sjohnh 24954751Sjohnh *newvpp = aliasvp; 25054751Sjohnh return (0); 25154751Sjohnh } 25254754Sjohnh #ifdef NULLFS_DIAGNOSTIC 25354751Sjohnh struct vnode * 25454754Sjohnh null_checkvp(vp, fil, lno) 25554751Sjohnh struct vnode *vp; 25654751Sjohnh char *fil; 25754751Sjohnh int lno; 25854751Sjohnh { 25954938Sheideman struct null_node *a = VTONULL(vp); 26054938Sheideman #if 0 26154938Sheideman /* 26254938Sheideman * Can't do this check because vop_reclaim runs 26354938Sheideman * with a funny vop vector. 26454938Sheideman */ 26554938Sheideman if (vp->v_op != null_vnodeop_p) { 26654938Sheideman printf ("null_checkvp: on non-null-node\n"); 26754938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 26854938Sheideman panic("null_checkvp"); 26954938Sheideman }; 27054938Sheideman #endif 27154938Sheideman if (a->null_lowervp == NULL) { 27254766Sjohnh /* Should never happen */ 27354751Sjohnh int i; u_long *p; 27454751Sjohnh printf("vp = %x, ZERO ptr\n", vp); 27554751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++) 27654751Sjohnh printf(" %x", p[i]); 27754751Sjohnh printf("\n"); 27854938Sheideman /* wait for debugger */ 27954938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 28054754Sjohnh panic("null_checkvp"); 28154751Sjohnh } 28254938Sheideman if (a->null_lowervp->v_usecount < 1) { 28354938Sheideman int i; u_long *p; 28454938Sheideman printf("vp = %x, unref'ed lowervp\n", vp); 28554938Sheideman for (p = (u_long *) a, i = 0; i < 8; i++) 28654938Sheideman printf(" %x", p[i]); 28754938Sheideman printf("\n"); 28854938Sheideman /* wait for debugger */ 28954938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 29054938Sheideman panic ("null with unref'ed lowervp"); 29154938Sheideman }; 29254938Sheideman #if 0 29354938Sheideman printf("null %x/%d -> %x/%d [%s, %d]\n", 29454938Sheideman NULLTOV(a), NULLTOV(a)->v_usecount, 29554766Sjohnh a->null_lowervp, a->null_lowervp->v_usecount, 29654751Sjohnh fil, lno); 29754938Sheideman #endif 29854754Sjohnh return a->null_lowervp; 29954751Sjohnh } 30054751Sjohnh #endif 301*54951Sheideman 302*54951Sheideman 303