1*54751Sjohnh /* 2*54751Sjohnh * Copyright (c) 1992 The Regents of the University of California 3*54751Sjohnh * Copyright (c) 1990, 1992 Jan-Simon Pendry 4*54751Sjohnh * All rights reserved. 5*54751Sjohnh * 6*54751Sjohnh * This code is derived from software donated to Berkeley by 7*54751Sjohnh * Jan-Simon Pendry. 8*54751Sjohnh * 9*54751Sjohnh * %sccs.include.redist.c% 10*54751Sjohnh * 11*54751Sjohnh * @(#)lofs_subr.c 1.2 (Berkeley) 6/18/92 12*54751Sjohnh * 13*54751Sjohnh * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 14*54751Sjohnh */ 15*54751Sjohnh 16*54751Sjohnh #include <sys/param.h> 17*54751Sjohnh #include <sys/systm.h> 18*54751Sjohnh #include <sys/time.h> 19*54751Sjohnh #include <sys/types.h> 20*54751Sjohnh #include <sys/vnode.h> 21*54751Sjohnh #include <sys/mount.h> 22*54751Sjohnh #include <sys/namei.h> 23*54751Sjohnh #include <sys/malloc.h> 24*54751Sjohnh #include <lofs/lofs.h> 25*54751Sjohnh 26*54751Sjohnh #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 27*54751Sjohnh #define NLOFSCACHE 16 28*54751Sjohnh #define LOFS_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NLOFSCACHE-1)) 29*54751Sjohnh 30*54751Sjohnh /* 31*54751Sjohnh * Loopback cache: 32*54751Sjohnh * Each cache entry holds a reference to the target vnode 33*54751Sjohnh * along with a pointer to the alias vnode. When an 34*54751Sjohnh * entry is added the target vnode is VREF'd. When the 35*54751Sjohnh * alias is removed the target vnode is vrele'd. 36*54751Sjohnh */ 37*54751Sjohnh 38*54751Sjohnh /* 39*54751Sjohnh * Cache head 40*54751Sjohnh */ 41*54751Sjohnh struct lofscache { 42*54751Sjohnh struct lofsnode *ac_forw; 43*54751Sjohnh struct lofsnode *ac_back; 44*54751Sjohnh }; 45*54751Sjohnh 46*54751Sjohnh static struct lofscache lofscache[NLOFSCACHE]; 47*54751Sjohnh 48*54751Sjohnh /* 49*54751Sjohnh * Initialise cache headers 50*54751Sjohnh */ 51*54751Sjohnh lofs_init() 52*54751Sjohnh { 53*54751Sjohnh struct lofscache *ac; 54*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 55*54751Sjohnh printf("lofs_init\n"); /* printed during system boot */ 56*54751Sjohnh #endif 57*54751Sjohnh 58*54751Sjohnh for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++) 59*54751Sjohnh ac->ac_forw = ac->ac_back = (struct lofsnode *) ac; 60*54751Sjohnh } 61*54751Sjohnh 62*54751Sjohnh /* 63*54751Sjohnh * Compute hash list for given target vnode 64*54751Sjohnh */ 65*54751Sjohnh static struct lofscache * 66*54751Sjohnh lofs_hash(targetvp) 67*54751Sjohnh struct vnode *targetvp; 68*54751Sjohnh { 69*54751Sjohnh return (&lofscache[LOFS_NHASH(targetvp)]); 70*54751Sjohnh } 71*54751Sjohnh 72*54751Sjohnh /* 73*54751Sjohnh * Make a new lofsnode node. 74*54751Sjohnh * Vp is the alias vnode, lofsvp is the target vnode. 75*54751Sjohnh * Maintain a reference to (targetvp). 76*54751Sjohnh */ 77*54751Sjohnh static void 78*54751Sjohnh lofs_alloc(vp, targetvp) 79*54751Sjohnh struct vnode *vp; 80*54751Sjohnh struct vnode *targetvp; 81*54751Sjohnh { 82*54751Sjohnh struct lofscache *hd; 83*54751Sjohnh struct lofsnode *a; 84*54751Sjohnh 85*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 86*54751Sjohnh printf("lofs_alloc(%x, %x)\n", vp, targetvp); 87*54751Sjohnh #endif 88*54751Sjohnh 89*54751Sjohnh MALLOC(a, struct lofsnode *, sizeof(struct lofsnode), M_TEMP, M_WAITOK); 90*54751Sjohnh a->a_vnode = vp; 91*54751Sjohnh vp->v_data = a; 92*54751Sjohnh VREF(targetvp); 93*54751Sjohnh a->a_lofsvp = targetvp; 94*54751Sjohnh hd = lofs_hash(targetvp); 95*54751Sjohnh insque(a, hd); 96*54751Sjohnh 97*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 98*54751Sjohnh vprint("alloc vp", vp); 99*54751Sjohnh vprint("alloc targetvp", targetvp); 100*54751Sjohnh #endif 101*54751Sjohnh } 102*54751Sjohnh 103*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 104*54751Sjohnh void 105*54751Sjohnh lofs_flushmp(mp) 106*54751Sjohnh struct mount *mp; 107*54751Sjohnh { 108*54751Sjohnh struct lofscache *ac; 109*54751Sjohnh int i = 0; 110*54751Sjohnh struct lofsnode *roota; 111*54751Sjohnh 112*54751Sjohnh printf("lofs_flushmp(%x)\n", mp); 113*54751Sjohnh 114*54751Sjohnh roota = LOFSP(VFSTOLOFS(mp)->rootvp); 115*54751Sjohnh 116*54751Sjohnh for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++) { 117*54751Sjohnh struct lofsnode *a = ac->ac_forw; 118*54751Sjohnh while (a != (struct lofsnode *) ac) { 119*54751Sjohnh if (a != roota && a->a_vnode->v_mount == mp) { 120*54751Sjohnh struct vnode *vp = a->a_lofsvp; 121*54751Sjohnh if (vp) { 122*54751Sjohnh a->a_lofsvp = 0; 123*54751Sjohnh vprint("would vrele", vp); 124*54751Sjohnh /*vrele(vp);*/ 125*54751Sjohnh i++; 126*54751Sjohnh } 127*54751Sjohnh } 128*54751Sjohnh a = a->a_forw; 129*54751Sjohnh } 130*54751Sjohnh } 131*54751Sjohnh if (i > 0) 132*54751Sjohnh printf("lofsnode: vrele'd %d aliases\n", i); 133*54751Sjohnh } 134*54751Sjohnh #endif 135*54751Sjohnh 136*54751Sjohnh /* 137*54751Sjohnh * Return alias for target vnode if already exists, else 0. 138*54751Sjohnh */ 139*54751Sjohnh static struct lofsnode * 140*54751Sjohnh lofs_find(mp, targetvp) 141*54751Sjohnh struct mount *mp; 142*54751Sjohnh struct vnode *targetvp; 143*54751Sjohnh { 144*54751Sjohnh struct lofscache *hd; 145*54751Sjohnh struct lofsnode *a; 146*54751Sjohnh 147*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 148*54751Sjohnh printf("lofs_find(mp = %x, target = %x)\n", mp, targetvp); 149*54751Sjohnh #endif 150*54751Sjohnh 151*54751Sjohnh /* 152*54751Sjohnh * Find hash base, and then search the (two-way) linked 153*54751Sjohnh * list looking for a lofsnode structure which is referencing 154*54751Sjohnh * the target vnode. If found, the increment the lofsnode 155*54751Sjohnh * reference count (but NOT the target vnode's VREF counter). 156*54751Sjohnh */ 157*54751Sjohnh hd = lofs_hash(targetvp); 158*54751Sjohnh 159*54751Sjohnh for (a = hd->ac_forw; a != (struct lofsnode *) hd; a = a->a_forw) { 160*54751Sjohnh if (a->a_lofsvp == targetvp && a->a_vnode->v_mount == mp) { 161*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 162*54751Sjohnh printf("lofs_find(%x): found (%x,%x)->%x\n", 163*54751Sjohnh targetvp, mp, a->a_vnode, targetvp); 164*54751Sjohnh #endif 165*54751Sjohnh return (a); 166*54751Sjohnh } 167*54751Sjohnh } 168*54751Sjohnh 169*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 170*54751Sjohnh printf("lofs_find(%x, %x): NOT found\n", mp, targetvp); 171*54751Sjohnh #endif 172*54751Sjohnh 173*54751Sjohnh return (0); 174*54751Sjohnh } 175*54751Sjohnh 176*54751Sjohnh static int 177*54751Sjohnh lofs_alias(mp, targetvp, newvpp) 178*54751Sjohnh struct mount *mp; 179*54751Sjohnh struct vnode *targetvp; 180*54751Sjohnh struct vnode **newvpp; 181*54751Sjohnh { 182*54751Sjohnh struct lofsnode *ap; 183*54751Sjohnh struct vnode *aliasvp; 184*54751Sjohnh 185*54751Sjohnh if (targetvp->v_type != VDIR || targetvp->v_op == lofs_vnodeop_p) { 186*54751Sjohnh *newvpp = targetvp; 187*54751Sjohnh return; 188*54751Sjohnh } 189*54751Sjohnh 190*54751Sjohnh ap = lofs_find(mp, targetvp); 191*54751Sjohnh 192*54751Sjohnh if (ap) { 193*54751Sjohnh /* 194*54751Sjohnh * Take another reference to the alias vnode 195*54751Sjohnh */ 196*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 197*54751Sjohnh vprint("lofs_alias: exists", ap->a_vnode); 198*54751Sjohnh #endif 199*54751Sjohnh aliasvp = ap->a_vnode; 200*54751Sjohnh VREF(aliasvp); 201*54751Sjohnh } else { 202*54751Sjohnh int error; 203*54751Sjohnh 204*54751Sjohnh /* 205*54751Sjohnh * Get new vnode. 206*54751Sjohnh */ 207*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 208*54751Sjohnh printf("lofs_alias: create new alias vnode\n"); 209*54751Sjohnh #endif 210*54751Sjohnh if (error = getnewvnode(VT_UFS, mp, lofs_vnodeop_p, &aliasvp)) 211*54751Sjohnh return (error); /* XXX: VT_LOFS above */ 212*54751Sjohnh 213*54751Sjohnh /* 214*54751Sjohnh * Must be a directory 215*54751Sjohnh */ 216*54751Sjohnh aliasvp->v_type = VDIR; 217*54751Sjohnh 218*54751Sjohnh /* 219*54751Sjohnh * Make new vnode reference the lofsnode. 220*54751Sjohnh */ 221*54751Sjohnh lofs_alloc(aliasvp, targetvp); 222*54751Sjohnh 223*54751Sjohnh /* 224*54751Sjohnh * aliasvp is already VREF'd by getnewvnode() 225*54751Sjohnh */ 226*54751Sjohnh } 227*54751Sjohnh 228*54751Sjohnh vrele(targetvp); 229*54751Sjohnh 230*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 231*54751Sjohnh vprint("lofs_alias alias", aliasvp); 232*54751Sjohnh vprint("lofs_alias target", targetvp); 233*54751Sjohnh #endif 234*54751Sjohnh 235*54751Sjohnh *newvpp = aliasvp; 236*54751Sjohnh return (0); 237*54751Sjohnh } 238*54751Sjohnh 239*54751Sjohnh /* 240*54751Sjohnh * Try to find an existing lofsnode vnode refering 241*54751Sjohnh * to it, otherwise make a new lofsnode vnode which 242*54751Sjohnh * contains a reference to the target vnode. 243*54751Sjohnh */ 244*54751Sjohnh make_lofs(mp, vpp) 245*54751Sjohnh struct mount *mp; 246*54751Sjohnh struct vnode **vpp; 247*54751Sjohnh { 248*54751Sjohnh int error; 249*54751Sjohnh struct vnode *aliasvp; 250*54751Sjohnh struct vnode *targetvp; 251*54751Sjohnh 252*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 253*54751Sjohnh printf("make_lofs(mp = %x, vp = %x\n", mp, *vpp); 254*54751Sjohnh #endif 255*54751Sjohnh 256*54751Sjohnh /* 257*54751Sjohnh * (targetvp) is locked at this point. 258*54751Sjohnh */ 259*54751Sjohnh targetvp = *vpp; 260*54751Sjohnh 261*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 262*54751Sjohnh if (targetvp == 0) 263*54751Sjohnh panic("make_lofs: null vp"); 264*54751Sjohnh #endif 265*54751Sjohnh 266*54751Sjohnh /* 267*54751Sjohnh * Try to find an existing reference to the target vnodes. 268*54751Sjohnh */ 269*54751Sjohnh return (lofs_alias(mp, targetvp, vpp)); 270*54751Sjohnh } 271*54751Sjohnh 272*54751Sjohnh #ifdef LOFS_DIAGNOSTIC 273*54751Sjohnh struct vnode * 274*54751Sjohnh lofs_checkvp(vp, fil, lno) 275*54751Sjohnh struct vnode *vp; 276*54751Sjohnh char *fil; 277*54751Sjohnh int lno; 278*54751Sjohnh { 279*54751Sjohnh struct lofsnode *a = LOFSP(vp); 280*54751Sjohnh if (a->a_lofsvp == 0) { 281*54751Sjohnh int i; u_long *p; 282*54751Sjohnh printf("vp = %x, ZERO ptr\n", vp); 283*54751Sjohnh #ifdef notdef 284*54751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++) 285*54751Sjohnh printf(" %x", p[i]); 286*54751Sjohnh printf("\n"); 287*54751Sjohnh DELAY(2000000); 288*54751Sjohnh panic("lofs_checkvp"); 289*54751Sjohnh #endif 290*54751Sjohnh } 291*54751Sjohnh printf("aliasvp %x/%d -> %x/%d [%s, %d]\n", 292*54751Sjohnh a->a_vnode, a->a_vnode->v_usecount, 293*54751Sjohnh a->a_lofsvp, a->a_lofsvp ? a->a_lofsvp->v_usecount : -42, 294*54751Sjohnh fil, lno); 295*54751Sjohnh return a->a_lofsvp; 296*54751Sjohnh } 297*54751Sjohnh #endif 298