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