1 /* $NetBSD: umap_subr.c,v 1.3 1994/08/19 11:25:41 mycroft 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/umapfs/umap.h> 51 52 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 53 #define NUMAPNODECACHE 16 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 #define UMAP_NHASH(vp) \ 64 (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash]) 65 LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl; 66 u_long umap_node_hash; 67 68 /* 69 * Initialise cache headers 70 */ 71 umapfs_init() 72 { 73 74 #ifdef UMAPFS_DIAGNOSTIC 75 printf("umapfs_init\n"); /* printed during system boot */ 76 #endif 77 umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash); 78 } 79 80 /* 81 * umap_findid is called by various routines in umap_vnodeops.c to 82 * find a user or group id in a map. 83 */ 84 static u_long 85 umap_findid(id, map, nentries) 86 u_long id; 87 u_long map[][2]; 88 int nentries; 89 { 90 int i; 91 92 /* Find uid entry in map */ 93 i = 0; 94 while ((i<nentries) && ((map[i][0]) != id)) 95 i++; 96 97 if (i < nentries) 98 return (map[i][1]); 99 else 100 return (-1); 101 102 } 103 104 /* 105 * umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to 106 * find a user or group id in a map, in reverse. 107 */ 108 u_long 109 umap_reverse_findid(id, map, nentries) 110 u_long id; 111 u_long map[][2]; 112 int nentries; 113 { 114 int i; 115 116 /* Find uid entry in map */ 117 i = 0; 118 while ((i<nentries) && ((map[i][1]) != id)) 119 i++; 120 121 if (i < nentries) 122 return (map[i][0]); 123 else 124 return (-1); 125 126 } 127 128 /* 129 * Return alias for target vnode if already exists, else 0. 130 */ 131 static struct vnode * 132 umap_node_find(mp, targetvp) 133 struct mount *mp; 134 struct vnode *targetvp; 135 { 136 struct umap_node_hashhead *hd; 137 struct umap_node *a; 138 struct vnode *vp; 139 140 #ifdef UMAPFS_DIAGNOSTIC 141 printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp); 142 #endif 143 144 /* 145 * Find hash base, and then search the (two-way) linked 146 * list looking for a umap_node structure which is referencing 147 * the target vnode. If found, the increment the umap_node 148 * reference count (but NOT the target vnode's VREF counter). 149 */ 150 hd = UMAP_NHASH(targetvp); 151 loop: 152 for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) { 153 if (a->umap_lowervp == targetvp && 154 a->umap_vnode->v_mount == mp) { 155 vp = UMAPTOV(a); 156 /* 157 * We need vget for the VXLOCK 158 * stuff, but we don't want to lock 159 * the lower node. 160 */ 161 if (vget(vp, 0)) { 162 #ifdef UMAPFS_DIAGNOSTIC 163 printf ("umap_node_find: vget failed.\n"); 164 #endif 165 goto loop; 166 } 167 return (vp); 168 } 169 } 170 171 #ifdef UMAPFS_DIAGNOSTIC 172 printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp); 173 #endif 174 175 return (0); 176 } 177 178 /* 179 * Make a new umap_node node. 180 * Vp is the alias vnode, lofsvp is the target vnode. 181 * Maintain a reference to (targetvp). 182 */ 183 static int 184 umap_node_alloc(mp, lowervp, vpp) 185 struct mount *mp; 186 struct vnode *lowervp; 187 struct vnode **vpp; 188 { 189 struct umap_node_hashhead *hd; 190 struct umap_node *xp; 191 struct vnode *othervp, *vp; 192 int error; 193 194 if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, vpp)) 195 return (error); 196 vp = *vpp; 197 198 MALLOC(xp, struct umap_node *, sizeof(struct umap_node), 199 M_TEMP, M_WAITOK); 200 vp->v_type = lowervp->v_type; 201 xp->umap_vnode = vp; 202 vp->v_data = xp; 203 xp->umap_lowervp = lowervp; 204 /* 205 * Before we insert our new node onto the hash chains, 206 * check to see if someone else has beaten us to it. 207 * (We could have slept in MALLOC.) 208 */ 209 if (othervp = umap_node_find(lowervp)) { 210 FREE(xp, M_TEMP); 211 vp->v_type = VBAD; /* node is discarded */ 212 vp->v_usecount = 0; /* XXX */ 213 *vpp = othervp; 214 return (0); 215 } 216 VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */ 217 hd = UMAP_NHASH(lowervp); 218 LIST_INSERT_HEAD(hd, xp, umap_hash); 219 return (0); 220 } 221 222 223 /* 224 * Try to find an existing umap_node vnode refering 225 * to it, otherwise make a new umap_node vnode which 226 * contains a reference to the target vnode. 227 */ 228 int 229 umap_node_create(mp, targetvp, newvpp) 230 struct mount *mp; 231 struct vnode *targetvp; 232 struct vnode **newvpp; 233 { 234 struct vnode *aliasvp; 235 236 if (aliasvp = umap_node_find(mp, targetvp)) { 237 /* 238 * Take another reference to the alias vnode 239 */ 240 #ifdef UMAPFS_DIAGNOSTIC 241 vprint("umap_node_create: exists", ap->umap_vnode); 242 #endif 243 /* VREF(aliasvp); */ 244 } else { 245 int error; 246 247 /* 248 * Get new vnode. 249 */ 250 #ifdef UMAPFS_DIAGNOSTIC 251 printf("umap_node_create: create new alias vnode\n"); 252 #endif 253 /* 254 * Make new vnode reference the umap_node. 255 */ 256 if (error = umap_node_alloc(mp, targetvp, &aliasvp)) 257 return (error); 258 259 /* 260 * aliasvp is already VREF'd by getnewvnode() 261 */ 262 } 263 264 vrele(targetvp); 265 266 #ifdef UMAPFS_DIAGNOSTIC 267 vprint("umap_node_create: alias", aliasvp); 268 vprint("umap_node_create: target", targetvp); 269 #endif 270 271 *newvpp = aliasvp; 272 return (0); 273 } 274 275 #ifdef UMAPFS_DIAGNOSTIC 276 int umap_checkvp_barrier = 1; 277 struct vnode * 278 umap_checkvp(vp, fil, lno) 279 struct vnode *vp; 280 char *fil; 281 int lno; 282 { 283 struct umap_node *a = VTOUMAP(vp); 284 #if 0 285 /* 286 * Can't do this check because vop_reclaim runs 287 * with funny vop vector. 288 */ 289 if (vp->v_op != umap_vnodeop_p) { 290 printf ("umap_checkvp: on non-umap-node\n"); 291 while (umap_checkvp_barrier) /*WAIT*/ ; 292 panic("umap_checkvp"); 293 } 294 #endif 295 if (a->umap_lowervp == NULL) { 296 /* Should never happen */ 297 int i; u_long *p; 298 printf("vp = %x, ZERO ptr\n", vp); 299 for (p = (u_long *) a, i = 0; i < 8; i++) 300 printf(" %x", p[i]); 301 printf("\n"); 302 /* wait for debugger */ 303 while (umap_checkvp_barrier) /*WAIT*/ ; 304 panic("umap_checkvp"); 305 } 306 if (a->umap_lowervp->v_usecount < 1) { 307 int i; u_long *p; 308 printf("vp = %x, unref'ed lowervp\n", vp); 309 for (p = (u_long *) a, i = 0; i < 8; i++) 310 printf(" %x", p[i]); 311 printf("\n"); 312 /* wait for debugger */ 313 while (umap_checkvp_barrier) /*WAIT*/ ; 314 panic ("umap with unref'ed lowervp"); 315 } 316 #if 0 317 printf("umap %x/%d -> %x/%d [%s, %d]\n", 318 a->umap_vnode, a->umap_vnode->v_usecount, 319 a->umap_lowervp, a->umap_lowervp->v_usecount, 320 fil, lno); 321 #endif 322 return (a->umap_lowervp); 323 } 324 #endif 325 326 /* umap_mapids maps all of the ids in a credential, both user and group. */ 327 328 void 329 umap_mapids(v_mount, credp) 330 struct mount *v_mount; 331 struct ucred *credp; 332 { 333 int i, unentries, gnentries; 334 uid_t uid, *usermap; 335 gid_t gid, *groupmap; 336 337 unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries; 338 usermap = &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]); 339 gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries; 340 groupmap = &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]); 341 342 /* Find uid entry in map */ 343 344 uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries); 345 346 if (uid != -1) 347 credp->cr_uid = uid; 348 else 349 credp->cr_uid = (uid_t) NOBODY; 350 351 #ifdef notdef 352 /* cr_gid is the same as cr_groups[0] in 4BSD */ 353 354 /* Find gid entry in map */ 355 356 gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries); 357 358 if (gid != -1) 359 credp->cr_gid = gid; 360 else 361 credp->cr_gid = NULLGROUP; 362 #endif 363 364 /* Now we must map each of the set of groups in the cr_groups 365 structure. */ 366 367 i = 0; 368 while (credp->cr_groups[i] != 0) { 369 gid = (gid_t) umap_findid(credp->cr_groups[i], 370 groupmap, gnentries); 371 372 if (gid != -1) 373 credp->cr_groups[i++] = gid; 374 else 375 credp->cr_groups[i++] = NULLGROUP; 376 } 377 } 378