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