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> 2454751Sjohnh #include <lofs/lofs.h> 2554751Sjohnh 2654751Sjohnh #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 27*54754Sjohnh #define NNULLNODECACHE 16 28*54754Sjohnh #define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1)) 2954751Sjohnh 3054751Sjohnh /* 31*54754Sjohnh * Null layer cache: 3254751Sjohnh * Each cache entry holds a reference to the target vnode 3354751Sjohnh * along with a pointer to the alias vnode. When an 3454751Sjohnh * entry is added the target vnode is VREF'd. When the 3554751Sjohnh * alias is removed the target vnode is vrele'd. 3654751Sjohnh */ 3754751Sjohnh 3854751Sjohnh /* 3954751Sjohnh * Cache head 4054751Sjohnh */ 41*54754Sjohnh struct null_node_cache { 42*54754Sjohnh struct null_node *ac_forw; 43*54754Sjohnh struct null_node *ac_back; 4454751Sjohnh }; 4554751Sjohnh 46*54754Sjohnh static struct null_node_cache null_node_cache[NNULLNODECACHE]; 4754751Sjohnh 4854751Sjohnh /* 4954751Sjohnh * Initialise cache headers 5054751Sjohnh */ 51*54754Sjohnh nullfs_init() 5254751Sjohnh { 53*54754Sjohnh struct null_node_cache *ac; 54*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 55*54754Sjohnh printf("nullfs_init\n"); /* printed during system boot */ 5654751Sjohnh #endif 5754751Sjohnh 58*54754Sjohnh for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) 59*54754Sjohnh ac->ac_forw = ac->ac_back = (struct null_node *) ac; 6054751Sjohnh } 6154751Sjohnh 6254751Sjohnh /* 6354751Sjohnh * Compute hash list for given target vnode 6454751Sjohnh */ 65*54754Sjohnh static struct null_node_cache * 66*54754Sjohnh null_node_hash(targetvp) 6754751Sjohnh struct vnode *targetvp; 6854751Sjohnh { 69*54754Sjohnh return (&null_node_cache[NULL_NHASH(targetvp)]); 7054751Sjohnh } 7154751Sjohnh 7254751Sjohnh /* 73*54754Sjohnh * Make a new null_node node. 7454751Sjohnh * Vp is the alias vnode, lofsvp is the target vnode. 7554751Sjohnh * Maintain a reference to (targetvp). 7654751Sjohnh */ 7754751Sjohnh static void 78*54754Sjohnh null_node_alloc(vp, targetvp) 7954751Sjohnh struct vnode *vp; 8054751Sjohnh struct vnode *targetvp; 8154751Sjohnh { 82*54754Sjohnh struct null_node_cache *hd; 83*54754Sjohnh struct null_node *a; 8454751Sjohnh 85*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 86*54754Sjohnh printf("null_node_alloc(%x, %x)\n", vp, targetvp); 8754751Sjohnh #endif 8854751Sjohnh 89*54754Sjohnh MALLOC(a, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 90*54754Sjohnh a->null_vnode = vp; 9154751Sjohnh vp->v_data = a; 9254751Sjohnh VREF(targetvp); 93*54754Sjohnh a->null_lowervp = targetvp; 94*54754Sjohnh hd = null_node_hash(targetvp); 9554751Sjohnh insque(a, hd); 9654751Sjohnh 97*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 9854751Sjohnh vprint("alloc vp", vp); 9954751Sjohnh vprint("alloc targetvp", targetvp); 10054751Sjohnh #endif 10154751Sjohnh } 10254751Sjohnh 103*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 10454751Sjohnh void 105*54754Sjohnh null_node_flushmp (mp) 10654751Sjohnh struct mount *mp; 10754751Sjohnh { 108*54754Sjohnh struct null_node_cache *ac; 10954751Sjohnh int i = 0; 110*54754Sjohnh struct null_node *roota; 11154751Sjohnh 112*54754Sjohnh printf("null_node_flushmp (%x)\n", mp); 11354751Sjohnh 114*54754Sjohnh roota = VTONULLNODE(MOUNTTONULLMOUNT(mp)->nullm_rootvp); 11554751Sjohnh 116*54754Sjohnh for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) { 117*54754Sjohnh struct null_node *a = ac->ac_forw; 118*54754Sjohnh while (a != (struct null_node *) ac) { 119*54754Sjohnh if (a != roota && a->null_vnode->v_mount == mp) { 120*54754Sjohnh struct vnode *vp = a->null_lowervp; 12154751Sjohnh if (vp) { 122*54754Sjohnh a->null_lowervp = 0; 12354751Sjohnh vprint("would vrele", vp); 12454751Sjohnh /*vrele(vp);*/ 12554751Sjohnh i++; 12654751Sjohnh } 12754751Sjohnh } 128*54754Sjohnh a = a->null_forw; 12954751Sjohnh } 13054751Sjohnh } 13154751Sjohnh if (i > 0) 132*54754Sjohnh printf("null_node: vrele'd %d aliases\n", i); 13354751Sjohnh } 13454751Sjohnh #endif 13554751Sjohnh 13654751Sjohnh /* 13754751Sjohnh * Return alias for target vnode if already exists, else 0. 13854751Sjohnh */ 139*54754Sjohnh static struct null_node * 140*54754Sjohnh null_node_find(mp, targetvp) 14154751Sjohnh struct mount *mp; 14254751Sjohnh struct vnode *targetvp; 14354751Sjohnh { 144*54754Sjohnh struct null_node_cache *hd; 145*54754Sjohnh struct null_node *a; 14654751Sjohnh 147*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 148*54754Sjohnh printf("null_node_find(mp = %x, target = %x)\n", mp, targetvp); 14954751Sjohnh #endif 15054751Sjohnh 15154751Sjohnh /* 15254751Sjohnh * Find hash base, and then search the (two-way) linked 153*54754Sjohnh * list looking for a null_node structure which is referencing 154*54754Sjohnh * the target vnode. If found, the increment the null_node 15554751Sjohnh * reference count (but NOT the target vnode's VREF counter). 15654751Sjohnh */ 157*54754Sjohnh hd = null_node_hash(targetvp); 15854751Sjohnh 159*54754Sjohnh for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 160*54754Sjohnh if (a->null_lowervp == targetvp && a->null_vnode->v_mount == mp) { 161*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 162*54754Sjohnh printf("null_node_find(%x): found (%x,%x)->%x\n", 163*54754Sjohnh targetvp, mp, a->null_vnode, targetvp); 16454751Sjohnh #endif 16554751Sjohnh return (a); 16654751Sjohnh } 16754751Sjohnh } 16854751Sjohnh 169*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 170*54754Sjohnh printf("null_node_find(%x, %x): NOT found\n", mp, targetvp); 17154751Sjohnh #endif 17254751Sjohnh 17354751Sjohnh return (0); 17454751Sjohnh } 17554751Sjohnh 17654751Sjohnh static int 177*54754Sjohnh null_node_alias(mp, targetvp, newvpp) 17854751Sjohnh struct mount *mp; 17954751Sjohnh struct vnode *targetvp; 18054751Sjohnh struct vnode **newvpp; 18154751Sjohnh { 182*54754Sjohnh struct null_node *ap; 18354751Sjohnh struct vnode *aliasvp; 18454751Sjohnh 185*54754Sjohnh if (targetvp->v_type != VDIR || targetvp->v_op == null_vnodeop_p) { 18654751Sjohnh *newvpp = targetvp; 18754751Sjohnh return; 18854751Sjohnh } 18954751Sjohnh 190*54754Sjohnh ap = null_node_find(mp, targetvp); 19154751Sjohnh 19254751Sjohnh if (ap) { 19354751Sjohnh /* 19454751Sjohnh * Take another reference to the alias vnode 19554751Sjohnh */ 196*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 197*54754Sjohnh vprint("null_node_alias: exists", ap->null_vnode); 19854751Sjohnh #endif 199*54754Sjohnh aliasvp = ap->null_vnode; 20054751Sjohnh VREF(aliasvp); 20154751Sjohnh } else { 20254751Sjohnh int error; 20354751Sjohnh 20454751Sjohnh /* 20554751Sjohnh * Get new vnode. 20654751Sjohnh */ 207*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 208*54754Sjohnh printf("null_node_alias: create new alias vnode\n"); 20954751Sjohnh #endif 210*54754Sjohnh if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp)) 21154751Sjohnh return (error); /* XXX: VT_LOFS above */ 21254751Sjohnh 21354751Sjohnh /* 21454751Sjohnh * Must be a directory 21554751Sjohnh */ 21654751Sjohnh aliasvp->v_type = VDIR; 21754751Sjohnh 21854751Sjohnh /* 219*54754Sjohnh * Make new vnode reference the null_node. 22054751Sjohnh */ 221*54754Sjohnh null_node_alloc(aliasvp, targetvp); 22254751Sjohnh 22354751Sjohnh /* 22454751Sjohnh * aliasvp is already VREF'd by getnewvnode() 22554751Sjohnh */ 22654751Sjohnh } 22754751Sjohnh 22854751Sjohnh vrele(targetvp); 22954751Sjohnh 230*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 231*54754Sjohnh vprint("null_node_alias alias", aliasvp); 232*54754Sjohnh vprint("null_node_alias target", targetvp); 23354751Sjohnh #endif 23454751Sjohnh 23554751Sjohnh *newvpp = aliasvp; 23654751Sjohnh return (0); 23754751Sjohnh } 23854751Sjohnh 23954751Sjohnh /* 240*54754Sjohnh * Try to find an existing null_node vnode refering 241*54754Sjohnh * to it, otherwise make a new null_node vnode which 24254751Sjohnh * contains a reference to the target vnode. 24354751Sjohnh */ 244*54754Sjohnh make_null_node(mp, vpp) 24554751Sjohnh struct mount *mp; 24654751Sjohnh struct vnode **vpp; 24754751Sjohnh { 24854751Sjohnh int error; 24954751Sjohnh struct vnode *aliasvp; 25054751Sjohnh struct vnode *targetvp; 25154751Sjohnh 252*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 253*54754Sjohnh printf("make_null_node(mp = %x, vp = %x\n", mp, *vpp); 25454751Sjohnh #endif 25554751Sjohnh 25654751Sjohnh /* 25754751Sjohnh * (targetvp) is locked at this point. 25854751Sjohnh */ 25954751Sjohnh targetvp = *vpp; 26054751Sjohnh 261*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 26254751Sjohnh if (targetvp == 0) 263*54754Sjohnh panic("make_null_node: null vp"); 26454751Sjohnh #endif 26554751Sjohnh 26654751Sjohnh /* 26754751Sjohnh * Try to find an existing reference to the target vnodes. 26854751Sjohnh */ 269*54754Sjohnh return (null_node_alias(mp, targetvp, vpp)); 27054751Sjohnh } 27154751Sjohnh 272*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 27354751Sjohnh struct vnode * 274*54754Sjohnh null_checkvp(vp, fil, lno) 27554751Sjohnh struct vnode *vp; 27654751Sjohnh char *fil; 27754751Sjohnh int lno; 27854751Sjohnh { 279*54754Sjohnh struct null_node *a = VTONULLNODE(vp); 280*54754Sjohnh if (a->null_lowervp == 0) { 28154751Sjohnh int i; u_long *p; 28254751Sjohnh printf("vp = %x, ZERO ptr\n", vp); 28354751Sjohnh #ifdef notdef 28454751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++) 28554751Sjohnh printf(" %x", p[i]); 28654751Sjohnh printf("\n"); 28754751Sjohnh DELAY(2000000); 288*54754Sjohnh panic("null_checkvp"); 28954751Sjohnh #endif 29054751Sjohnh } 29154751Sjohnh printf("aliasvp %x/%d -> %x/%d [%s, %d]\n", 292*54754Sjohnh a->null_vnode, a->null_vnode->v_usecount, 293*54754Sjohnh a->null_lowervp, a->null_lowervp ? a->null_lowervp->v_usecount : -42, 29454751Sjohnh fil, lno); 295*54754Sjohnh return a->null_lowervp; 29654751Sjohnh } 29754751Sjohnh #endif 298