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