154751Sjohnh /* 263245Sbostic * Copyright (c) 1992, 1993 363245Sbostic * The Regents of the University of California. All rights reserved. 454751Sjohnh * 554751Sjohnh * This code is derived from software donated to Berkeley by 654751Sjohnh * Jan-Simon Pendry. 754751Sjohnh * 854751Sjohnh * %sccs.include.redist.c% 954751Sjohnh * 10*67398Smkm * @(#)null_subr.c 8.5 (Berkeley) 06/15/94 1154751Sjohnh * 1254751Sjohnh * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 1354751Sjohnh */ 1454751Sjohnh 1554751Sjohnh #include <sys/param.h> 1654751Sjohnh #include <sys/systm.h> 1754751Sjohnh #include <sys/time.h> 1854751Sjohnh #include <sys/types.h> 1954751Sjohnh #include <sys/vnode.h> 2054751Sjohnh #include <sys/mount.h> 2154751Sjohnh #include <sys/namei.h> 2254751Sjohnh #include <sys/malloc.h> 2355025Smckusick #include <miscfs/nullfs/null.h> 2454751Sjohnh 2554751Sjohnh #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 2654754Sjohnh #define NNULLNODECACHE 16 2754754Sjohnh #define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1)) 2854751Sjohnh 2954751Sjohnh /* 3054754Sjohnh * Null layer cache: 3154938Sheideman * Each cache entry holds a reference to the lower vnode 3254751Sjohnh * along with a pointer to the alias vnode. When an 3354938Sheideman * entry is added the lower vnode is VREF'd. When the 3454938Sheideman * alias is removed the lower vnode is vrele'd. 3554751Sjohnh */ 3654751Sjohnh 3754751Sjohnh /* 3854751Sjohnh * Cache head 3954751Sjohnh */ 4054754Sjohnh struct null_node_cache { 4154754Sjohnh struct null_node *ac_forw; 4254754Sjohnh struct null_node *ac_back; 4354751Sjohnh }; 4454751Sjohnh 4554754Sjohnh static struct null_node_cache null_node_cache[NNULLNODECACHE]; 4654751Sjohnh 4754751Sjohnh /* 4854751Sjohnh * Initialise cache headers 4954751Sjohnh */ 5054754Sjohnh nullfs_init() 5154751Sjohnh { 5254754Sjohnh struct null_node_cache *ac; 5354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 5454754Sjohnh printf("nullfs_init\n"); /* printed during system boot */ 5554751Sjohnh #endif 5654751Sjohnh 5754754Sjohnh for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) 5854754Sjohnh ac->ac_forw = ac->ac_back = (struct null_node *) ac; 5954751Sjohnh } 6054751Sjohnh 6154751Sjohnh /* 6254938Sheideman * Compute hash list for given lower vnode 6354751Sjohnh */ 6454754Sjohnh static struct null_node_cache * 6554938Sheideman null_node_hash(lowervp) 6654938Sheideman struct vnode *lowervp; 6754751Sjohnh { 6854951Sheideman 6954938Sheideman return (&null_node_cache[NULL_NHASH(lowervp)]); 7054751Sjohnh } 7154751Sjohnh 7254766Sjohnh /* 7354938Sheideman * Return a VREF'ed alias for lower vnode if already exists, else 0. 7454938Sheideman */ 7554938Sheideman static struct vnode * 7654938Sheideman null_node_find(mp, lowervp) 7754751Sjohnh struct mount *mp; 7854938Sheideman struct vnode *lowervp; 7954751Sjohnh { 8054754Sjohnh struct null_node_cache *hd; 8154754Sjohnh struct null_node *a; 8254938Sheideman struct vnode *vp; 8354751Sjohnh 8454751Sjohnh /* 8554751Sjohnh * Find hash base, and then search the (two-way) linked 8654754Sjohnh * list looking for a null_node structure which is referencing 8754938Sheideman * the lower vnode. If found, the increment the null_node 8854938Sheideman * reference count (but NOT the lower vnode's VREF counter). 8954751Sjohnh */ 9054938Sheideman hd = null_node_hash(lowervp); 9154938Sheideman loop: 9254754Sjohnh for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 9354938Sheideman if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 9454938Sheideman vp = NULLTOV(a); 9554938Sheideman /* 9654951Sheideman * We need vget for the VXLOCK 9754951Sheideman * stuff, but we don't want to lock 9854951Sheideman * the lower node. 9954938Sheideman */ 10065245Smckusick if (vget(vp, 0)) { 10154938Sheideman printf ("null_node_find: vget failed.\n"); 10254938Sheideman goto loop; 10354938Sheideman }; 10454938Sheideman return (vp); 10554751Sjohnh } 10654751Sjohnh } 10754751Sjohnh 10854938Sheideman return NULL; 10954751Sjohnh } 11054751Sjohnh 11154938Sheideman 11254766Sjohnh /* 11354951Sheideman * Make a new null_node node. 11454951Sheideman * Vp is the alias vnode, lofsvp is the lower vnode. 11554951Sheideman * Maintain a reference to (lowervp). 11654951Sheideman */ 11754951Sheideman static int 11854951Sheideman null_node_alloc(mp, lowervp, vpp) 11954951Sheideman struct mount *mp; 12054951Sheideman struct vnode *lowervp; 12154951Sheideman struct vnode **vpp; 12254951Sheideman { 12354951Sheideman struct null_node_cache *hd; 12454951Sheideman struct null_node *xp; 12554951Sheideman struct vnode *othervp, *vp; 12654951Sheideman int error; 12754951Sheideman 12865424Spendry if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp)) 12965424Spendry return (error); 13054951Sheideman vp = *vpp; 13154951Sheideman 13254951Sheideman MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 13354951Sheideman vp->v_type = lowervp->v_type; 13454951Sheideman xp->null_vnode = vp; 13554951Sheideman vp->v_data = xp; 13654951Sheideman xp->null_lowervp = lowervp; 13754951Sheideman /* 13854951Sheideman * Before we insert our new node onto the hash chains, 13954951Sheideman * check to see if someone else has beaten us to it. 14054951Sheideman * (We could have slept in MALLOC.) 14154951Sheideman */ 14254951Sheideman if (othervp = null_node_find(lowervp)) { 14354951Sheideman FREE(xp, M_TEMP); 14454951Sheideman vp->v_type = VBAD; /* node is discarded */ 14554951Sheideman vp->v_usecount = 0; /* XXX */ 14654951Sheideman *vpp = othervp; 14754951Sheideman return 0; 14854951Sheideman }; 14954951Sheideman VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 15054951Sheideman hd = null_node_hash(lowervp); 15154951Sheideman insque(xp, hd); 15254951Sheideman return 0; 15354951Sheideman } 15454951Sheideman 15554951Sheideman 15654951Sheideman /* 15754766Sjohnh * Try to find an existing null_node vnode refering 15854766Sjohnh * to it, otherwise make a new null_node vnode which 15954938Sheideman * contains a reference to the lower vnode. 16054766Sjohnh */ 16154766Sjohnh int 16254938Sheideman null_node_create(mp, lowervp, newvpp) 16354751Sjohnh struct mount *mp; 16454938Sheideman struct vnode *lowervp; 16554751Sjohnh struct vnode **newvpp; 16654751Sjohnh { 16754751Sjohnh struct vnode *aliasvp; 16854751Sjohnh 16954938Sheideman if (aliasvp = null_node_find(mp, lowervp)) { 17054751Sjohnh /* 17154938Sheideman * null_node_find has taken another reference 17254938Sheideman * to the alias vnode. 17354751Sjohnh */ 17454754Sjohnh #ifdef NULLFS_DIAGNOSTIC 17554938Sheideman vprint("null_node_create: exists", NULLTOV(ap)); 17654751Sjohnh #endif 17754938Sheideman /* VREF(aliasvp); --- done in null_node_find */ 17854751Sjohnh } else { 17954751Sjohnh int error; 18054751Sjohnh 18154751Sjohnh /* 18254751Sjohnh * Get new vnode. 18354751Sjohnh */ 18454754Sjohnh #ifdef NULLFS_DIAGNOSTIC 18554938Sheideman printf("null_node_create: create new alias vnode\n"); 18654751Sjohnh #endif 18754751Sjohnh 18854751Sjohnh /* 18954754Sjohnh * Make new vnode reference the null_node. 19054751Sjohnh */ 19154951Sheideman if (error = null_node_alloc(mp, lowervp, &aliasvp)) 19254951Sheideman return error; 19354751Sjohnh 19454751Sjohnh /* 19554751Sjohnh * aliasvp is already VREF'd by getnewvnode() 19654751Sjohnh */ 19754751Sjohnh } 19854751Sjohnh 19954938Sheideman vrele(lowervp); 20054751Sjohnh 20154951Sheideman #ifdef DIAGNOSTIC 20254938Sheideman if (lowervp->v_usecount < 1) { 20354951Sheideman /* Should never happen... */ 204*67398Smkm vprint ("null_node_create: alias ", aliasvp); 205*67398Smkm vprint ("null_node_create: lower ", lowervp); 20654938Sheideman panic ("null_node_create: lower has 0 usecount."); 20754938Sheideman }; 20854951Sheideman #endif 20954938Sheideman 21054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21154938Sheideman vprint("null_node_create: alias", aliasvp); 21254938Sheideman vprint("null_node_create: lower", lowervp); 21354751Sjohnh #endif 21454751Sjohnh 21554751Sjohnh *newvpp = aliasvp; 21654751Sjohnh return (0); 21754751Sjohnh } 21854754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21954751Sjohnh struct vnode * 22054754Sjohnh null_checkvp(vp, fil, lno) 22154751Sjohnh struct vnode *vp; 22254751Sjohnh char *fil; 22354751Sjohnh int lno; 22454751Sjohnh { 22554938Sheideman struct null_node *a = VTONULL(vp); 22655025Smckusick #ifdef notyet 22754938Sheideman /* 22854938Sheideman * Can't do this check because vop_reclaim runs 22954938Sheideman * with a funny vop vector. 23054938Sheideman */ 23154938Sheideman if (vp->v_op != null_vnodeop_p) { 23254938Sheideman printf ("null_checkvp: on non-null-node\n"); 23354938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 23454938Sheideman panic("null_checkvp"); 23554938Sheideman }; 23654938Sheideman #endif 23754938Sheideman if (a->null_lowervp == NULL) { 23854766Sjohnh /* Should never happen */ 23954751Sjohnh int i; u_long *p; 24054751Sjohnh printf("vp = %x, ZERO ptr\n", vp); 24154751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++) 24254751Sjohnh printf(" %x", p[i]); 24354751Sjohnh printf("\n"); 24454938Sheideman /* wait for debugger */ 24554938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 24654754Sjohnh panic("null_checkvp"); 24754751Sjohnh } 24854938Sheideman if (a->null_lowervp->v_usecount < 1) { 24954938Sheideman int i; u_long *p; 25054938Sheideman printf("vp = %x, unref'ed lowervp\n", vp); 25154938Sheideman for (p = (u_long *) a, i = 0; i < 8; i++) 25254938Sheideman printf(" %x", p[i]); 25354938Sheideman printf("\n"); 25454938Sheideman /* wait for debugger */ 25554938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 25654938Sheideman panic ("null with unref'ed lowervp"); 25754938Sheideman }; 25855025Smckusick #ifdef notyet 25954938Sheideman printf("null %x/%d -> %x/%d [%s, %d]\n", 26054938Sheideman NULLTOV(a), NULLTOV(a)->v_usecount, 26154766Sjohnh a->null_lowervp, a->null_lowervp->v_usecount, 26254751Sjohnh fil, lno); 26354938Sheideman #endif 26454754Sjohnh return a->null_lowervp; 26554751Sjohnh } 26654751Sjohnh #endif 267