154751Sjohnh /* 263245Sbostic * Copyright (c) 1992, 1993 363245Sbostic * The Regents of the University of California. All rights reserved. 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 * 11*65245Smckusick * @(#)null_subr.c 8.2 (Berkeley) 12/30/93 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> 2455025Smckusick #include <miscfs/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 { 6954951Sheideman 7054938Sheideman return (&null_node_cache[NULL_NHASH(lowervp)]); 7154751Sjohnh } 7254751Sjohnh 7354766Sjohnh /* 7454938Sheideman * Return a VREF'ed alias for lower vnode if already exists, else 0. 7554938Sheideman */ 7654938Sheideman static struct vnode * 7754938Sheideman null_node_find(mp, lowervp) 7854751Sjohnh struct mount *mp; 7954938Sheideman struct vnode *lowervp; 8054751Sjohnh { 8154754Sjohnh struct null_node_cache *hd; 8254754Sjohnh struct null_node *a; 8354938Sheideman struct vnode *vp; 8454751Sjohnh 8554751Sjohnh /* 8654751Sjohnh * Find hash base, and then search the (two-way) linked 8754754Sjohnh * list looking for a null_node structure which is referencing 8854938Sheideman * the lower vnode. If found, the increment the null_node 8954938Sheideman * reference count (but NOT the lower vnode's VREF counter). 9054751Sjohnh */ 9154938Sheideman hd = null_node_hash(lowervp); 9254938Sheideman loop: 9354754Sjohnh for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 9454938Sheideman if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 9554938Sheideman vp = NULLTOV(a); 9654938Sheideman /* 9754951Sheideman * We need vget for the VXLOCK 9854951Sheideman * stuff, but we don't want to lock 9954951Sheideman * the lower node. 10054938Sheideman */ 101*65245Smckusick if (vget(vp, 0)) { 10254938Sheideman printf ("null_node_find: vget failed.\n"); 10354938Sheideman goto loop; 10454938Sheideman }; 10554938Sheideman return (vp); 10654751Sjohnh } 10754751Sjohnh } 10854751Sjohnh 10954938Sheideman return NULL; 11054751Sjohnh } 11154751Sjohnh 11254938Sheideman 11354766Sjohnh /* 11454951Sheideman * Make a new null_node node. 11554951Sheideman * Vp is the alias vnode, lofsvp is the lower vnode. 11654951Sheideman * Maintain a reference to (lowervp). 11754951Sheideman */ 11854951Sheideman static int 11954951Sheideman null_node_alloc(mp, lowervp, vpp) 12054951Sheideman struct mount *mp; 12154951Sheideman struct vnode *lowervp; 12254951Sheideman struct vnode **vpp; 12354951Sheideman { 12454951Sheideman struct null_node_cache *hd; 12554951Sheideman struct null_node *xp; 12654951Sheideman struct vnode *othervp, *vp; 12754951Sheideman int error; 12854951Sheideman 12954951Sheideman if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, vpp)) 13054951Sheideman return (error); /* XXX: VT_NULL above */ 13154951Sheideman vp = *vpp; 13254951Sheideman 13354951Sheideman MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 13454951Sheideman vp->v_type = lowervp->v_type; 13554951Sheideman xp->null_vnode = vp; 13654951Sheideman vp->v_data = xp; 13754951Sheideman xp->null_lowervp = lowervp; 13854951Sheideman /* 13954951Sheideman * Before we insert our new node onto the hash chains, 14054951Sheideman * check to see if someone else has beaten us to it. 14154951Sheideman * (We could have slept in MALLOC.) 14254951Sheideman */ 14354951Sheideman if (othervp = null_node_find(lowervp)) { 14454951Sheideman FREE(xp, M_TEMP); 14554951Sheideman vp->v_type = VBAD; /* node is discarded */ 14654951Sheideman vp->v_usecount = 0; /* XXX */ 14754951Sheideman *vpp = othervp; 14854951Sheideman return 0; 14954951Sheideman }; 15054951Sheideman VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 15154951Sheideman hd = null_node_hash(lowervp); 15254951Sheideman insque(xp, hd); 15354951Sheideman return 0; 15454951Sheideman } 15554951Sheideman 15654951Sheideman 15754951Sheideman /* 15854766Sjohnh * Try to find an existing null_node vnode refering 15954766Sjohnh * to it, otherwise make a new null_node vnode which 16054938Sheideman * contains a reference to the lower vnode. 16154766Sjohnh */ 16254766Sjohnh int 16354938Sheideman null_node_create(mp, lowervp, newvpp) 16454751Sjohnh struct mount *mp; 16554938Sheideman struct vnode *lowervp; 16654751Sjohnh struct vnode **newvpp; 16754751Sjohnh { 16854751Sjohnh struct vnode *aliasvp; 16954751Sjohnh 17054938Sheideman if (aliasvp = null_node_find(mp, lowervp)) { 17154751Sjohnh /* 17254938Sheideman * null_node_find has taken another reference 17354938Sheideman * to the alias vnode. 17454751Sjohnh */ 17554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 17654938Sheideman vprint("null_node_create: exists", NULLTOV(ap)); 17754751Sjohnh #endif 17854938Sheideman /* VREF(aliasvp); --- done in null_node_find */ 17954751Sjohnh } else { 18054751Sjohnh int error; 18154751Sjohnh 18254751Sjohnh /* 18354751Sjohnh * Get new vnode. 18454751Sjohnh */ 18554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 18654938Sheideman printf("null_node_create: create new alias vnode\n"); 18754751Sjohnh #endif 18854751Sjohnh 18954751Sjohnh /* 19054754Sjohnh * Make new vnode reference the null_node. 19154751Sjohnh */ 19254951Sheideman if (error = null_node_alloc(mp, lowervp, &aliasvp)) 19354951Sheideman return error; 19454751Sjohnh 19554751Sjohnh /* 19654751Sjohnh * aliasvp is already VREF'd by getnewvnode() 19754751Sjohnh */ 19854751Sjohnh } 19954751Sjohnh 20054938Sheideman vrele(lowervp); 20154751Sjohnh 20254951Sheideman #ifdef DIAGNOSTIC 20354938Sheideman if (lowervp->v_usecount < 1) { 20454951Sheideman /* Should never happen... */ 20554938Sheideman vprint ("null_node_create: alias "); 20654938Sheideman vprint ("null_node_create: lower "); 20754938Sheideman printf ("null_node_create: lower has 0 usecount.\n"); 20854938Sheideman panic ("null_node_create: lower has 0 usecount."); 20954938Sheideman }; 21054951Sheideman #endif 21154938Sheideman 21254754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21354938Sheideman vprint("null_node_create: alias", aliasvp); 21454938Sheideman vprint("null_node_create: lower", lowervp); 21554751Sjohnh #endif 21654751Sjohnh 21754751Sjohnh *newvpp = aliasvp; 21854751Sjohnh return (0); 21954751Sjohnh } 22054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 22154751Sjohnh struct vnode * 22254754Sjohnh null_checkvp(vp, fil, lno) 22354751Sjohnh struct vnode *vp; 22454751Sjohnh char *fil; 22554751Sjohnh int lno; 22654751Sjohnh { 22754938Sheideman struct null_node *a = VTONULL(vp); 22855025Smckusick #ifdef notyet 22954938Sheideman /* 23054938Sheideman * Can't do this check because vop_reclaim runs 23154938Sheideman * with a funny vop vector. 23254938Sheideman */ 23354938Sheideman if (vp->v_op != null_vnodeop_p) { 23454938Sheideman printf ("null_checkvp: on non-null-node\n"); 23554938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 23654938Sheideman panic("null_checkvp"); 23754938Sheideman }; 23854938Sheideman #endif 23954938Sheideman if (a->null_lowervp == NULL) { 24054766Sjohnh /* Should never happen */ 24154751Sjohnh int i; u_long *p; 24254751Sjohnh printf("vp = %x, ZERO ptr\n", vp); 24354751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++) 24454751Sjohnh printf(" %x", p[i]); 24554751Sjohnh printf("\n"); 24654938Sheideman /* wait for debugger */ 24754938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 24854754Sjohnh panic("null_checkvp"); 24954751Sjohnh } 25054938Sheideman if (a->null_lowervp->v_usecount < 1) { 25154938Sheideman int i; u_long *p; 25254938Sheideman printf("vp = %x, unref'ed lowervp\n", vp); 25354938Sheideman for (p = (u_long *) a, i = 0; i < 8; i++) 25454938Sheideman printf(" %x", p[i]); 25554938Sheideman printf("\n"); 25654938Sheideman /* wait for debugger */ 25754938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 25854938Sheideman panic ("null with unref'ed lowervp"); 25954938Sheideman }; 26055025Smckusick #ifdef notyet 26154938Sheideman printf("null %x/%d -> %x/%d [%s, %d]\n", 26254938Sheideman NULLTOV(a), NULLTOV(a)->v_usecount, 26354766Sjohnh a->null_lowervp, a->null_lowervp->v_usecount, 26454751Sjohnh fil, lno); 26554938Sheideman #endif 26654754Sjohnh return a->null_lowervp; 26754751Sjohnh } 26854751Sjohnh #endif 269