]>
git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/umapfs/umap_subr.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 /* $NetBSD: umap_subr.c,v 1.4 1994/09/20 06:43:02 cgd Exp $ */
25 * Copyright (c) 1992, 1993
26 * The Regents of the University of California. All rights reserved.
28 * This code is derived from software donated to Berkeley by
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
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.
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
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
63 #include <sys/param.h>
64 #include <sys/systm.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>
72 #include <miscfs/specfs/specdev.h>
73 #include <miscfs/umapfs/umap.h>
75 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
76 #define NUMAPNODECACHE 16
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.
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
;
92 * Initialise cache headers
97 #ifdef UMAPFS_DIAGNOSTIC
98 printf("umapfs_init\n"); /* printed during system boot */
100 umap_node_hashtbl
= hashinit(NUMAPNODECACHE
, M_CACHE
, &umap_node_hash
);
104 * umap_findid is called by various routines in umap_vnodeops.c to
105 * find a user or group id in a map.
108 umap_findid(id
, map
, nentries
)
115 /* Find uid entry in map */
117 while ((i
<nentries
) && ((map
[i
][0]) != id
))
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.
132 umap_reverse_findid(id
, map
, nentries
)
139 /* Find uid entry in map */
141 while ((i
<nentries
) && ((map
[i
][1]) != id
))
152 * Return alias for target vnode if already exists, else 0.
154 static struct vnode
*
155 umap_node_find(mp
, targetvp
)
157 struct vnode
*targetvp
;
159 struct umap_node_hashhead
*hd
;
163 #ifdef UMAPFS_DIAGNOSTIC
164 printf("umap_node_find(mp = %x, target = %x)\n", mp
, targetvp
);
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).
173 hd
= UMAP_NHASH(targetvp
);
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
) {
180 * We need vget for the VXLOCK
181 * stuff, but we don't want to lock
184 if (vget(vp
, 0, current_proc())) {
185 #ifdef UMAPFS_DIAGNOSTIC
186 printf ("umap_node_find: vget failed.\n");
194 #ifdef UMAPFS_DIAGNOSTIC
195 printf("umap_node_find(%x, %x): NOT found\n", mp
, targetvp
);
202 * Make a new umap_node node.
203 * Vp is the alias vnode, lowervp is the target vnode.
204 * Maintain a reference to lowervp.
207 umap_node_alloc(mp
, lowervp
, vpp
)
209 struct vnode
*lowervp
;
212 struct umap_node_hashhead
*hd
;
213 struct umap_node
*xp
;
214 struct vnode
*vp
, *nvp
;
216 extern int (**dead_vnodeop_p
)(void *);
217 struct specinfo
*sp
= (struct specinfo
*)0;
219 if (lowervp
->v_type
== VBLK
|| lowervp
->v_type
== VCHR
)
220 MALLOC_ZONE(sp
, struct specinfo
*, sizeof(struct specinfo
),
223 MALLOC(xp
, struct umap_node
*, sizeof(struct umap_node
), M_TEMP
,
225 if (error
= getnewvnode(VT_UMAP
, mp
, umap_vnodeop_p
, &vp
)) {
228 FREE_ZONE(sp
, sizeof (struct specinfo
), M_VNODE
);
231 vp
->v_type
= lowervp
->v_type
;
233 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) {
235 vp
->v_rdev
= lowervp
->v_rdev
;
240 xp
->umap_lowervp
= lowervp
;
242 * Before we insert our new node onto the hash chains,
243 * check to see if someone else has beaten us to it.
245 if (nvp
= umap_node_find(lowervp
)) {
248 /* free the substructures we've allocated. */
251 vp
->v_specinfo
= (struct specinfo
*)0;
252 FREE_ZONE(sp
, sizeof (struct specinfo
), M_VNODE
);
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. */
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.
269 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) {
270 struct vnode
*cvp
, **cvpp
;
272 cvpp
= &speclisth
[SPECHASH(vp
->v_rdev
)];
274 for (cvp
= *cvpp
; cvp
; cvp
= cvp
->v_specnext
) {
275 if (vp
->v_rdev
!= cvp
->v_rdev
||
276 vp
->v_type
!= cvp
->v_type
)
280 * Alias, but not in use, so flush it out.
282 if (cvp
->v_usecount
== 0) {
286 if (vget(cvp
, 0, current_proc())) /* can't lock; will die! */
291 vp
->v_hashchain
= cvpp
;
292 vp
->v_specnext
= *cvpp
;
297 panic("umap_node_alloc: no alias for device");
299 vp
->v_flag
|= VALIASED
;
300 cvp
->v_flag
|= VALIASED
;
303 /* XXX end of transmogrified checkalias() */
305 if (vp
->v_type
== VREG
)
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
);
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.
322 umap_node_create(mp
, targetvp
, newvpp
)
324 struct vnode
*targetvp
;
325 struct vnode
**newvpp
;
327 struct vnode
*aliasvp
;
329 if (aliasvp
= umap_node_find(mp
, targetvp
)) {
331 * Take another reference to the alias vnode
333 #ifdef UMAPFS_DIAGNOSTIC
334 vprint("umap_node_create: exists", ap
->umap_vnode
);
343 #ifdef UMAPFS_DIAGNOSTIC
344 printf("umap_node_create: create new alias vnode\n");
347 * Make new vnode reference the umap_node.
349 if (error
= umap_node_alloc(mp
, targetvp
, &aliasvp
))
353 * aliasvp is already VREF'd by getnewvnode()
359 #ifdef UMAPFS_DIAGNOSTIC
360 vprint("umap_node_create: alias", aliasvp
);
361 vprint("umap_node_create: target", targetvp
);
368 #ifdef UMAPFS_DIAGNOSTIC
369 int umap_checkvp_barrier
= 1;
371 umap_checkvp(vp
, fil
, lno
)
376 struct umap_node
*a
= VTOUMAP(vp
);
379 * Can't do this check because vop_reclaim runs
380 * with funny vop vector.
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");
388 if (a
->umap_lowervp
== NULL
) {
389 /* Should never happen */
391 printf("vp = %x, ZERO ptr\n", vp
);
392 for (p
= (u_long
*) a
, i
= 0; i
< 8; i
++)
395 /* wait for debugger */
396 while (umap_checkvp_barrier
) /*WAIT*/ ;
397 panic("umap_checkvp");
399 if (a
->umap_lowervp
->v_usecount
< 1) {
401 printf("vp = %x, unref'ed lowervp\n", vp
);
402 for (p
= (u_long
*) a
, i
= 0; i
< 8; i
++)
405 /* wait for debugger */
406 while (umap_checkvp_barrier
) /*WAIT*/ ;
407 panic ("umap with unref'ed lowervp");
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
,
415 return (a
->umap_lowervp
);
419 /* umap_mapids maps all of the ids in a credential, both user and group. */
422 umap_mapids(v_mount
, credp
)
423 struct mount
*v_mount
;
426 int i
, unentries
, gnentries
;
428 gid_t gid
, *groupmap
;
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]);
435 /* Find uid entry in map */
437 uid
= (uid_t
) umap_findid(credp
->cr_uid
, usermap
, unentries
);
442 credp
->cr_uid
= (uid_t
) NOBODY
;
445 /* cr_gid is the same as cr_groups[0] in 4BSD */
447 /* Find gid entry in map */
449 gid
= (gid_t
) umap_findid(credp
->cr_gid
, groupmap
, gnentries
);
454 credp
->cr_gid
= NULLGROUP
;
457 /* Now we must map each of the set of groups in the cr_groups
461 while (credp
->cr_groups
[i
] != 0) {
462 gid
= (gid_t
) umap_findid(credp
->cr_groups
[i
],
463 groupmap
, gnentries
);
466 credp
->cr_groups
[i
++] = gid
;
468 credp
->cr_groups
[i
++] = NULLGROUP
;