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*67716Smckusick * @(#)null_subr.c 8.6 (Berkeley) 08/20/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 2754751Sjohnh 2854751Sjohnh /* 2954754Sjohnh * Null layer cache: 3054938Sheideman * Each cache entry holds a reference to the lower vnode 3154751Sjohnh * along with a pointer to the alias vnode. When an 3254938Sheideman * entry is added the lower vnode is VREF'd. When the 3354938Sheideman * alias is removed the lower vnode is vrele'd. 3454751Sjohnh */ 3554751Sjohnh 36*67716Smckusick #define NULL_NHASH(vp) \ 37*67716Smckusick (&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash]) 38*67716Smckusick LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl; 39*67716Smckusick u_long null_node_hash; 4054751Sjohnh 4154751Sjohnh /* 4254751Sjohnh * Initialise cache headers 4354751Sjohnh */ 4454754Sjohnh nullfs_init() 4554751Sjohnh { 46*67716Smckusick 4754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 4854754Sjohnh printf("nullfs_init\n"); /* printed during system boot */ 4954751Sjohnh #endif 50*67716Smckusick null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash); 5154751Sjohnh } 5254751Sjohnh 5354751Sjohnh /* 5454938Sheideman * Return a VREF'ed alias for lower vnode if already exists, else 0. 5554938Sheideman */ 5654938Sheideman static struct vnode * 5754938Sheideman null_node_find(mp, lowervp) 5854751Sjohnh struct mount *mp; 5954938Sheideman struct vnode *lowervp; 6054751Sjohnh { 61*67716Smckusick struct null_node_hashhead *hd; 6254754Sjohnh struct null_node *a; 6354938Sheideman struct vnode *vp; 6454751Sjohnh 6554751Sjohnh /* 6654751Sjohnh * Find hash base, and then search the (two-way) linked 6754754Sjohnh * list looking for a null_node structure which is referencing 6854938Sheideman * the lower vnode. If found, the increment the null_node 6954938Sheideman * reference count (but NOT the lower vnode's VREF counter). 7054751Sjohnh */ 71*67716Smckusick hd = NULL_NHASH(lowervp); 7254938Sheideman loop: 73*67716Smckusick for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) { 7454938Sheideman if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 7554938Sheideman vp = NULLTOV(a); 7654938Sheideman /* 7754951Sheideman * We need vget for the VXLOCK 7854951Sheideman * stuff, but we don't want to lock 7954951Sheideman * the lower node. 8054938Sheideman */ 8165245Smckusick if (vget(vp, 0)) { 8254938Sheideman printf ("null_node_find: vget failed.\n"); 8354938Sheideman goto loop; 8454938Sheideman }; 8554938Sheideman return (vp); 8654751Sjohnh } 8754751Sjohnh } 8854751Sjohnh 8954938Sheideman return NULL; 9054751Sjohnh } 9154751Sjohnh 9254938Sheideman 9354766Sjohnh /* 9454951Sheideman * Make a new null_node node. 9554951Sheideman * Vp is the alias vnode, lofsvp is the lower vnode. 9654951Sheideman * Maintain a reference to (lowervp). 9754951Sheideman */ 9854951Sheideman static int 9954951Sheideman null_node_alloc(mp, lowervp, vpp) 10054951Sheideman struct mount *mp; 10154951Sheideman struct vnode *lowervp; 10254951Sheideman struct vnode **vpp; 10354951Sheideman { 104*67716Smckusick struct null_node_hashhead *hd; 10554951Sheideman struct null_node *xp; 10654951Sheideman struct vnode *othervp, *vp; 10754951Sheideman int error; 10854951Sheideman 10965424Spendry if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp)) 11065424Spendry return (error); 11154951Sheideman vp = *vpp; 11254951Sheideman 11354951Sheideman MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 11454951Sheideman vp->v_type = lowervp->v_type; 11554951Sheideman xp->null_vnode = vp; 11654951Sheideman vp->v_data = xp; 11754951Sheideman xp->null_lowervp = lowervp; 11854951Sheideman /* 11954951Sheideman * Before we insert our new node onto the hash chains, 12054951Sheideman * check to see if someone else has beaten us to it. 12154951Sheideman * (We could have slept in MALLOC.) 12254951Sheideman */ 12354951Sheideman if (othervp = null_node_find(lowervp)) { 12454951Sheideman FREE(xp, M_TEMP); 12554951Sheideman vp->v_type = VBAD; /* node is discarded */ 12654951Sheideman vp->v_usecount = 0; /* XXX */ 12754951Sheideman *vpp = othervp; 12854951Sheideman return 0; 12954951Sheideman }; 13054951Sheideman VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 131*67716Smckusick hd = NULL_NHASH(lowervp); 132*67716Smckusick LIST_INSERT_HEAD(hd, xp, null_hash); 13354951Sheideman return 0; 13454951Sheideman } 13554951Sheideman 13654951Sheideman 13754951Sheideman /* 13854766Sjohnh * Try to find an existing null_node vnode refering 13954766Sjohnh * to it, otherwise make a new null_node vnode which 14054938Sheideman * contains a reference to the lower vnode. 14154766Sjohnh */ 14254766Sjohnh int 14354938Sheideman null_node_create(mp, lowervp, newvpp) 14454751Sjohnh struct mount *mp; 14554938Sheideman struct vnode *lowervp; 14654751Sjohnh struct vnode **newvpp; 14754751Sjohnh { 14854751Sjohnh struct vnode *aliasvp; 14954751Sjohnh 15054938Sheideman if (aliasvp = null_node_find(mp, lowervp)) { 15154751Sjohnh /* 15254938Sheideman * null_node_find has taken another reference 15354938Sheideman * to the alias vnode. 15454751Sjohnh */ 15554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 15654938Sheideman vprint("null_node_create: exists", NULLTOV(ap)); 15754751Sjohnh #endif 15854938Sheideman /* VREF(aliasvp); --- done in null_node_find */ 15954751Sjohnh } else { 16054751Sjohnh int error; 16154751Sjohnh 16254751Sjohnh /* 16354751Sjohnh * Get new vnode. 16454751Sjohnh */ 16554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 16654938Sheideman printf("null_node_create: create new alias vnode\n"); 16754751Sjohnh #endif 16854751Sjohnh 16954751Sjohnh /* 17054754Sjohnh * Make new vnode reference the null_node. 17154751Sjohnh */ 17254951Sheideman if (error = null_node_alloc(mp, lowervp, &aliasvp)) 17354951Sheideman return error; 17454751Sjohnh 17554751Sjohnh /* 17654751Sjohnh * aliasvp is already VREF'd by getnewvnode() 17754751Sjohnh */ 17854751Sjohnh } 17954751Sjohnh 18054938Sheideman vrele(lowervp); 18154751Sjohnh 18254951Sheideman #ifdef DIAGNOSTIC 18354938Sheideman if (lowervp->v_usecount < 1) { 18454951Sheideman /* Should never happen... */ 18567398Smkm vprint ("null_node_create: alias ", aliasvp); 18667398Smkm vprint ("null_node_create: lower ", lowervp); 18754938Sheideman panic ("null_node_create: lower has 0 usecount."); 18854938Sheideman }; 18954951Sheideman #endif 19054938Sheideman 19154754Sjohnh #ifdef NULLFS_DIAGNOSTIC 19254938Sheideman vprint("null_node_create: alias", aliasvp); 19354938Sheideman vprint("null_node_create: lower", lowervp); 19454751Sjohnh #endif 19554751Sjohnh 19654751Sjohnh *newvpp = aliasvp; 19754751Sjohnh return (0); 19854751Sjohnh } 19954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 20054751Sjohnh struct vnode * 20154754Sjohnh null_checkvp(vp, fil, lno) 20254751Sjohnh struct vnode *vp; 20354751Sjohnh char *fil; 20454751Sjohnh int lno; 20554751Sjohnh { 20654938Sheideman struct null_node *a = VTONULL(vp); 20755025Smckusick #ifdef notyet 20854938Sheideman /* 20954938Sheideman * Can't do this check because vop_reclaim runs 21054938Sheideman * with a funny vop vector. 21154938Sheideman */ 21254938Sheideman if (vp->v_op != null_vnodeop_p) { 21354938Sheideman printf ("null_checkvp: on non-null-node\n"); 21454938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 21554938Sheideman panic("null_checkvp"); 21654938Sheideman }; 21754938Sheideman #endif 21854938Sheideman if (a->null_lowervp == NULL) { 21954766Sjohnh /* Should never happen */ 22054751Sjohnh int i; u_long *p; 22154751Sjohnh printf("vp = %x, ZERO ptr\n", vp); 22254751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++) 22354751Sjohnh printf(" %x", p[i]); 22454751Sjohnh printf("\n"); 22554938Sheideman /* wait for debugger */ 22654938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 22754754Sjohnh panic("null_checkvp"); 22854751Sjohnh } 22954938Sheideman if (a->null_lowervp->v_usecount < 1) { 23054938Sheideman int i; u_long *p; 23154938Sheideman printf("vp = %x, unref'ed lowervp\n", vp); 23254938Sheideman for (p = (u_long *) a, i = 0; i < 8; i++) 23354938Sheideman printf(" %x", p[i]); 23454938Sheideman printf("\n"); 23554938Sheideman /* wait for debugger */ 23654938Sheideman while (null_checkvp_barrier) /*WAIT*/ ; 23754938Sheideman panic ("null with unref'ed lowervp"); 23854938Sheideman }; 23955025Smckusick #ifdef notyet 24054938Sheideman printf("null %x/%d -> %x/%d [%s, %d]\n", 24154938Sheideman NULLTOV(a), NULLTOV(a)->v_usecount, 24254766Sjohnh a->null_lowervp, a->null_lowervp->v_usecount, 24354751Sjohnh fil, lno); 24454938Sheideman #endif 24554754Sjohnh return a->null_lowervp; 24654751Sjohnh } 24754751Sjohnh #endif 248