153841Spendry /* 263237Sbostic * Copyright (c) 1992, 1993 363237Sbostic * The Regents of the University of California. All rights reserved. 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*65518Spendry * @(#)lofs_subr.c 8.4 (Berkeley) 01/05/94 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> 2455022Smckusick #include <miscfs/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 */ 51*65518Spendry int 5253841Spendry lofs_init() 5353841Spendry { 5453841Spendry struct lofscache *ac; 5553841Spendry 5653841Spendry for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++) 5753841Spendry ac->ac_forw = ac->ac_back = (struct lofsnode *) ac; 58*65518Spendry 59*65518Spendry return (0); 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 { 69*65518Spendry 7053841Spendry return (&lofscache[LOFS_NHASH(targetvp)]); 7153841Spendry } 7253841Spendry 7353841Spendry /* 7453841Spendry * Make a new lofsnode node. 7553841Spendry * Vp is the alias vnode, lofsvp is the target vnode. 7653841Spendry * Maintain a reference to (targetvp). 7753841Spendry */ 7853841Spendry static void 7953841Spendry lofs_alloc(vp, targetvp) 8053841Spendry struct vnode *vp; 8153841Spendry struct vnode *targetvp; 8253841Spendry { 8353841Spendry struct lofscache *hd; 8453841Spendry struct lofsnode *a; 8553841Spendry 8654050Spendry MALLOC(a, struct lofsnode *, sizeof(struct lofsnode), M_TEMP, M_WAITOK); 8753841Spendry a->a_vnode = vp; 8854050Spendry vp->v_data = a; 8953841Spendry VREF(targetvp); 9054050Spendry a->a_lofsvp = targetvp; 9153841Spendry hd = lofs_hash(targetvp); 9253841Spendry insque(a, hd); 9353841Spendry 9453841Spendry } 9553841Spendry 9653841Spendry 9753841Spendry /* 9853841Spendry * Return alias for target vnode if already exists, else 0. 9953841Spendry */ 10053841Spendry static struct lofsnode * 10153841Spendry lofs_find(mp, targetvp) 10253841Spendry struct mount *mp; 10353841Spendry struct vnode *targetvp; 10453841Spendry { 10553841Spendry struct lofscache *hd; 10653841Spendry struct lofsnode *a; 10753841Spendry 10853841Spendry /* 10953841Spendry * Find hash base, and then search the (two-way) linked 11053841Spendry * list looking for a lofsnode structure which is referencing 11153841Spendry * the target vnode. If found, the increment the lofsnode 11253841Spendry * reference count (but NOT the target vnode's VREF counter). 11353841Spendry */ 11453841Spendry hd = lofs_hash(targetvp); 11553841Spendry 11653841Spendry for (a = hd->ac_forw; a != (struct lofsnode *) hd; a = a->a_forw) { 11753841Spendry if (a->a_lofsvp == targetvp && a->a_vnode->v_mount == mp) { 11853841Spendry return (a); 11953841Spendry } 12053841Spendry } 12153841Spendry 12253841Spendry return (0); 12353841Spendry } 12453841Spendry 12553841Spendry static int 12653841Spendry lofs_alias(mp, targetvp, newvpp) 12753841Spendry struct mount *mp; 12853841Spendry struct vnode *targetvp; 12953841Spendry struct vnode **newvpp; 13053841Spendry { 13153841Spendry struct lofsnode *ap; 13253841Spendry struct vnode *aliasvp; 13353841Spendry 13453841Spendry if (targetvp->v_type != VDIR || targetvp->v_op == lofs_vnodeop_p) { 13553841Spendry *newvpp = targetvp; 13659741Spendry return (0); 13753841Spendry } 13853841Spendry 13953841Spendry ap = lofs_find(mp, targetvp); 14053841Spendry 14153841Spendry if (ap) { 14253841Spendry /* 14353841Spendry * Take another reference to the alias vnode 14453841Spendry */ 14553841Spendry aliasvp = ap->a_vnode; 14653841Spendry VREF(aliasvp); 14753841Spendry } else { 14853841Spendry int error; 14953841Spendry 15053841Spendry /* 15153841Spendry * Get new vnode. 15253841Spendry */ 15365380Spendry if (error = getnewvnode(VT_LOFS, mp, lofs_vnodeop_p, &aliasvp)) 15465380Spendry return (error); 15553841Spendry 15653841Spendry /* 15753841Spendry * Must be a directory 15853841Spendry */ 15953841Spendry aliasvp->v_type = VDIR; 16053841Spendry 16153841Spendry /* 16253841Spendry * Make new vnode reference the lofsnode. 16353841Spendry */ 16453841Spendry lofs_alloc(aliasvp, targetvp); 16553841Spendry 16653841Spendry /* 16753841Spendry * aliasvp is already VREF'd by getnewvnode() 16853841Spendry */ 16953841Spendry } 17053841Spendry 17153841Spendry vrele(targetvp); 17253841Spendry 17353841Spendry *newvpp = aliasvp; 17453841Spendry return (0); 17553841Spendry } 17653841Spendry 17753841Spendry /* 17853841Spendry * Try to find an existing lofsnode vnode refering 17953841Spendry * to it, otherwise make a new lofsnode vnode which 18053841Spendry * contains a reference to the target vnode. 18153841Spendry */ 182*65518Spendry int 18353841Spendry make_lofs(mp, vpp) 18453841Spendry struct mount *mp; 18553841Spendry struct vnode **vpp; 18653841Spendry { 18753841Spendry struct vnode *targetvp; 18853841Spendry 18953841Spendry /* 19053841Spendry * (targetvp) is locked at this point. 19153841Spendry */ 19253841Spendry targetvp = *vpp; 19353841Spendry 19453841Spendry /* 19553841Spendry * Try to find an existing reference to the target vnodes. 19653841Spendry */ 19753841Spendry return (lofs_alias(mp, targetvp, vpp)); 19853841Spendry } 19953841Spendry 200