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