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