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> 24*54893Sheideman #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: 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 */ 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 /* 6354751Sjohnh * Compute hash list for given target vnode 6454751Sjohnh */ 6554754Sjohnh static struct null_node_cache * 6654754Sjohnh null_node_hash(targetvp) 6754751Sjohnh struct vnode *targetvp; 6854751Sjohnh { 6954754Sjohnh return (&null_node_cache[NULL_NHASH(targetvp)]); 7054751Sjohnh } 7154751Sjohnh 7254751Sjohnh /* 7354754Sjohnh * 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 7854754Sjohnh null_node_alloc(vp, targetvp) 7954751Sjohnh struct vnode *vp; 8054751Sjohnh struct vnode *targetvp; 8154751Sjohnh { 8254754Sjohnh struct null_node_cache *hd; 8354754Sjohnh struct null_node *a; 8454751Sjohnh 8554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 8654754Sjohnh printf("null_node_alloc(%x, %x)\n", vp, targetvp); 8754751Sjohnh #endif 8854751Sjohnh 8954754Sjohnh MALLOC(a, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 9054754Sjohnh a->null_vnode = vp; 9154751Sjohnh vp->v_data = a; 9254751Sjohnh VREF(targetvp); 9354754Sjohnh a->null_lowervp = targetvp; 9454754Sjohnh hd = null_node_hash(targetvp); 9554751Sjohnh insque(a, hd); 9654751Sjohnh 9754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 9854751Sjohnh vprint("alloc vp", vp); 9954751Sjohnh vprint("alloc targetvp", targetvp); 10054751Sjohnh #endif 10154751Sjohnh } 10254751Sjohnh 10354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 10454766Sjohnh /* 10554766Sjohnh * NEEDSWORK: The ability to set lowervp to null here 10654766Sjohnh * implies that one can never count on lowervp staying null 10754766Sjohnh * (even if vp is locked). This seems quite bad. Think 10854766Sjohnh * about these things. 10954766Sjohnh */ 11054751Sjohnh void 11154754Sjohnh null_node_flushmp (mp) 11254751Sjohnh struct mount *mp; 11354751Sjohnh { 11454754Sjohnh struct null_node_cache *ac; 11554751Sjohnh int i = 0; 11654754Sjohnh struct null_node *roota; 11754751Sjohnh 11854754Sjohnh printf("null_node_flushmp (%x)\n", mp); 11954751Sjohnh 12054754Sjohnh roota = VTONULLNODE(MOUNTTONULLMOUNT(mp)->nullm_rootvp); 12154751Sjohnh 12254754Sjohnh for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) { 12354754Sjohnh struct null_node *a = ac->ac_forw; 12454754Sjohnh while (a != (struct null_node *) ac) { 12554754Sjohnh if (a != roota && a->null_vnode->v_mount == mp) { 12654754Sjohnh struct vnode *vp = a->null_lowervp; 12754751Sjohnh if (vp) { 12854754Sjohnh a->null_lowervp = 0; 12954751Sjohnh vprint("would vrele", vp); 13054751Sjohnh /*vrele(vp);*/ 13154751Sjohnh i++; 13254751Sjohnh } 13354751Sjohnh } 13454754Sjohnh a = a->null_forw; 13554751Sjohnh } 13654751Sjohnh } 13754751Sjohnh if (i > 0) 13854754Sjohnh printf("null_node: vrele'd %d aliases\n", i); 13954751Sjohnh } 14054751Sjohnh #endif 14154751Sjohnh 14254751Sjohnh /* 14354751Sjohnh * Return alias for target vnode if already exists, else 0. 14454751Sjohnh */ 14554754Sjohnh static struct null_node * 14654754Sjohnh null_node_find(mp, targetvp) 14754751Sjohnh struct mount *mp; 14854751Sjohnh struct vnode *targetvp; 14954751Sjohnh { 15054754Sjohnh struct null_node_cache *hd; 15154754Sjohnh struct null_node *a; 15254751Sjohnh 15354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 15454754Sjohnh printf("null_node_find(mp = %x, target = %x)\n", mp, targetvp); 15554751Sjohnh #endif 15654751Sjohnh 15754751Sjohnh /* 15854751Sjohnh * Find hash base, and then search the (two-way) linked 15954754Sjohnh * list looking for a null_node structure which is referencing 16054754Sjohnh * the target vnode. If found, the increment the null_node 16154751Sjohnh * reference count (but NOT the target vnode's VREF counter). 16254751Sjohnh */ 16354754Sjohnh hd = null_node_hash(targetvp); 16454751Sjohnh 16554754Sjohnh for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 16654754Sjohnh if (a->null_lowervp == targetvp && a->null_vnode->v_mount == mp) { 16754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 16854754Sjohnh printf("null_node_find(%x): found (%x,%x)->%x\n", 16954754Sjohnh targetvp, mp, a->null_vnode, targetvp); 17054751Sjohnh #endif 17154751Sjohnh return (a); 17254751Sjohnh } 17354751Sjohnh } 17454751Sjohnh 17554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 17654754Sjohnh printf("null_node_find(%x, %x): NOT found\n", mp, targetvp); 17754751Sjohnh #endif 17854751Sjohnh 17954751Sjohnh return (0); 18054751Sjohnh } 18154751Sjohnh 18254766Sjohnh /* 18354766Sjohnh * Try to find an existing null_node vnode refering 18454766Sjohnh * to it, otherwise make a new null_node vnode which 18554766Sjohnh * contains a reference to the target vnode. 18654766Sjohnh */ 18754766Sjohnh int 18854766Sjohnh null_node_create(mp, targetvp, newvpp) 18954751Sjohnh struct mount *mp; 19054751Sjohnh struct vnode *targetvp; 19154751Sjohnh struct vnode **newvpp; 19254751Sjohnh { 19354754Sjohnh struct null_node *ap; 19454751Sjohnh struct vnode *aliasvp; 19554751Sjohnh 19654754Sjohnh if (targetvp->v_type != VDIR || targetvp->v_op == null_vnodeop_p) { 19754751Sjohnh *newvpp = targetvp; 19854751Sjohnh return; 19954751Sjohnh } 20054751Sjohnh 20154754Sjohnh ap = null_node_find(mp, targetvp); 20254751Sjohnh 20354751Sjohnh if (ap) { 20454751Sjohnh /* 20554751Sjohnh * Take another reference to the alias vnode 20654751Sjohnh */ 20754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 20854754Sjohnh vprint("null_node_alias: exists", ap->null_vnode); 20954751Sjohnh #endif 21054754Sjohnh aliasvp = ap->null_vnode; 21154751Sjohnh VREF(aliasvp); 21254751Sjohnh } else { 21354751Sjohnh int error; 21454751Sjohnh 21554751Sjohnh /* 21654751Sjohnh * Get new vnode. 21754751Sjohnh */ 21854754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21954754Sjohnh printf("null_node_alias: create new alias vnode\n"); 22054751Sjohnh #endif 22154754Sjohnh if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp)) 22254751Sjohnh return (error); /* XXX: VT_LOFS above */ 22354751Sjohnh 22454751Sjohnh /* 22554751Sjohnh * Must be a directory 22654751Sjohnh */ 22754751Sjohnh aliasvp->v_type = VDIR; 22854751Sjohnh 22954751Sjohnh /* 23054754Sjohnh * Make new vnode reference the null_node. 23154751Sjohnh */ 23254754Sjohnh null_node_alloc(aliasvp, targetvp); 23354751Sjohnh 23454751Sjohnh /* 23554751Sjohnh * aliasvp is already VREF'd by getnewvnode() 23654751Sjohnh */ 23754751Sjohnh } 23854751Sjohnh 23954751Sjohnh vrele(targetvp); 24054751Sjohnh 24154754Sjohnh #ifdef NULLFS_DIAGNOSTIC 24254754Sjohnh vprint("null_node_alias alias", aliasvp); 24354754Sjohnh vprint("null_node_alias target", targetvp); 24454751Sjohnh #endif 24554751Sjohnh 24654751Sjohnh *newvpp = aliasvp; 24754751Sjohnh return (0); 24854751Sjohnh } 24954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 25054751Sjohnh struct vnode * 25154754Sjohnh null_checkvp(vp, fil, lno) 25254751Sjohnh struct vnode *vp; 25354751Sjohnh char *fil; 25454751Sjohnh int lno; 25554751Sjohnh { 25654754Sjohnh struct null_node *a = VTONULLNODE(vp); 25754754Sjohnh if (a->null_lowervp == 0) { 25854766Sjohnh /* Should never happen */ 25954751Sjohnh int i; u_long *p; 26054751Sjohnh printf("vp = %x, ZERO ptr\n", vp); 26154751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++) 26254751Sjohnh printf(" %x", p[i]); 26354751Sjohnh printf("\n"); 26454751Sjohnh DELAY(2000000); 26554754Sjohnh panic("null_checkvp"); 26654751Sjohnh } 26754766Sjohnh printf("nullvp %x/%d -> %x/%d [%s, %d]\n", 26854754Sjohnh a->null_vnode, a->null_vnode->v_usecount, 26954766Sjohnh a->null_lowervp, a->null_lowervp->v_usecount, 27054751Sjohnh fil, lno); 27154754Sjohnh return a->null_lowervp; 27254751Sjohnh } 27354751Sjohnh #endif 274