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