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 * %sccs.include.redist.c% 9 * 10 * @(#)umap_subr.c 8.6 (Berkeley) 01/26/94 11 * 12 * $Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 13 */ 14 15 #include <sys/param.h> 16 #include <sys/systm.h> 17 #include <sys/time.h> 18 #include <sys/types.h> 19 #include <sys/vnode.h> 20 #include <sys/mount.h> 21 #include <sys/namei.h> 22 #include <sys/malloc.h> 23 #include <miscfs/umapfs/umap.h> 24 25 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 26 #define NUMAPNODECACHE 16 27 #define UMAP_NHASH(vp) ((((u_long) vp)>>LOG2_SIZEVNODE) & (NUMAPNODECACHE-1)) 28 29 /* 30 * Null layer cache: 31 * Each cache entry holds a reference to the target vnode 32 * along with a pointer to the alias vnode. When an 33 * entry is added the target vnode is VREF'd. When the 34 * alias is removed the target vnode is vrele'd. 35 */ 36 37 /* 38 * Cache head 39 */ 40 struct umap_node_cache { 41 struct umap_node *ac_forw; 42 struct umap_node *ac_back; 43 }; 44 45 static struct umap_node_cache umap_node_cache[NUMAPNODECACHE]; 46 47 /* 48 * Initialise cache headers 49 */ 50 umapfs_init() 51 { 52 struct umap_node_cache *ac; 53 #ifdef UMAPFS_DIAGNOSTIC 54 printf("umapfs_init\n"); /* printed during system boot */ 55 #endif 56 57 for (ac = umap_node_cache; ac < umap_node_cache + NUMAPNODECACHE; ac++) 58 ac->ac_forw = ac->ac_back = (struct umap_node *) ac; 59 } 60 61 /* 62 * Compute hash list for given target vnode 63 */ 64 static struct umap_node_cache * 65 umap_node_hash(targetvp) 66 struct vnode *targetvp; 67 { 68 69 return (&umap_node_cache[UMAP_NHASH(targetvp)]); 70 } 71 72 /* 73 * umap_findid is called by various routines in umap_vnodeops.c to 74 * find a user or group id in a map. 75 */ 76 static u_long 77 umap_findid(id, map, nentries) 78 u_long id; 79 u_long map[][2]; 80 int nentries; 81 { 82 int i; 83 84 /* Find uid entry in map */ 85 i = 0; 86 while ((i<nentries) && ((map[i][0]) != id)) 87 i++; 88 89 if (i < nentries) 90 return (map[i][1]); 91 else 92 return (-1); 93 94 } 95 96 /* 97 * umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to 98 * find a user or group id in a map, in reverse. 99 */ 100 u_long 101 umap_reverse_findid(id, map, nentries) 102 u_long id; 103 u_long map[][2]; 104 int nentries; 105 { 106 int i; 107 108 /* Find uid entry in map */ 109 i = 0; 110 while ((i<nentries) && ((map[i][1]) != id)) 111 i++; 112 113 if (i < nentries) 114 return (map[i][0]); 115 else 116 return (-1); 117 118 } 119 120 /* 121 * Return alias for target vnode if already exists, else 0. 122 */ 123 static struct vnode * 124 umap_node_find(mp, targetvp) 125 struct mount *mp; 126 struct vnode *targetvp; 127 { 128 struct umap_node_cache *hd; 129 struct umap_node *a; 130 struct vnode *vp; 131 132 #ifdef UMAPFS_DIAGNOSTIC 133 printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp); 134 #endif 135 136 /* 137 * Find hash base, and then search the (two-way) linked 138 * list looking for a umap_node structure which is referencing 139 * the target vnode. If found, the increment the umap_node 140 * reference count (but NOT the target vnode's VREF counter). 141 */ 142 hd = umap_node_hash(targetvp); 143 144 loop: 145 for (a = hd->ac_forw; a != (struct umap_node *) hd; a = a->umap_forw) { 146 if (a->umap_lowervp == targetvp && 147 a->umap_vnode->v_mount == mp) { 148 vp = UMAPTOV(a); 149 /* 150 * We need vget for the VXLOCK 151 * stuff, but we don't want to lock 152 * the lower node. 153 */ 154 if (vget(vp, 0)) { 155 #ifdef UMAPFS_DIAGNOSTIC 156 printf ("umap_node_find: vget failed.\n"); 157 #endif 158 goto loop; 159 } 160 return (vp); 161 } 162 } 163 164 #ifdef UMAPFS_DIAGNOSTIC 165 printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp); 166 #endif 167 168 return (0); 169 } 170 171 /* 172 * Make a new umap_node node. 173 * Vp is the alias vnode, lofsvp is the target vnode. 174 * Maintain a reference to (targetvp). 175 */ 176 static int 177 umap_node_alloc(mp, lowervp, vpp) 178 struct mount *mp; 179 struct vnode *lowervp; 180 struct vnode **vpp; 181 { 182 struct umap_node_cache *hd; 183 struct umap_node *xp; 184 struct vnode *othervp, *vp; 185 int error; 186 187 if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, vpp)) 188 return (error); 189 vp = *vpp; 190 191 MALLOC(xp, struct umap_node *, sizeof(struct umap_node), 192 M_TEMP, M_WAITOK); 193 vp->v_type = lowervp->v_type; 194 xp->umap_vnode = vp; 195 vp->v_data = xp; 196 xp->umap_lowervp = lowervp; 197 /* 198 * Before we insert our new node onto the hash chains, 199 * check to see if someone else has beaten us to it. 200 * (We could have slept in MALLOC.) 201 */ 202 if (othervp = umap_node_find(lowervp)) { 203 FREE(xp, M_TEMP); 204 vp->v_type = VBAD; /* node is discarded */ 205 vp->v_usecount = 0; /* XXX */ 206 *vpp = othervp; 207 return (0); 208 } 209 VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */ 210 hd = umap_node_hash(lowervp); 211 insque(xp, hd); 212 return (0); 213 } 214 215 216 /* 217 * Try to find an existing umap_node vnode refering 218 * to it, otherwise make a new umap_node vnode which 219 * contains a reference to the target vnode. 220 */ 221 int 222 umap_node_create(mp, targetvp, newvpp) 223 struct mount *mp; 224 struct vnode *targetvp; 225 struct vnode **newvpp; 226 { 227 struct vnode *aliasvp; 228 229 if (aliasvp = umap_node_find(mp, targetvp)) { 230 /* 231 * Take another reference to the alias vnode 232 */ 233 #ifdef UMAPFS_DIAGNOSTIC 234 vprint("umap_node_create: exists", ap->umap_vnode); 235 #endif 236 /* VREF(aliasvp); */ 237 } else { 238 int error; 239 240 /* 241 * Get new vnode. 242 */ 243 #ifdef UMAPFS_DIAGNOSTIC 244 printf("umap_node_create: create new alias vnode\n"); 245 #endif 246 /* 247 * Make new vnode reference the umap_node. 248 */ 249 if (error = umap_node_alloc(mp, targetvp, &aliasvp)) 250 return (error); 251 252 /* 253 * aliasvp is already VREF'd by getnewvnode() 254 */ 255 } 256 257 vrele(targetvp); 258 259 #ifdef UMAPFS_DIAGNOSTIC 260 vprint("umap_node_create: alias", aliasvp); 261 vprint("umap_node_create: target", targetvp); 262 #endif 263 264 *newvpp = aliasvp; 265 return (0); 266 } 267 268 #ifdef UMAPFS_DIAGNOSTIC 269 int umap_checkvp_barrier = 1; 270 struct vnode * 271 umap_checkvp(vp, fil, lno) 272 struct vnode *vp; 273 char *fil; 274 int lno; 275 { 276 struct umap_node *a = VTOUMAP(vp); 277 #if 0 278 /* 279 * Can't do this check because vop_reclaim runs 280 * with funny vop vector. 281 */ 282 if (vp->v_op != umap_vnodeop_p) { 283 printf ("umap_checkvp: on non-umap-node\n"); 284 while (umap_checkvp_barrier) /*WAIT*/ ; 285 panic("umap_checkvp"); 286 } 287 #endif 288 if (a->umap_lowervp == NULL) { 289 /* Should never happen */ 290 int i; u_long *p; 291 printf("vp = %x, ZERO ptr\n", vp); 292 for (p = (u_long *) a, i = 0; i < 8; i++) 293 printf(" %x", p[i]); 294 printf("\n"); 295 /* wait for debugger */ 296 while (umap_checkvp_barrier) /*WAIT*/ ; 297 panic("umap_checkvp"); 298 } 299 if (a->umap_lowervp->v_usecount < 1) { 300 int i; u_long *p; 301 printf("vp = %x, unref'ed lowervp\n", vp); 302 for (p = (u_long *) a, i = 0; i < 8; i++) 303 printf(" %x", p[i]); 304 printf("\n"); 305 /* wait for debugger */ 306 while (umap_checkvp_barrier) /*WAIT*/ ; 307 panic ("umap with unref'ed lowervp"); 308 } 309 #if 0 310 printf("umap %x/%d -> %x/%d [%s, %d]\n", 311 a->umap_vnode, a->umap_vnode->v_usecount, 312 a->umap_lowervp, a->umap_lowervp->v_usecount, 313 fil, lno); 314 #endif 315 return (a->umap_lowervp); 316 } 317 #endif 318 319 /* umap_mapids maps all of the ids in a credential, both user and group. */ 320 321 void 322 umap_mapids(v_mount, credp) 323 struct mount *v_mount; 324 struct ucred *credp; 325 { 326 int i, unentries, gnentries; 327 u_long *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