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