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