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_vnops.c,v 1.3 1994/08/19 11:25:42 mycroft 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
29 * the UCLA Ficus project.
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 * @(#)umap_vnops.c 8.3 (Berkeley) 1/5/94
66 #include <sys/param.h>
67 #include <sys/systm.h>
69 #include <sys/types.h>
70 #include <sys/vnode.h>
71 #include <sys/mount.h>
72 #include <sys/namei.h>
73 #include <sys/malloc.h>
75 #include <miscfs/umapfs/umap.h>
78 int umap_bug_bypass
= 0; /* for debugging: enables bypass printf'ing */
81 * This is the 10-Apr-92 bypass routine.
82 * See null_vnops.c:null_bypass for more details.
86 struct vop_generic_args
/* {
87 struct vnodeop_desc *a_desc;
88 <other random data follows, presumably>
91 extern int (**umap_vnodeop_p
)(void *); /* not extern, really "forward" */
92 struct ucred
**credpp
= 0, *credp
= 0;
93 struct ucred
*savecredp
, *savecompcredp
= 0;
94 struct ucred
*compcredp
= 0;
95 struct vnode
**this_vp_p
;
97 struct vnode
*old_vps
[VDESC_MAX_VPS
];
98 struct vnode
*vp1
= 0;
99 struct vnode
**vps_p
[VDESC_MAX_VPS
];
100 struct vnode
***vppp
;
101 struct vnodeop_desc
*descp
= ap
->a_desc
;
103 struct componentname
**compnamepp
= 0;
106 printf ("umap_bypass: %s\n", descp
->vdesc_name
);
110 * We require at least one vp.
112 if (descp
->vdesc_vp_offsets
== NULL
||
113 descp
->vdesc_vp_offsets
[0] == VDESC_NO_OFFSET
)
114 panic ("umap_bypass: no vp's in map.\n");
118 * Map the vnodes going in.
119 * Later, we'll invoke the operation based on
120 * the first mapped vnode's operation vector.
122 reles
= descp
->vdesc_flags
;
123 for (i
= 0; i
< VDESC_MAX_VPS
; reles
>>= 1, i
++) {
124 if (descp
->vdesc_vp_offsets
[i
] == VDESC_NO_OFFSET
)
125 break; /* bail out at end of list */
126 vps_p
[i
] = this_vp_p
=
127 VOPARG_OFFSETTO(struct vnode
**, descp
->vdesc_vp_offsets
[i
], ap
);
134 * We're not guaranteed that any but the first vnode
135 * are of our type. Check for and don't map any
136 * that aren't. (Must map first vp or vclean fails.)
139 if (i
&& (*this_vp_p
)->v_op
!= umap_vnodeop_p
) {
142 old_vps
[i
] = *this_vp_p
;
143 *(vps_p
[i
]) = UMAPVPTOLOWERVP(*this_vp_p
);
151 * Fix the credentials. (That's the purpose of this layer.)
154 if (descp
->vdesc_cred_offset
!= VDESC_NO_OFFSET
) {
156 credpp
= VOPARG_OFFSETTO(struct ucred
**,
157 descp
->vdesc_cred_offset
, ap
);
159 /* Save old values */
162 if (savecredp
!= NOCRED
)
163 *credpp
= crdup(savecredp
);
166 if (umap_bug_bypass
&& credp
->cr_uid
!= 0)
167 printf("umap_bypass: user was %d, group %d\n",
168 credp
->cr_uid
, credp
->cr_gid
);
170 /* Map all ids in the credential structure. */
172 umap_mapids(vp1
->v_mount
, credp
);
174 if (umap_bug_bypass
&& credp
->cr_uid
!= 0)
175 printf("umap_bypass: user now %d, group %d\n",
176 credp
->cr_uid
, credp
->cr_gid
);
179 /* BSD often keeps a credential in the componentname structure
180 * for speed. If there is one, it better get mapped, too.
183 if (descp
->vdesc_componentname_offset
!= VDESC_NO_OFFSET
) {
185 compnamepp
= VOPARG_OFFSETTO(struct componentname
**,
186 descp
->vdesc_componentname_offset
, ap
);
188 savecompcredp
= (*compnamepp
)->cn_cred
;
189 if (savecompcredp
!= NOCRED
)
190 (*compnamepp
)->cn_cred
= crdup(savecompcredp
);
191 compcredp
= (*compnamepp
)->cn_cred
;
193 if (umap_bug_bypass
&& compcredp
->cr_uid
!= 0)
194 printf("umap_bypass: component credit user was %d, group %d\n",
195 compcredp
->cr_uid
, compcredp
->cr_gid
);
197 /* Map all ids in the credential structure. */
199 umap_mapids(vp1
->v_mount
, compcredp
);
201 if (umap_bug_bypass
&& compcredp
->cr_uid
!= 0)
202 printf("umap_bypass: component credit user now %d, group %d\n",
203 compcredp
->cr_uid
, compcredp
->cr_gid
);
207 * Call the operation on the lower layer
208 * with the modified argument structure.
210 error
= VCALL(*(vps_p
[0]), descp
->vdesc_offset
, ap
);
213 * Maintain the illusion of call-by-value
214 * by restoring vnodes in the argument structure
215 * to their original value.
217 reles
= descp
->vdesc_flags
;
218 for (i
= 0; i
< VDESC_MAX_VPS
; reles
>>= 1, i
++) {
219 if (descp
->vdesc_vp_offsets
[i
] == VDESC_NO_OFFSET
)
220 break; /* bail out at end of list */
222 *(vps_p
[i
]) = old_vps
[i
];
229 * Map the possible out-going vpp
230 * (Assumes that the lower layer always returns
231 * a VREF'ed vpp unless it gets an error.)
233 if (descp
->vdesc_vpp_offset
!= VDESC_NO_OFFSET
&&
234 !(descp
->vdesc_flags
& VDESC_NOMAP_VPP
) &&
236 if (descp
->vdesc_flags
& VDESC_VPP_WILLRELE
)
238 vppp
= VOPARG_OFFSETTO(struct vnode
***,
239 descp
->vdesc_vpp_offset
, ap
);
240 error
= umap_node_create(old_vps
[0]->v_mount
, **vppp
, *vppp
);
245 * Free duplicate cred structure and restore old one.
247 if (descp
->vdesc_cred_offset
!= VDESC_NO_OFFSET
) {
248 if (umap_bug_bypass
&& credp
&& credp
->cr_uid
!= 0)
249 printf("umap_bypass: returning-user was %d\n",
252 if (savecredp
!= NOCRED
) {
256 if (umap_bug_bypass
&& credpp
&& (*credpp
)->cr_uid
!= 0)
257 printf("umap_bypass: returning-user now %d\n\n",
262 if (descp
->vdesc_componentname_offset
!= VDESC_NO_OFFSET
) {
263 if (umap_bug_bypass
&& compcredp
&& compcredp
->cr_uid
!= 0)
264 printf("umap_bypass: returning-component-user was %d\n",
267 if (savecompcredp
!= NOCRED
) {
268 if (compcredp
!= NOCRED
)
270 (*compnamepp
)->cn_cred
= savecompcredp
;
271 if (umap_bug_bypass
&& credpp
&& (*credpp
)->cr_uid
!= 0)
272 printf("umap_bypass: returning-component-user now %d\n",
273 savecompcredp
->cr_uid
);
282 * We handle getattr to change the fsid.
286 struct vop_getattr_args
/* {
289 struct ucred *a_cred;
295 int error
, tmpid
, nentries
, gnentries
;
297 gid_t (*gmapdata
)[2];
299 struct vnodeop_desc
*descp
= ap
->a_desc
;
301 if (error
= umap_bypass(ap
))
303 /* Requires that arguments be restored. */
304 ap
->a_vap
->va_fsid
= ap
->a_vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
307 * Umap needs to map the uid and gid returned by a stat
308 * into the proper values for this site. This involves
309 * finding the returned uid in the mapping information,
310 * translating it into the uid on the other end,
311 * and filling in the proper field in the vattr
312 * structure pointed to by ap->a_vap. The group
313 * is easier, since currently all groups will be
314 * translate to the NULLGROUP.
317 /* Find entry in map */
319 uid
= ap
->a_vap
->va_uid
;
320 gid
= ap
->a_vap
->va_gid
;
322 printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid
,
325 vp1p
= VOPARG_OFFSETTO(struct vnode
**, descp
->vdesc_vp_offsets
[0], ap
);
326 nentries
= MOUNTTOUMAPMOUNT((*vp1p
)->v_mount
)->info_nentries
;
327 mapdata
= (MOUNTTOUMAPMOUNT((*vp1p
)->v_mount
)->info_mapdata
);
328 gnentries
= MOUNTTOUMAPMOUNT((*vp1p
)->v_mount
)->info_gnentries
;
329 gmapdata
= (MOUNTTOUMAPMOUNT((*vp1p
)->v_mount
)->info_gmapdata
);
331 /* Reverse map the uid for the vnode. Since it's a reverse
332 map, we can't use umap_mapids() to do it. */
334 tmpid
= umap_reverse_findid(uid
, mapdata
, nentries
);
337 ap
->a_vap
->va_uid
= (uid_t
) tmpid
;
339 printf("umap_getattr: original uid = %d\n", uid
);
341 ap
->a_vap
->va_uid
= (uid_t
) NOBODY
;
343 /* Reverse map the gid for the vnode. */
345 tmpid
= umap_reverse_findid(gid
, gmapdata
, gnentries
);
348 ap
->a_vap
->va_gid
= (gid_t
) tmpid
;
350 printf("umap_getattr: original gid = %d\n", gid
);
352 ap
->a_vap
->va_gid
= (gid_t
) NULLGROUP
;
359 struct vop_inactive_args
/* {
364 * Do nothing (and _don't_ bypass).
365 * Wait to vrele lowervp until reclaim,
366 * so that until then our umap_node is in the
367 * cache and reusable.
375 struct vop_reclaim_args
/* {
379 struct vnode
*vp
= ap
->a_vp
;
380 struct umap_node
*xp
= VTOUMAP(vp
);
381 struct vnode
*lowervp
= xp
->umap_lowervp
;
383 /* After this assignment, this node will not be re-used. */
384 xp
->umap_lowervp
= NULL
;
385 LIST_REMOVE(xp
, umap_hash
);
386 FREE(vp
->v_data
, M_TEMP
);
394 struct vop_strategy_args
/* {
398 struct buf
*bp
= ap
->a_bp
;
400 struct vnode
*savedvp
;
403 bp
->b_vp
= UMAPVPTOLOWERVP(bp
->b_vp
);
405 error
= VOP_STRATEGY(ap
->a_bp
);
414 struct vop_bwrite_args
/* {
418 struct buf
*bp
= ap
->a_bp
;
420 struct vnode
*savedvp
;
423 bp
->b_vp
= UMAPVPTOLOWERVP(bp
->b_vp
);
425 error
= VOP_BWRITE(ap
->a_bp
);
435 struct vop_print_args
/* {
439 struct vnode
*vp
= ap
->a_vp
;
440 printf("\ttag VT_UMAPFS, vp=%x, lowervp=%x\n", vp
, UMAPVPTOLOWERVP(vp
));
446 struct vop_rename_args
/* {
447 struct vnode *a_fdvp;
449 struct componentname *a_fcnp;
450 struct vnode *a_tdvp;
452 struct componentname *a_tcnp;
456 struct componentname
*compnamep
;
457 struct ucred
*compcredp
, *savecompcredp
;
461 * Rename is irregular, having two componentname structures.
462 * We need to map the cre in the second structure,
463 * and then bypass takes care of the rest.
467 compnamep
= ap
->a_tcnp
;
468 compcredp
= compnamep
->cn_cred
;
470 savecompcredp
= compcredp
;
471 compcredp
= compnamep
->cn_cred
= crdup(savecompcredp
);
473 if (umap_bug_bypass
&& compcredp
->cr_uid
!= 0)
474 printf("umap_rename: rename component credit user was %d, group %d\n",
475 compcredp
->cr_uid
, compcredp
->cr_gid
);
477 /* Map all ids in the credential structure. */
479 umap_mapids(vp
->v_mount
, compcredp
);
481 if (umap_bug_bypass
&& compcredp
->cr_uid
!= 0)
482 printf("umap_rename: rename component credit user now %d, group %d\n",
483 compcredp
->cr_uid
, compcredp
->cr_gid
);
485 error
= umap_bypass(ap
);
487 /* Restore the additional mapped componentname cred structure. */
490 compnamep
->cn_cred
= savecompcredp
;
496 * Global vfs data structures
499 * XXX - strategy, bwrite are hand coded currently. They should
500 * go away with a merged buffer/block cache.
504 #define VOPFUNC int (*)(void *)
506 int (**umap_vnodeop_p
)(void *);
507 struct vnodeopv_entry_desc umap_vnodeop_entries
[] = {
508 { &vop_default_desc
, (VOPFUNC
)umap_bypass
},
509 { &vop_getattr_desc
, (VOPFUNC
)umap_getattr
},
510 { &vop_inactive_desc
, (VOPFUNC
)umap_inactive
},
511 { &vop_reclaim_desc
, (VOPFUNC
)umap_reclaim
},
512 { &vop_print_desc
, (VOPFUNC
)umap_print
},
513 { &vop_rename_desc
, (VOPFUNC
)umap_rename
},
514 { &vop_strategy_desc
, (VOPFUNC
)umap_strategy
},
515 { &vop_bwrite_desc
, (VOPFUNC
)umap_bwrite
},
517 { (struct vnodeop_desc
*) NULL
, (int(*)()) NULL
}
519 struct vnodeopv_desc umap_vnodeop_opv_desc
=
520 { &umap_vnodeop_p
, umap_vnodeop_entries
};