1 /* 2 * Copyright (c) 1992 The Regents of the University of California 3 * Copyright (c) 1990, 1992 Jan-Simon Pendry 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 1.2 (Berkeley) 6/18/92 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 <umapfs/umap.h> 25 26 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 27 #define NUMAPNODECACHE 16 28 #define UMAP_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NUMAPNODECACHE-1)) 29 30 /* 31 * Null layer 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 umap_node_cache { 42 struct umap_node *ac_forw; 43 struct umap_node *ac_back; 44 }; 45 46 static struct umap_node_cache umap_node_cache[NUMAPNODECACHE]; 47 48 /* 49 * Initialise cache headers 50 */ 51 umapfs_init() 52 { 53 struct umap_node_cache *ac; 54 #ifdef UMAPFS_DIAGNOSTIC 55 printf("umapfs_init\n"); /* printed during system boot */ 56 #endif 57 58 for (ac = umap_node_cache; ac < umap_node_cache + NUMAPNODECACHE; ac++) 59 ac->ac_forw = ac->ac_back = (struct umap_node *) ac; 60 } 61 62 /* 63 * Compute hash list for given target vnode 64 */ 65 static struct umap_node_cache * 66 umap_node_hash(targetvp) 67 struct vnode *targetvp; 68 { 69 return (&umap_node_cache[UMAP_NHASH(targetvp)]); 70 } 71 72 /* 73 * Make a new umap_node node. 74 * Vp is the alias vnode, lofsvp is the target vnode. 75 * Maintain a reference to (targetvp). 76 */ 77 static void 78 umap_node_alloc(vp, targetvp) 79 struct vnode *vp; 80 struct vnode *targetvp; 81 { 82 struct umap_node_cache *hd; 83 struct umap_node *a; 84 85 #ifdef UMAPFS_DIAGNOSTIC 86 printf("umap_node_alloc(%x, %x)\n", vp, targetvp); 87 #endif 88 89 MALLOC(a, struct umap_node *, sizeof(struct umap_node), M_TEMP, M_WAITOK); 90 vp->v_type = targetvp->v_type; 91 a->umap_vnode = vp; 92 vp->v_data = a; 93 VREF(targetvp); /* Extra VREF will be vrele'd in umap_node_create */ 94 a->umap_lowervp = targetvp; 95 hd = umap_node_hash(targetvp); 96 insque(a, hd); 97 98 #ifdef UMAPFS_DIAGNOSTIC 99 vprint("umap_node_alloc vp", vp); 100 vprint("umap_node_alloc targetvp", targetvp); 101 #endif 102 } 103 104 #ifdef UMAPFS_DIAGNOSTIC 105 /* 106 * NEEDSWORK: The ability to set lowervp to umap here 107 * implies that one can never count on lowervp staying umap 108 * (even if vp is locked). This seems quite bad. Think 109 * about these things. 110 */ 111 void 112 umap_node_flushmp (mp) 113 struct mount *mp; 114 { 115 struct umap_node_cache *ac; 116 int i = 0; 117 struct umap_node *roota; 118 119 printf("umap_node_flushmp (%x)\n", mp); 120 121 roota = VTOUMAP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp); 122 123 for (ac = umap_node_cache; ac < umap_node_cache + NUMAPNODECACHE; ac++) { 124 struct umap_node *a = ac->ac_forw; 125 while (a != (struct umap_node *) ac) { 126 if (a != roota && a->umap_vnode->v_mount == mp) { 127 struct vnode *vp = a->umap_lowervp; 128 if (vp) { 129 a->umap_lowervp = 0; 130 vprint("umap_flushmp: would vrele", vp); 131 /*vrele(vp);*/ 132 i++; 133 } 134 } 135 a = a->umap_forw; 136 } 137 } 138 if (i > 0) 139 printf("umap_node: vrele'd %d aliases\n", i); 140 } 141 #endif 142 143 /* 144 * Return alias for target vnode if already exists, else 0. 145 */ 146 static struct umap_node * 147 umap_node_find(mp, targetvp) 148 struct mount *mp; 149 struct vnode *targetvp; 150 { 151 struct umap_node_cache *hd; 152 struct umap_node *a; 153 154 #ifdef UMAPFS_DIAGNOSTIC 155 printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp); 156 #endif 157 158 /* 159 * Find hash base, and then search the (two-way) linked 160 * list looking for a umap_node structure which is referencing 161 * the target vnode. If found, the increment the umap_node 162 * reference count (but NOT the target vnode's VREF counter). 163 */ 164 hd = umap_node_hash(targetvp); 165 166 for (a = hd->ac_forw; a != (struct umap_node *) hd; a = a->umap_forw) { 167 if (a->umap_lowervp == targetvp && a->umap_vnode->v_mount == mp) { 168 #ifdef UMAPFS_DIAGNOSTIC 169 printf("umap_node_find(%x): found (%x,%x)->%x\n", 170 targetvp, mp, a->umap_vnode, targetvp); 171 #endif 172 return (a); 173 } 174 } 175 176 #ifdef UMAPFS_DIAGNOSTIC 177 printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp); 178 #endif 179 180 return (0); 181 } 182 183 /* 184 * Try to find an existing umap_node vnode refering 185 * to it, otherwise make a new umap_node vnode which 186 * contains a reference to the target vnode. 187 */ 188 int 189 umap_node_create(mp, targetvp, newvpp) 190 struct mount *mp; 191 struct vnode *targetvp; 192 struct vnode **newvpp; 193 { 194 struct umap_node *ap; 195 struct vnode *aliasvp; 196 197 ap = umap_node_find(mp, targetvp); 198 199 if (ap) { 200 /* 201 * Take another reference to the alias vnode 202 */ 203 #ifdef UMAPFS_DIAGNOSTIC 204 vprint("umap_node_create: exists", ap->umap_vnode); 205 #endif 206 aliasvp = ap->umap_vnode; 207 VREF(aliasvp); 208 } else { 209 int error; 210 211 /* 212 * Get new vnode. 213 */ 214 #ifdef UMAPFS_DIAGNOSTIC 215 printf("umap_node_create: create new alias vnode\n"); 216 #endif 217 if (error = getnewvnode(VT_UFS, mp, umap_vnodeop_p, &aliasvp)) 218 return (error); /* XXX: VT_LOFS above */ 219 220 /* 221 * Make new vnode reference the umap_node. 222 */ 223 umap_node_alloc(aliasvp, targetvp); 224 225 /* 226 * aliasvp is already VREF'd by getnewvnode() 227 */ 228 } 229 230 vrele(targetvp); 231 232 #ifdef UMAPFS_DIAGNOSTIC 233 vprint("umap_node_create: alias", aliasvp); 234 vprint("umap_node_create: target", targetvp); 235 #endif 236 237 *newvpp = aliasvp; 238 return (0); 239 } 240 #ifdef UMAPFS_DIAGNOSTIC 241 int umap_checkvp_barrier = 1; 242 struct vnode * 243 umap_checkvp(vp, fil, lno) 244 struct vnode *vp; 245 char *fil; 246 int lno; 247 { 248 struct umap_node *a = VTOUMAP(vp); 249 #if 0 250 /* 251 * Can't do this check because vop_reclaim runs 252 * with funny vop vector. 253 */ 254 if (vp->v_op != umap_vnodeop_p) { 255 printf ("umap_checkvp: on non-umap-node\n"); 256 while (umap_checkvp_barrier) /*WAIT*/ ; 257 panic("umap_checkvp"); 258 }; 259 #endif 260 if (a->umap_lowervp == NULL) { 261 /* Should never happen */ 262 int i; u_long *p; 263 printf("vp = %x, ZERO ptr\n", vp); 264 for (p = (u_long *) a, i = 0; i < 8; i++) 265 printf(" %x", p[i]); 266 printf("\n"); 267 /* wait for debugger */ 268 while (umap_checkvp_barrier) /*WAIT*/ ; 269 panic("umap_checkvp"); 270 } 271 if (a->umap_lowervp->v_usecount < 1) { 272 int i; u_long *p; 273 printf("vp = %x, unref'ed lowervp\n", vp); 274 for (p = (u_long *) a, i = 0; i < 8; i++) 275 printf(" %x", p[i]); 276 printf("\n"); 277 /* wait for debugger */ 278 while (umap_checkvp_barrier) /*WAIT*/ ; 279 panic ("umap with unref'ed lowervp"); 280 }; 281 #if 0 282 printf("umap %x/%d -> %x/%d [%s, %d]\n", 283 a->umap_vnode, a->umap_vnode->v_usecount, 284 a->umap_lowervp, a->umap_lowervp->v_usecount, 285 fil, lno); 286 #endif 287 return a->umap_lowervp; 288 } 289 #endif 290 291 /* umap_mapids maps all of the ids in a credential, both user and group. */ 292 293 umap_mapids(credp,usermap,unentries,groupmap,gnentries) 294 struct ucred *credp; 295 int * usermap, groupmap; 296 int unentries,gnentries; 297 { 298 int i,gid,uid; 299 300 /* Find uid entry in map */ 301 302 uid = umap_findid(credp->cr_uid,usermap,unentries); 303 304 if (uid != -1) { 305 credp->cr_ruid = 306 credp->cr_uid = 307 (u_short)uid; 308 } else 309 credp->cr_ruid = credp->cr_uid = (u_short)NOBODY; 310 311 /* Find gid entry in map */ 312 313 gid = umap_findid(credp->cr_gid,groupmap,gnentries); 314 315 if (gid != -1) { 316 credp->cr_rgid = 317 credp->cr_gid = 318 (u_short)gid; 319 } else 320 credp->cr_rgid = credp->cr_gid = (u_short)NULLGROUP; 321 322 /* Now we must map each of the set of groups in the cr_groups 323 structure. */ 324 325 i = 0; 326 while (credp->cr_groups[i] != 0) 327 { 328 gid = umap_findid(credp->cr_groups[i],groupmap, 329 gnentries); 330 331 if (gid != -1) 332 credp->cr_groups[i++] = (u_short)gid; 333 else 334 credp->cr_groups[i++] = (u_short)NULLGROUP; 335 336 } 337 } 338 339 /* umap_findid is called by various routines in umap_vnodeops.c to 340 * find a user or group id in a map. 341 */ 342 343 umap_findid(id,map,nentries) 344 ushort id; 345 int map[][2]; 346 int nentries; 347 { 348 int i; 349 350 /* Find uid entry in map */ 351 i = 0; 352 while ((i<nentries) && ((u_short)(map[i][0] ) != id)) 353 i++; 354 355 if ( i < nentries ) 356 return (map[i][1]); 357 else 358 return (-1); 359 360 } 361 362 /* umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to 363 * find a user or group id in a map, in reverse. 364 */ 365 366 umap_reverse_findid(id,map,nentries) 367 ushort id; 368 int map[][2]; 369 int nentries; 370 { 371 int i; 372 373 /* Find uid entry in map */ 374 i = 0; 375 while ((i<nentries) && ((u_short)(map[i][1] ) != id)) 376 i++; 377 378 if ( i < nentries ) 379 return (map[i][0]); 380 else 381 return (-1); 382 383 } 384 385