]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/umapfs/umap_subr.c
xnu-201.tar.gz
[apple/xnu.git] / bsd / miscfs / umapfs / umap_subr.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* $NetBSD: umap_subr.c,v 1.4 1994/09/20 06:43:02 cgd Exp $ */
23
24 /*
25 * Copyright (c) 1992, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * This code is derived from software donated to Berkeley by
29 * Jan-Simon Pendry.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 * from: Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp
60 * @(#)umap_subr.c 8.6 (Berkeley) 1/26/94
61 */
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/time.h>
66 #include <sys/types.h>
67 #include <sys/vnode.h>
68 #include <sys/mount.h>
69 #include <sys/namei.h>
70 #include <sys/malloc.h>
71 #include <sys/ubc.h>
72 #include <miscfs/specfs/specdev.h>
73 #include <miscfs/umapfs/umap.h>
74
75 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
76 #define NUMAPNODECACHE 16
77
78 /*
79 * Null layer cache:
80 * Each cache entry holds a reference to the target vnode
81 * along with a pointer to the alias vnode. When an
82 * entry is added the target vnode is VREF'd. When the
83 * alias is removed the target vnode is vrele'd.
84 */
85
86 #define UMAP_NHASH(vp) \
87 (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash])
88 LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl;
89 u_long umap_node_hash;
90
91 /*
92 * Initialise cache headers
93 */
94 umapfs_init()
95 {
96
97 #ifdef UMAPFS_DIAGNOSTIC
98 printf("umapfs_init\n"); /* printed during system boot */
99 #endif
100 umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash);
101 }
102
103 /*
104 * umap_findid is called by various routines in umap_vnodeops.c to
105 * find a user or group id in a map.
106 */
107 static u_long
108 umap_findid(id, map, nentries)
109 u_long id;
110 u_long map[][2];
111 int nentries;
112 {
113 int i;
114
115 /* Find uid entry in map */
116 i = 0;
117 while ((i<nentries) && ((map[i][0]) != id))
118 i++;
119
120 if (i < nentries)
121 return (map[i][1]);
122 else
123 return (-1);
124
125 }
126
127 /*
128 * umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to
129 * find a user or group id in a map, in reverse.
130 */
131 u_long
132 umap_reverse_findid(id, map, nentries)
133 u_long id;
134 u_long map[][2];
135 int nentries;
136 {
137 int i;
138
139 /* Find uid entry in map */
140 i = 0;
141 while ((i<nentries) && ((map[i][1]) != id))
142 i++;
143
144 if (i < nentries)
145 return (map[i][0]);
146 else
147 return (-1);
148
149 }
150
151 /*
152 * Return alias for target vnode if already exists, else 0.
153 */
154 static struct vnode *
155 umap_node_find(mp, targetvp)
156 struct mount *mp;
157 struct vnode *targetvp;
158 {
159 struct umap_node_hashhead *hd;
160 struct umap_node *a;
161 struct vnode *vp;
162
163 #ifdef UMAPFS_DIAGNOSTIC
164 printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp);
165 #endif
166
167 /*
168 * Find hash base, and then search the (two-way) linked
169 * list looking for a umap_node structure which is referencing
170 * the target vnode. If found, the increment the umap_node
171 * reference count (but NOT the target vnode's VREF counter).
172 */
173 hd = UMAP_NHASH(targetvp);
174 loop:
175 for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) {
176 if (a->umap_lowervp == targetvp &&
177 a->umap_vnode->v_mount == mp) {
178 vp = UMAPTOV(a);
179 /*
180 * We need vget for the VXLOCK
181 * stuff, but we don't want to lock
182 * the lower node.
183 */
184 if (vget(vp, 0, current_proc())) {
185 #ifdef UMAPFS_DIAGNOSTIC
186 printf ("umap_node_find: vget failed.\n");
187 #endif
188 goto loop;
189 }
190 return (vp);
191 }
192 }
193
194 #ifdef UMAPFS_DIAGNOSTIC
195 printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp);
196 #endif
197
198 return (0);
199 }
200
201 /*
202 * Make a new umap_node node.
203 * Vp is the alias vnode, lowervp is the target vnode.
204 * Maintain a reference to lowervp.
205 */
206 static int
207 umap_node_alloc(mp, lowervp, vpp)
208 struct mount *mp;
209 struct vnode *lowervp;
210 struct vnode **vpp;
211 {
212 struct umap_node_hashhead *hd;
213 struct umap_node *xp;
214 struct vnode *vp, *nvp;
215 int error;
216 extern int (**dead_vnodeop_p)(void *);
217 struct specinfo *sp = (struct specinfo *)0;
218
219 if (lowervp->v_type == VBLK || lowervp->v_type == VCHR)
220 MALLOC_ZONE(sp, struct specinfo *, sizeof(struct specinfo),
221 M_VNODE, M_WAITOK);
222
223 MALLOC(xp, struct umap_node *, sizeof(struct umap_node), M_TEMP,
224 M_WAITOK);
225 if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, &vp)) {
226 FREE(xp, M_TEMP);
227 if (sp)
228 FREE_ZONE(sp, sizeof (struct specinfo), M_VNODE);
229 return (error);
230 }
231 vp->v_type = lowervp->v_type;
232
233 if (vp->v_type == VBLK || vp->v_type == VCHR) {
234 vp->v_specinfo = sp;
235 vp->v_rdev = lowervp->v_rdev;
236 }
237
238 vp->v_data = xp;
239 xp->umap_vnode = vp;
240 xp->umap_lowervp = lowervp;
241 /*
242 * Before we insert our new node onto the hash chains,
243 * check to see if someone else has beaten us to it.
244 */
245 if (nvp = umap_node_find(lowervp)) {
246 *vpp = nvp;
247
248 /* free the substructures we've allocated. */
249 FREE(xp, M_TEMP);
250 if (sp) {
251 vp->v_specinfo = (struct specinfo *)0;
252 FREE_ZONE(sp, sizeof (struct specinfo), M_VNODE);
253 }
254
255 vp->v_type = VBAD; /* node is discarded */
256 vp->v_op = dead_vnodeop_p; /* so ops will still work */
257 vrele(vp); /* get rid of it. */
258 return (0);
259 }
260
261 /*
262 * XXX if it's a device node, it needs to be checkalias()ed.
263 * however, for locking reasons, that's just not possible.
264 * so we have to do most of the dirty work inline. Note that
265 * this is a limited case; we know that there's going to be
266 * an alias, and we know that that alias will be a "real"
267 * device node, i.e. not tagged VT_NON.
268 */
269 if (vp->v_type == VBLK || vp->v_type == VCHR) {
270 struct vnode *cvp, **cvpp;
271
272 cvpp = &speclisth[SPECHASH(vp->v_rdev)];
273 loop:
274 for (cvp = *cvpp; cvp; cvp = cvp->v_specnext) {
275 if (vp->v_rdev != cvp->v_rdev ||
276 vp->v_type != cvp->v_type)
277 continue;
278
279 /*
280 * Alias, but not in use, so flush it out.
281 */
282 if (cvp->v_usecount == 0) {
283 vgone(cvp);
284 goto loop;
285 }
286 if (vget(cvp, 0, current_proc())) /* can't lock; will die! */
287 goto loop;
288 break;
289 }
290
291 vp->v_hashchain = cvpp;
292 vp->v_specnext = *cvpp;
293 vp->v_specflags = 0;
294 *cvpp = vp;
295 #if DIAGNOSTIC
296 if (cvp == NULLVP)
297 panic("umap_node_alloc: no alias for device");
298 #endif
299 vp->v_flag |= VALIASED;
300 cvp->v_flag |= VALIASED;
301 vrele(cvp);
302 }
303 /* XXX end of transmogrified checkalias() */
304
305 if (vp->v_type == VREG)
306 ubc_info_init(vp);
307
308 *vpp = vp;
309 VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */
310 hd = UMAP_NHASH(lowervp);
311 LIST_INSERT_HEAD(hd, xp, umap_hash);
312 return (0);
313 }
314
315
316 /*
317 * Try to find an existing umap_node vnode refering
318 * to it, otherwise make a new umap_node vnode which
319 * contains a reference to the target vnode.
320 */
321 int
322 umap_node_create(mp, targetvp, newvpp)
323 struct mount *mp;
324 struct vnode *targetvp;
325 struct vnode **newvpp;
326 {
327 struct vnode *aliasvp;
328
329 if (aliasvp = umap_node_find(mp, targetvp)) {
330 /*
331 * Take another reference to the alias vnode
332 */
333 #ifdef UMAPFS_DIAGNOSTIC
334 vprint("umap_node_create: exists", ap->umap_vnode);
335 #endif
336 /* VREF(aliasvp); */
337 } else {
338 int error;
339
340 /*
341 * Get new vnode.
342 */
343 #ifdef UMAPFS_DIAGNOSTIC
344 printf("umap_node_create: create new alias vnode\n");
345 #endif
346 /*
347 * Make new vnode reference the umap_node.
348 */
349 if (error = umap_node_alloc(mp, targetvp, &aliasvp))
350 return (error);
351
352 /*
353 * aliasvp is already VREF'd by getnewvnode()
354 */
355 }
356
357 vrele(targetvp);
358
359 #ifdef UMAPFS_DIAGNOSTIC
360 vprint("umap_node_create: alias", aliasvp);
361 vprint("umap_node_create: target", targetvp);
362 #endif
363
364 *newvpp = aliasvp;
365 return (0);
366 }
367
368 #ifdef UMAPFS_DIAGNOSTIC
369 int umap_checkvp_barrier = 1;
370 struct vnode *
371 umap_checkvp(vp, fil, lno)
372 struct vnode *vp;
373 char *fil;
374 int lno;
375 {
376 struct umap_node *a = VTOUMAP(vp);
377 #if 0
378 /*
379 * Can't do this check because vop_reclaim runs
380 * with funny vop vector.
381 */
382 if (vp->v_op != umap_vnodeop_p) {
383 printf ("umap_checkvp: on non-umap-node\n");
384 while (umap_checkvp_barrier) /*WAIT*/ ;
385 panic("umap_checkvp");
386 }
387 #endif
388 if (a->umap_lowervp == NULL) {
389 /* Should never happen */
390 int i; u_long *p;
391 printf("vp = %x, ZERO ptr\n", vp);
392 for (p = (u_long *) a, i = 0; i < 8; i++)
393 printf(" %x", p[i]);
394 printf("\n");
395 /* wait for debugger */
396 while (umap_checkvp_barrier) /*WAIT*/ ;
397 panic("umap_checkvp");
398 }
399 if (a->umap_lowervp->v_usecount < 1) {
400 int i; u_long *p;
401 printf("vp = %x, unref'ed lowervp\n", vp);
402 for (p = (u_long *) a, i = 0; i < 8; i++)
403 printf(" %x", p[i]);
404 printf("\n");
405 /* wait for debugger */
406 while (umap_checkvp_barrier) /*WAIT*/ ;
407 panic ("umap with unref'ed lowervp");
408 }
409 #if 0
410 printf("umap %x/%d -> %x/%d [%s, %d]\n",
411 a->umap_vnode, a->umap_vnode->v_usecount,
412 a->umap_lowervp, a->umap_lowervp->v_usecount,
413 fil, lno);
414 #endif
415 return (a->umap_lowervp);
416 }
417 #endif
418
419 /* umap_mapids maps all of the ids in a credential, both user and group. */
420
421 void
422 umap_mapids(v_mount, credp)
423 struct mount *v_mount;
424 struct ucred *credp;
425 {
426 int i, unentries, gnentries;
427 uid_t uid, *usermap;
428 gid_t gid, *groupmap;
429
430 unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries;
431 usermap = &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]);
432 gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries;
433 groupmap = &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]);
434
435 /* Find uid entry in map */
436
437 uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries);
438
439 if (uid != -1)
440 credp->cr_uid = uid;
441 else
442 credp->cr_uid = (uid_t) NOBODY;
443
444 #ifdef notdef
445 /* cr_gid is the same as cr_groups[0] in 4BSD */
446
447 /* Find gid entry in map */
448
449 gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries);
450
451 if (gid != -1)
452 credp->cr_gid = gid;
453 else
454 credp->cr_gid = NULLGROUP;
455 #endif
456
457 /* Now we must map each of the set of groups in the cr_groups
458 structure. */
459
460 i = 0;
461 while (credp->cr_groups[i] != 0) {
462 gid = (gid_t) umap_findid(credp->cr_groups[i],
463 groupmap, gnentries);
464
465 if (gid != -1)
466 credp->cr_groups[i++] = gid;
467 else
468 credp->cr_groups[i++] = NULLGROUP;
469 }
470 }