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.4 (Berkeley) 01/05/94 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 int 52 lofs_init() 53 { 54 struct lofscache *ac; 55 56 for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++) 57 ac->ac_forw = ac->ac_back = (struct lofsnode *) ac; 58 59 return (0); 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 70 return (&lofscache[LOFS_NHASH(targetvp)]); 71 } 72 73 /* 74 * Make a new lofsnode node. 75 * Vp is the alias vnode, lofsvp is the target vnode. 76 * Maintain a reference to (targetvp). 77 */ 78 static void 79 lofs_alloc(vp, targetvp) 80 struct vnode *vp; 81 struct vnode *targetvp; 82 { 83 struct lofscache *hd; 84 struct lofsnode *a; 85 86 MALLOC(a, struct lofsnode *, sizeof(struct lofsnode), M_TEMP, M_WAITOK); 87 a->a_vnode = vp; 88 vp->v_data = a; 89 VREF(targetvp); 90 a->a_lofsvp = targetvp; 91 hd = lofs_hash(targetvp); 92 insque(a, hd); 93 94 } 95 96 97 /* 98 * Return alias for target vnode if already exists, else 0. 99 */ 100 static struct lofsnode * 101 lofs_find(mp, targetvp) 102 struct mount *mp; 103 struct vnode *targetvp; 104 { 105 struct lofscache *hd; 106 struct lofsnode *a; 107 108 /* 109 * Find hash base, and then search the (two-way) linked 110 * list looking for a lofsnode structure which is referencing 111 * the target vnode. If found, the increment the lofsnode 112 * reference count (but NOT the target vnode's VREF counter). 113 */ 114 hd = lofs_hash(targetvp); 115 116 for (a = hd->ac_forw; a != (struct lofsnode *) hd; a = a->a_forw) { 117 if (a->a_lofsvp == targetvp && a->a_vnode->v_mount == mp) { 118 return (a); 119 } 120 } 121 122 return (0); 123 } 124 125 static int 126 lofs_alias(mp, targetvp, newvpp) 127 struct mount *mp; 128 struct vnode *targetvp; 129 struct vnode **newvpp; 130 { 131 struct lofsnode *ap; 132 struct vnode *aliasvp; 133 134 if (targetvp->v_type != VDIR || targetvp->v_op == lofs_vnodeop_p) { 135 *newvpp = targetvp; 136 return (0); 137 } 138 139 ap = lofs_find(mp, targetvp); 140 141 if (ap) { 142 /* 143 * Take another reference to the alias vnode 144 */ 145 aliasvp = ap->a_vnode; 146 VREF(aliasvp); 147 } else { 148 int error; 149 150 /* 151 * Get new vnode. 152 */ 153 if (error = getnewvnode(VT_LOFS, mp, lofs_vnodeop_p, &aliasvp)) 154 return (error); 155 156 /* 157 * Must be a directory 158 */ 159 aliasvp->v_type = VDIR; 160 161 /* 162 * Make new vnode reference the lofsnode. 163 */ 164 lofs_alloc(aliasvp, targetvp); 165 166 /* 167 * aliasvp is already VREF'd by getnewvnode() 168 */ 169 } 170 171 vrele(targetvp); 172 173 *newvpp = aliasvp; 174 return (0); 175 } 176 177 /* 178 * Try to find an existing lofsnode vnode refering 179 * to it, otherwise make a new lofsnode vnode which 180 * contains a reference to the target vnode. 181 */ 182 int 183 make_lofs(mp, vpp) 184 struct mount *mp; 185 struct vnode **vpp; 186 { 187 struct vnode *targetvp; 188 189 /* 190 * (targetvp) is locked at this point. 191 */ 192 targetvp = *vpp; 193 194 /* 195 * Try to find an existing reference to the target vnodes. 196 */ 197 return (lofs_alias(mp, targetvp, vpp)); 198 } 199 200