153841Spendry /* 253841Spendry * Copyright (c) 1992 The Regents of the University of California 353841Spendry * Copyright (c) 1990, 1992 Jan-Simon Pendry 453841Spendry * All rights reserved. 553841Spendry * 653841Spendry * This code is derived from software donated to Berkeley by 753841Spendry * Jan-Simon Pendry. 853841Spendry * 953841Spendry * %sccs.include.redist.c% 1053841Spendry * 11*54050Spendry * @(#)lofs_subr.c 1.2 (Berkeley) 06/18/92 1253841Spendry * 1353841Spendry * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 1453841Spendry */ 1553841Spendry 1653841Spendry #include <sys/param.h> 1753841Spendry #include <sys/systm.h> 1853841Spendry #include <sys/time.h> 1953841Spendry #include <sys/types.h> 2053841Spendry #include <sys/vnode.h> 2153841Spendry #include <sys/mount.h> 2253841Spendry #include <sys/namei.h> 2353841Spendry #include <sys/malloc.h> 2453841Spendry #include <lofs/lofs.h> 2553841Spendry 2653841Spendry #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 2753841Spendry #define NLOFSCACHE 16 2853841Spendry #define LOFS_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NLOFSCACHE-1)) 2953841Spendry 3053841Spendry /* 3153841Spendry * Loopback cache: 3253841Spendry * Each cache entry holds a reference to the target vnode 3353841Spendry * along with a pointer to the alias vnode. When an 3453841Spendry * entry is added the target vnode is VREF'd. When the 3553841Spendry * alias is removed the target vnode is vrele'd. 3653841Spendry */ 3753841Spendry 3853841Spendry /* 3953841Spendry * Cache head 4053841Spendry */ 4153841Spendry struct lofscache { 4253841Spendry struct lofsnode *ac_forw; 4353841Spendry struct lofsnode *ac_back; 4453841Spendry }; 4553841Spendry 4653841Spendry static struct lofscache lofscache[NLOFSCACHE]; 4753841Spendry 4853841Spendry /* 4953841Spendry * Initialise cache headers 5053841Spendry */ 5153841Spendry lofs_init() 5253841Spendry { 5353841Spendry struct lofscache *ac; 5453841Spendry #ifdef LOFS_DIAGNOSTIC 5553841Spendry printf("lofs_init\n"); /* printed during system boot */ 5653841Spendry #endif 5753841Spendry 5853841Spendry for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++) 5953841Spendry ac->ac_forw = ac->ac_back = (struct lofsnode *) ac; 6053841Spendry } 6153841Spendry 6253841Spendry /* 6353841Spendry * Compute hash list for given target vnode 6453841Spendry */ 6553841Spendry static struct lofscache * 6653841Spendry lofs_hash(targetvp) 6753841Spendry struct vnode *targetvp; 6853841Spendry { 6953841Spendry return (&lofscache[LOFS_NHASH(targetvp)]); 7053841Spendry } 7153841Spendry 7253841Spendry /* 7353841Spendry * Make a new lofsnode node. 7453841Spendry * Vp is the alias vnode, lofsvp is the target vnode. 7553841Spendry * Maintain a reference to (targetvp). 7653841Spendry */ 7753841Spendry static void 7853841Spendry lofs_alloc(vp, targetvp) 7953841Spendry struct vnode *vp; 8053841Spendry struct vnode *targetvp; 8153841Spendry { 8253841Spendry struct lofscache *hd; 8353841Spendry struct lofsnode *a; 8453841Spendry 8553841Spendry #ifdef LOFS_DIAGNOSTIC 8653841Spendry printf("lofs_alloc(%x, %x)\n", vp, targetvp); 8753841Spendry #endif 8853841Spendry 89*54050Spendry MALLOC(a, struct lofsnode *, sizeof(struct lofsnode), M_TEMP, M_WAITOK); 9053841Spendry a->a_vnode = vp; 91*54050Spendry vp->v_data = a; 9253841Spendry VREF(targetvp); 93*54050Spendry a->a_lofsvp = targetvp; 9453841Spendry hd = lofs_hash(targetvp); 9553841Spendry insque(a, hd); 9653841Spendry 9753841Spendry #ifdef LOFS_DIAGNOSTIC 9853841Spendry vprint("alloc vp", vp); 9953841Spendry vprint("alloc targetvp", targetvp); 10053841Spendry #endif 10153841Spendry } 10253841Spendry 10353841Spendry #ifdef LOFS_DIAGNOSTIC 10453841Spendry void 10553841Spendry lofs_flushmp(mp) 10653841Spendry struct mount *mp; 10753841Spendry { 10853841Spendry struct lofscache *ac; 10953841Spendry int i = 0; 11053841Spendry struct lofsnode *roota; 11153841Spendry 11253841Spendry printf("lofs_flushmp(%x)\n", mp); 11353841Spendry 11453841Spendry roota = LOFSP(VFSTOLOFS(mp)->rootvp); 11553841Spendry 11653841Spendry for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++) { 11753841Spendry struct lofsnode *a = ac->ac_forw; 11853841Spendry while (a != (struct lofsnode *) ac) { 11953841Spendry if (a != roota && a->a_vnode->v_mount == mp) { 12053841Spendry struct vnode *vp = a->a_lofsvp; 12153841Spendry if (vp) { 12253841Spendry a->a_lofsvp = 0; 12353841Spendry vprint("would vrele", vp); 12453841Spendry /*vrele(vp);*/ 12553841Spendry i++; 12653841Spendry } 12753841Spendry } 12853841Spendry a = a->a_forw; 12953841Spendry } 13053841Spendry } 13153841Spendry if (i > 0) 13253841Spendry printf("lofsnode: vrele'd %d aliases\n", i); 13353841Spendry } 13453841Spendry #endif 13553841Spendry 13653841Spendry /* 13753841Spendry * Return alias for target vnode if already exists, else 0. 13853841Spendry */ 13953841Spendry static struct lofsnode * 14053841Spendry lofs_find(mp, targetvp) 14153841Spendry struct mount *mp; 14253841Spendry struct vnode *targetvp; 14353841Spendry { 14453841Spendry struct lofscache *hd; 14553841Spendry struct lofsnode *a; 14653841Spendry 14753841Spendry #ifdef LOFS_DIAGNOSTIC 14853841Spendry printf("lofs_find(mp = %x, target = %x)\n", mp, targetvp); 14953841Spendry #endif 15053841Spendry 15153841Spendry /* 15253841Spendry * Find hash base, and then search the (two-way) linked 15353841Spendry * list looking for a lofsnode structure which is referencing 15453841Spendry * the target vnode. If found, the increment the lofsnode 15553841Spendry * reference count (but NOT the target vnode's VREF counter). 15653841Spendry */ 15753841Spendry hd = lofs_hash(targetvp); 15853841Spendry 15953841Spendry for (a = hd->ac_forw; a != (struct lofsnode *) hd; a = a->a_forw) { 16053841Spendry if (a->a_lofsvp == targetvp && a->a_vnode->v_mount == mp) { 16153841Spendry #ifdef LOFS_DIAGNOSTIC 16253841Spendry printf("lofs_find(%x): found (%x,%x)->%x\n", 16353841Spendry targetvp, mp, a->a_vnode, targetvp); 16453841Spendry #endif 16553841Spendry return (a); 16653841Spendry } 16753841Spendry } 16853841Spendry 16953841Spendry #ifdef LOFS_DIAGNOSTIC 17053841Spendry printf("lofs_find(%x, %x): NOT found\n", mp, targetvp); 17153841Spendry #endif 17253841Spendry 17353841Spendry return (0); 17453841Spendry } 17553841Spendry 17653841Spendry static int 17753841Spendry lofs_alias(mp, targetvp, newvpp) 17853841Spendry struct mount *mp; 17953841Spendry struct vnode *targetvp; 18053841Spendry struct vnode **newvpp; 18153841Spendry { 18253841Spendry struct lofsnode *ap; 18353841Spendry struct vnode *aliasvp; 18453841Spendry 18553841Spendry if (targetvp->v_type != VDIR || targetvp->v_op == lofs_vnodeop_p) { 18653841Spendry *newvpp = targetvp; 18753841Spendry return; 18853841Spendry } 18953841Spendry 19053841Spendry ap = lofs_find(mp, targetvp); 19153841Spendry 19253841Spendry if (ap) { 19353841Spendry /* 19453841Spendry * Take another reference to the alias vnode 19553841Spendry */ 19653841Spendry #ifdef LOFS_DIAGNOSTIC 19753841Spendry vprint("lofs_alias: exists", ap->a_vnode); 19853841Spendry #endif 19953841Spendry aliasvp = ap->a_vnode; 20053841Spendry VREF(aliasvp); 20153841Spendry } else { 20253841Spendry int error; 20353841Spendry 20453841Spendry /* 20553841Spendry * Get new vnode. 20653841Spendry */ 20753841Spendry #ifdef LOFS_DIAGNOSTIC 20853841Spendry printf("lofs_alias: create new alias vnode\n"); 20953841Spendry #endif 21053841Spendry if (error = getnewvnode(VT_UFS, mp, lofs_vnodeop_p, &aliasvp)) 21153841Spendry return (error); /* XXX: VT_LOFS above */ 21253841Spendry 21353841Spendry /* 21453841Spendry * Must be a directory 21553841Spendry */ 21653841Spendry aliasvp->v_type = VDIR; 21753841Spendry 21853841Spendry /* 21953841Spendry * Make new vnode reference the lofsnode. 22053841Spendry */ 22153841Spendry lofs_alloc(aliasvp, targetvp); 22253841Spendry 22353841Spendry /* 22453841Spendry * aliasvp is already VREF'd by getnewvnode() 22553841Spendry */ 22653841Spendry } 22753841Spendry 22853841Spendry vrele(targetvp); 22953841Spendry 23053841Spendry #ifdef LOFS_DIAGNOSTIC 23153841Spendry vprint("lofs_alias alias", aliasvp); 23253841Spendry vprint("lofs_alias target", targetvp); 23353841Spendry #endif 23453841Spendry 23553841Spendry *newvpp = aliasvp; 23653841Spendry return (0); 23753841Spendry } 23853841Spendry 23953841Spendry /* 24053841Spendry * Try to find an existing lofsnode vnode refering 24153841Spendry * to it, otherwise make a new lofsnode vnode which 24253841Spendry * contains a reference to the target vnode. 24353841Spendry */ 24453841Spendry make_lofs(mp, vpp) 24553841Spendry struct mount *mp; 24653841Spendry struct vnode **vpp; 24753841Spendry { 24853841Spendry int error; 24953841Spendry struct vnode *aliasvp; 25053841Spendry struct vnode *targetvp; 25153841Spendry 25253841Spendry #ifdef LOFS_DIAGNOSTIC 25353841Spendry printf("make_lofs(mp = %x, vp = %x\n", mp, *vpp); 25453841Spendry #endif 25553841Spendry 25653841Spendry /* 25753841Spendry * (targetvp) is locked at this point. 25853841Spendry */ 25953841Spendry targetvp = *vpp; 26053841Spendry 26153841Spendry #ifdef LOFS_DIAGNOSTIC 26253841Spendry if (targetvp == 0) 26353841Spendry panic("make_lofs: null vp"); 26453841Spendry #endif 26553841Spendry 26653841Spendry /* 26753841Spendry * Try to find an existing reference to the target vnodes. 26853841Spendry */ 26953841Spendry return (lofs_alias(mp, targetvp, vpp)); 27053841Spendry } 27153841Spendry 27253841Spendry #ifdef LOFS_DIAGNOSTIC 27353841Spendry struct vnode * 27453841Spendry lofs_checkvp(vp, fil, lno) 27553841Spendry struct vnode *vp; 27653841Spendry char *fil; 27753841Spendry int lno; 27853841Spendry { 27953841Spendry struct lofsnode *a = LOFSP(vp); 28053841Spendry if (a->a_lofsvp == 0) { 28153841Spendry int i; u_long *p; 28253841Spendry printf("vp = %x, ZERO ptr\n", vp); 28353841Spendry #ifdef notdef 28453841Spendry for (p = (u_long *) a, i = 0; i < 8; i++) 28553841Spendry printf(" %x", p[i]); 28653841Spendry printf("\n"); 28753841Spendry DELAY(2000000); 28853841Spendry panic("lofs_checkvp"); 28953841Spendry #endif 29053841Spendry } 29153841Spendry printf("aliasvp %x/%d -> %x/%d [%s, %d]\n", 29253841Spendry a->a_vnode, a->a_vnode->v_usecount, 29353841Spendry a->a_lofsvp, a->a_lofsvp ? a->a_lofsvp->v_usecount : -42, 29453841Spendry fil, lno); 29553841Spendry return a->a_lofsvp; 29653841Spendry } 29753841Spendry #endif 298