1 /* $NetBSD: umap_subr.c,v 1.4 1994/09/20 06:43:02 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp 39 * @(#)umap_subr.c 8.6 (Berkeley) 1/26/94 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/time.h> 45 #include <sys/types.h> 46 #include <sys/vnode.h> 47 #include <sys/mount.h> 48 #include <sys/namei.h> 49 #include <sys/malloc.h> 50 #include <miscfs/specfs/specdev.h> 51 #include <miscfs/umapfs/umap.h> 52 53 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 54 #define NUMAPNODECACHE 16 55 56 /* 57 * Null layer cache: 58 * Each cache entry holds a reference to the target vnode 59 * along with a pointer to the alias vnode. When an 60 * entry is added the target vnode is VREF'd. When the 61 * alias is removed the target vnode is vrele'd. 62 */ 63 64 #define UMAP_NHASH(vp) \ 65 (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash]) 66 LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl; 67 u_long umap_node_hash; 68 69 /* 70 * Initialise cache headers 71 */ 72 umapfs_init() 73 { 74 75 #ifdef UMAPFS_DIAGNOSTIC 76 printf("umapfs_init\n"); /* printed during system boot */ 77 #endif 78 umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash); 79 } 80 81 /* 82 * umap_findid is called by various routines in umap_vnodeops.c to 83 * find a user or group id in a map. 84 */ 85 static u_long 86 umap_findid(id, map, nentries) 87 u_long id; 88 u_long map[][2]; 89 int nentries; 90 { 91 int i; 92 93 /* Find uid entry in map */ 94 i = 0; 95 while ((i<nentries) && ((map[i][0]) != id)) 96 i++; 97 98 if (i < nentries) 99 return (map[i][1]); 100 else 101 return (-1); 102 103 } 104 105 /* 106 * umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to 107 * find a user or group id in a map, in reverse. 108 */ 109 u_long 110 umap_reverse_findid(id, map, nentries) 111 u_long id; 112 u_long map[][2]; 113 int nentries; 114 { 115 int i; 116 117 /* Find uid entry in map */ 118 i = 0; 119 while ((i<nentries) && ((map[i][1]) != id)) 120 i++; 121 122 if (i < nentries) 123 return (map[i][0]); 124 else 125 return (-1); 126 127 } 128 129 /* 130 * Return alias for target vnode if already exists, else 0. 131 */ 132 static struct vnode * 133 umap_node_find(mp, targetvp) 134 struct mount *mp; 135 struct vnode *targetvp; 136 { 137 struct umap_node_hashhead *hd; 138 struct umap_node *a; 139 struct vnode *vp; 140 141 #ifdef UMAPFS_DIAGNOSTIC 142 printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp); 143 #endif 144 145 /* 146 * Find hash base, and then search the (two-way) linked 147 * list looking for a umap_node structure which is referencing 148 * the target vnode. If found, the increment the umap_node 149 * reference count (but NOT the target vnode's VREF counter). 150 */ 151 hd = UMAP_NHASH(targetvp); 152 loop: 153 for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) { 154 if (a->umap_lowervp == targetvp && 155 a->umap_vnode->v_mount == mp) { 156 vp = UMAPTOV(a); 157 /* 158 * We need vget for the VXLOCK 159 * stuff, but we don't want to lock 160 * the lower node. 161 */ 162 if (vget(vp, 0)) { 163 #ifdef UMAPFS_DIAGNOSTIC 164 printf ("umap_node_find: vget failed.\n"); 165 #endif 166 goto loop; 167 } 168 return (vp); 169 } 170 } 171 172 #ifdef UMAPFS_DIAGNOSTIC 173 printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp); 174 #endif 175 176 return (0); 177 } 178 179 /* 180 * Make a new umap_node node. 181 * Vp is the alias vnode, lowervp is the target vnode. 182 * Maintain a reference to lowervp. 183 */ 184 static int 185 umap_node_alloc(mp, lowervp, vpp) 186 struct mount *mp; 187 struct vnode *lowervp; 188 struct vnode **vpp; 189 { 190 struct umap_node_hashhead *hd; 191 struct umap_node *xp; 192 struct vnode *vp, *nvp; 193 int error; 194 extern int (**dead_vnodeop_p)(); 195 196 if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, &vp)) 197 return (error); 198 vp->v_type = lowervp->v_type; 199 200 MALLOC(xp, struct umap_node *, sizeof(struct umap_node), M_TEMP, 201 M_WAITOK); 202 if (vp->v_type == VBLK || vp->v_type == VCHR) { 203 MALLOC(vp->v_specinfo, struct specinfo *, 204 sizeof(struct specinfo), M_VNODE, M_WAITOK); 205 vp->v_rdev = lowervp->v_rdev; 206 } 207 208 vp->v_data = xp; 209 xp->umap_vnode = vp; 210 xp->umap_lowervp = lowervp; 211 /* 212 * Before we insert our new node onto the hash chains, 213 * check to see if someone else has beaten us to it. 214 * (We could have slept in MALLOC.) 215 */ 216 if (nvp = umap_node_find(lowervp)) { 217 *vpp = nvp; 218 219 /* free the substructures we've allocated. */ 220 FREE(xp, M_TEMP); 221 if (vp->v_type == VBLK || vp->v_type == VCHR) 222 FREE(vp->v_specinfo, M_VNODE); 223 224 vp->v_type = VBAD; /* node is discarded */ 225 vp->v_op = dead_vnodeop_p; /* so ops will still work */ 226 vrele(vp); /* get rid of it. */ 227 return (0); 228 } 229 230 /* 231 * XXX if it's a device node, it needs to be checkalias()ed. 232 * however, for locking reasons, that's just not possible. 233 * so we have to do most of the dirty work inline. Note that 234 * this is a limited case; we know that there's going to be 235 * an alias, and we know that that alias will be a "real" 236 * device node, i.e. not tagged VT_NON. 237 */ 238 if (vp->v_type == VBLK || vp->v_type == VCHR) { 239 struct vnode *cvp, **cvpp; 240 241 cvpp = &speclisth[SPECHASH(vp->v_rdev)]; 242 loop: 243 for (cvp = *cvpp; cvp; cvp = cvp->v_specnext) { 244 if (vp->v_rdev != cvp->v_rdev || 245 vp->v_type != cvp->v_type) 246 continue; 247 248 /* 249 * Alias, but not in use, so flush it out. 250 */ 251 if (cvp->v_usecount == 0) { 252 vgone(cvp); 253 goto loop; 254 } 255 if (vget(cvp, 0)) /* can't lock; will die! */ 256 goto loop; 257 break; 258 } 259 260 vp->v_hashchain = cvpp; 261 vp->v_specnext = *cvpp; 262 vp->v_specflags = 0; 263 *cvpp = vp; 264 #ifdef DIAGNOSTIC 265 if (cvp == NULLVP) 266 panic("umap_node_alloc: no alias for device"); 267 #endif 268 vp->v_flag |= VALIASED; 269 cvp->v_flag |= VALIASED; 270 vrele(cvp); 271 } 272 /* XXX end of transmogrified checkalias() */ 273 274 *vpp = vp; 275 VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */ 276 hd = UMAP_NHASH(lowervp); 277 LIST_INSERT_HEAD(hd, xp, umap_hash); 278 return (0); 279 } 280 281 282 /* 283 * Try to find an existing umap_node vnode refering 284 * to it, otherwise make a new umap_node vnode which 285 * contains a reference to the target vnode. 286 */ 287 int 288 umap_node_create(mp, targetvp, newvpp) 289 struct mount *mp; 290 struct vnode *targetvp; 291 struct vnode **newvpp; 292 { 293 struct vnode *aliasvp; 294 295 if (aliasvp = umap_node_find(mp, targetvp)) { 296 /* 297 * Take another reference to the alias vnode 298 */ 299 #ifdef UMAPFS_DIAGNOSTIC 300 vprint("umap_node_create: exists", ap->umap_vnode); 301 #endif 302 /* VREF(aliasvp); */ 303 } else { 304 int error; 305 306 /* 307 * Get new vnode. 308 */ 309 #ifdef UMAPFS_DIAGNOSTIC 310 printf("umap_node_create: create new alias vnode\n"); 311 #endif 312 /* 313 * Make new vnode reference the umap_node. 314 */ 315 if (error = umap_node_alloc(mp, targetvp, &aliasvp)) 316 return (error); 317 318 /* 319 * aliasvp is already VREF'd by getnewvnode() 320 */ 321 } 322 323 vrele(targetvp); 324 325 #ifdef UMAPFS_DIAGNOSTIC 326 vprint("umap_node_create: alias", aliasvp); 327 vprint("umap_node_create: target", targetvp); 328 #endif 329 330 *newvpp = aliasvp; 331 return (0); 332 } 333 334 #ifdef UMAPFS_DIAGNOSTIC 335 int umap_checkvp_barrier = 1; 336 struct vnode * 337 umap_checkvp(vp, fil, lno) 338 struct vnode *vp; 339 char *fil; 340 int lno; 341 { 342 struct umap_node *a = VTOUMAP(vp); 343 #if 0 344 /* 345 * Can't do this check because vop_reclaim runs 346 * with funny vop vector. 347 */ 348 if (vp->v_op != umap_vnodeop_p) { 349 printf ("umap_checkvp: on non-umap-node\n"); 350 while (umap_checkvp_barrier) /*WAIT*/ ; 351 panic("umap_checkvp"); 352 } 353 #endif 354 if (a->umap_lowervp == NULL) { 355 /* Should never happen */ 356 int i; u_long *p; 357 printf("vp = %x, ZERO ptr\n", vp); 358 for (p = (u_long *) a, i = 0; i < 8; i++) 359 printf(" %x", p[i]); 360 printf("\n"); 361 /* wait for debugger */ 362 while (umap_checkvp_barrier) /*WAIT*/ ; 363 panic("umap_checkvp"); 364 } 365 if (a->umap_lowervp->v_usecount < 1) { 366 int i; u_long *p; 367 printf("vp = %x, unref'ed lowervp\n", vp); 368 for (p = (u_long *) a, i = 0; i < 8; i++) 369 printf(" %x", p[i]); 370 printf("\n"); 371 /* wait for debugger */ 372 while (umap_checkvp_barrier) /*WAIT*/ ; 373 panic ("umap with unref'ed lowervp"); 374 } 375 #if 0 376 printf("umap %x/%d -> %x/%d [%s, %d]\n", 377 a->umap_vnode, a->umap_vnode->v_usecount, 378 a->umap_lowervp, a->umap_lowervp->v_usecount, 379 fil, lno); 380 #endif 381 return (a->umap_lowervp); 382 } 383 #endif 384 385 /* umap_mapids maps all of the ids in a credential, both user and group. */ 386 387 void 388 umap_mapids(v_mount, credp) 389 struct mount *v_mount; 390 struct ucred *credp; 391 { 392 int i, unentries, gnentries; 393 uid_t uid, *usermap; 394 gid_t gid, *groupmap; 395 396 unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries; 397 usermap = &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]); 398 gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries; 399 groupmap = &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]); 400 401 /* Find uid entry in map */ 402 403 uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries); 404 405 if (uid != -1) 406 credp->cr_uid = uid; 407 else 408 credp->cr_uid = (uid_t) NOBODY; 409 410 #ifdef notdef 411 /* cr_gid is the same as cr_groups[0] in 4BSD */ 412 413 /* Find gid entry in map */ 414 415 gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries); 416 417 if (gid != -1) 418 credp->cr_gid = gid; 419 else 420 credp->cr_gid = NULLGROUP; 421 #endif 422 423 /* Now we must map each of the set of groups in the cr_groups 424 structure. */ 425 426 i = 0; 427 while (credp->cr_groups[i] != 0) { 428 gid = (gid_t) umap_findid(credp->cr_groups[i], 429 groupmap, gnentries); 430 431 if (gid != -1) 432 credp->cr_groups[i++] = gid; 433 else 434 credp->cr_groups[i++] = NULLGROUP; 435 } 436 } 437