1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software donated to Berkeley by 6 * Jan-Simon Pendry. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)lofs_subr.c 8.5 (Berkeley) 01/21/94 11 * 12 * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 13 */ 14 15 #include <sys/param.h> 16 #include <sys/systm.h> 17 #include <sys/time.h> 18 #include <sys/types.h> 19 #include <sys/vnode.h> 20 #include <sys/mount.h> 21 #include <sys/namei.h> 22 #include <sys/malloc.h> 23 #include <miscfs/lofs/lofs.h> 24 25 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 26 #define NLOFSCACHE 16 27 #define LOFS_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NLOFSCACHE-1)) 28 29 /* 30 * Loopback cache: 31 * Each cache entry holds a reference to the target vnode 32 * along with a pointer to the alias vnode. When an 33 * entry is added the target vnode is VREF'd. When the 34 * alias is removed the target vnode is vrele'd. 35 */ 36 37 /* 38 * Cache head 39 */ 40 struct lofscache { 41 struct lofsnode *ac_forw; 42 struct lofsnode *ac_back; 43 }; 44 45 static struct lofscache lofscache[NLOFSCACHE]; 46 47 /* 48 * Initialise cache headers 49 */ 50 int 51 lofs_init() 52 { 53 struct lofscache *ac; 54 55 for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++) 56 ac->ac_forw = ac->ac_back = (struct lofsnode *) ac; 57 58 return (0); 59 } 60 61 /* 62 * Compute hash list for given target vnode 63 */ 64 static struct lofscache * 65 lofs_hash(targetvp) 66 struct vnode *targetvp; 67 { 68 69 return (&lofscache[LOFS_NHASH(targetvp)]); 70 } 71 72 /* 73 * Make a new lofsnode node. 74 * Vp is the alias vnode, lofsvp is the target vnode. 75 * Maintain a reference to (targetvp). 76 */ 77 static void 78 lofs_alloc(vp, targetvp) 79 struct vnode *vp; 80 struct vnode *targetvp; 81 { 82 struct lofscache *hd; 83 struct lofsnode *a; 84 85 MALLOC(a, struct lofsnode *, sizeof(struct lofsnode), M_TEMP, M_WAITOK); 86 a->a_vnode = vp; 87 vp->v_data = a; 88 VREF(targetvp); 89 a->a_lofsvp = targetvp; 90 hd = lofs_hash(targetvp); 91 insque(a, hd); 92 93 } 94 95 96 /* 97 * Return alias for target vnode if already exists, else 0. 98 */ 99 static struct lofsnode * 100 lofs_find(mp, targetvp) 101 struct mount *mp; 102 struct vnode *targetvp; 103 { 104 struct lofscache *hd; 105 struct lofsnode *a; 106 107 /* 108 * Find hash base, and then search the (two-way) linked 109 * list looking for a lofsnode structure which is referencing 110 * the target vnode. If found, the increment the lofsnode 111 * reference count (but NOT the target vnode's VREF counter). 112 */ 113 hd = lofs_hash(targetvp); 114 115 for (a = hd->ac_forw; a != (struct lofsnode *) hd; a = a->a_forw) { 116 if (a->a_lofsvp == targetvp && a->a_vnode->v_mount == mp) { 117 return (a); 118 } 119 } 120 121 return (0); 122 } 123 124 static int 125 lofs_alias(mp, targetvp, newvpp) 126 struct mount *mp; 127 struct vnode *targetvp; 128 struct vnode **newvpp; 129 { 130 struct lofsnode *ap; 131 struct vnode *aliasvp; 132 133 if (targetvp->v_type != VDIR || targetvp->v_op == lofs_vnodeop_p) { 134 *newvpp = targetvp; 135 return (0); 136 } 137 138 ap = lofs_find(mp, targetvp); 139 140 if (ap) { 141 /* 142 * Take another reference to the alias vnode 143 */ 144 aliasvp = ap->a_vnode; 145 VREF(aliasvp); 146 } else { 147 int error; 148 149 /* 150 * Get new vnode. 151 */ 152 if (error = getnewvnode(VT_LOFS, mp, lofs_vnodeop_p, &aliasvp)) 153 return (error); 154 155 /* 156 * Must be a directory 157 */ 158 aliasvp->v_type = VDIR; 159 160 /* 161 * Make new vnode reference the lofsnode. 162 */ 163 lofs_alloc(aliasvp, targetvp); 164 165 /* 166 * aliasvp is already VREF'd by getnewvnode() 167 */ 168 } 169 170 vrele(targetvp); 171 172 *newvpp = aliasvp; 173 return (0); 174 } 175 176 /* 177 * Try to find an existing lofsnode vnode refering 178 * to it, otherwise make a new lofsnode vnode which 179 * contains a reference to the target vnode. 180 */ 181 int 182 make_lofs(mp, vpp) 183 struct mount *mp; 184 struct vnode **vpp; 185 { 186 struct vnode *targetvp; 187 188 /* 189 * (targetvp) is locked at this point. 190 */ 191 targetvp = *vpp; 192 193 /* 194 * Try to find an existing reference to the target vnodes. 195 */ 196 return (lofs_alias(mp, targetvp, vpp)); 197 } 198 199