]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/umapfs/umap_vnops.c
xnu-201.19.3.tar.gz
[apple/xnu.git] / bsd / miscfs / umapfs / umap_vnops.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_vnops.c,v 1.3 1994/08/19 11:25:42 mycroft 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 * the UCLA Ficus project.
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 * @(#)umap_vnops.c 8.3 (Berkeley) 1/5/94
60 */
61
62 /*
63 * Umap Layer
64 */
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/time.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>
74 #include <sys/buf.h>
75 #include <miscfs/umapfs/umap.h>
76
77
78 int umap_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
79
80 /*
81 * This is the 10-Apr-92 bypass routine.
82 * See null_vnops.c:null_bypass for more details.
83 */
84 int
85 umap_bypass(ap)
86 struct vop_generic_args /* {
87 struct vnodeop_desc *a_desc;
88 <other random data follows, presumably>
89 } */ *ap;
90 {
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;
96 int error;
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;
102 int reles, i;
103 struct componentname **compnamepp = 0;
104
105 if (umap_bug_bypass)
106 printf ("umap_bypass: %s\n", descp->vdesc_name);
107
108 #ifdef SAFETY
109 /*
110 * We require at least one vp.
111 */
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");
115 #endif
116
117 /*
118 * Map the vnodes going in.
119 * Later, we'll invoke the operation based on
120 * the first mapped vnode's operation vector.
121 */
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);
128
129 if (i == 0) {
130 vp1 = *vps_p[0];
131 }
132
133 /*
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.)
137 */
138
139 if (i && (*this_vp_p)->v_op != umap_vnodeop_p) {
140 old_vps[i] = NULL;
141 } else {
142 old_vps[i] = *this_vp_p;
143 *(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p);
144 if (reles & 1)
145 VREF(*this_vp_p);
146 }
147
148 }
149
150 /*
151 * Fix the credentials. (That's the purpose of this layer.)
152 */
153
154 if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
155
156 credpp = VOPARG_OFFSETTO(struct ucred**,
157 descp->vdesc_cred_offset, ap);
158
159 /* Save old values */
160
161 savecredp = *credpp;
162 if (savecredp != NOCRED)
163 *credpp = crdup(savecredp);
164 credp = *credpp;
165
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);
169
170 /* Map all ids in the credential structure. */
171
172 umap_mapids(vp1->v_mount, credp);
173
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);
177 }
178
179 /* BSD often keeps a credential in the componentname structure
180 * for speed. If there is one, it better get mapped, too.
181 */
182
183 if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
184
185 compnamepp = VOPARG_OFFSETTO(struct componentname**,
186 descp->vdesc_componentname_offset, ap);
187
188 savecompcredp = (*compnamepp)->cn_cred;
189 if (savecompcredp != NOCRED)
190 (*compnamepp)->cn_cred = crdup(savecompcredp);
191 compcredp = (*compnamepp)->cn_cred;
192
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);
196
197 /* Map all ids in the credential structure. */
198
199 umap_mapids(vp1->v_mount, compcredp);
200
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);
204 }
205
206 /*
207 * Call the operation on the lower layer
208 * with the modified argument structure.
209 */
210 error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
211
212 /*
213 * Maintain the illusion of call-by-value
214 * by restoring vnodes in the argument structure
215 * to their original value.
216 */
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 */
221 if (old_vps[i]) {
222 *(vps_p[i]) = old_vps[i];
223 if (reles & 1)
224 vrele(*(vps_p[i]));
225 };
226 };
227
228 /*
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.)
232 */
233 if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
234 !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
235 !error) {
236 if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
237 goto out;
238 vppp = VOPARG_OFFSETTO(struct vnode***,
239 descp->vdesc_vpp_offset, ap);
240 error = umap_node_create(old_vps[0]->v_mount, **vppp, *vppp);
241 };
242
243 out:
244 /*
245 * Free duplicate cred structure and restore old one.
246 */
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",
250 credp->cr_uid);
251
252 if (savecredp != NOCRED) {
253 if (credp != NOCRED)
254 crfree(credp);
255 *credpp = savecredp;
256 if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
257 printf("umap_bypass: returning-user now %d\n\n",
258 savecredp->cr_uid);
259 }
260 }
261
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",
265 compcredp->cr_uid);
266
267 if (savecompcredp != NOCRED) {
268 if (compcredp != NOCRED)
269 crfree(compcredp);
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);
274 }
275 }
276
277 return (error);
278 }
279
280
281 /*
282 * We handle getattr to change the fsid.
283 */
284 int
285 umap_getattr(ap)
286 struct vop_getattr_args /* {
287 struct vnode *a_vp;
288 struct vattr *a_vap;
289 struct ucred *a_cred;
290 struct proc *a_p;
291 } */ *ap;
292 {
293 uid_t uid;
294 gid_t gid;
295 int error, tmpid, nentries, gnentries;
296 uid_t (*mapdata)[2];
297 gid_t (*gmapdata)[2];
298 struct vnode **vp1p;
299 struct vnodeop_desc *descp = ap->a_desc;
300
301 if (error = umap_bypass(ap))
302 return (error);
303 /* Requires that arguments be restored. */
304 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
305
306 /*
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.
315 */
316
317 /* Find entry in map */
318
319 uid = ap->a_vap->va_uid;
320 gid = ap->a_vap->va_gid;
321 if (umap_bug_bypass)
322 printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid,
323 gid);
324
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);
330
331 /* Reverse map the uid for the vnode. Since it's a reverse
332 map, we can't use umap_mapids() to do it. */
333
334 tmpid = umap_reverse_findid(uid, mapdata, nentries);
335
336 if (tmpid != -1) {
337 ap->a_vap->va_uid = (uid_t) tmpid;
338 if (umap_bug_bypass)
339 printf("umap_getattr: original uid = %d\n", uid);
340 } else
341 ap->a_vap->va_uid = (uid_t) NOBODY;
342
343 /* Reverse map the gid for the vnode. */
344
345 tmpid = umap_reverse_findid(gid, gmapdata, gnentries);
346
347 if (tmpid != -1) {
348 ap->a_vap->va_gid = (gid_t) tmpid;
349 if (umap_bug_bypass)
350 printf("umap_getattr: original gid = %d\n", gid);
351 } else
352 ap->a_vap->va_gid = (gid_t) NULLGROUP;
353
354 return (0);
355 }
356
357 int
358 umap_inactive(ap)
359 struct vop_inactive_args /* {
360 struct vnode *a_vp;
361 } */ *ap;
362 {
363 /*
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.
368 *
369 */
370 return (0);
371 }
372
373 int
374 umap_reclaim(ap)
375 struct vop_reclaim_args /* {
376 struct vnode *a_vp;
377 } */ *ap;
378 {
379 struct vnode *vp = ap->a_vp;
380 struct umap_node *xp = VTOUMAP(vp);
381 struct vnode *lowervp = xp->umap_lowervp;
382
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);
387 vp->v_data = NULL;
388 vrele(lowervp);
389 return (0);
390 }
391
392 int
393 umap_strategy(ap)
394 struct vop_strategy_args /* {
395 struct buf *a_bp;
396 } */ *ap;
397 {
398 struct buf *bp = ap->a_bp;
399 int error;
400 struct vnode *savedvp;
401
402 savedvp = bp->b_vp;
403 bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp);
404
405 error = VOP_STRATEGY(ap->a_bp);
406
407 bp->b_vp = savedvp;
408
409 return (error);
410 }
411
412 int
413 umap_bwrite(ap)
414 struct vop_bwrite_args /* {
415 struct buf *a_bp;
416 } */ *ap;
417 {
418 struct buf *bp = ap->a_bp;
419 int error;
420 struct vnode *savedvp;
421
422 savedvp = bp->b_vp;
423 bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp);
424
425 error = VOP_BWRITE(ap->a_bp);
426
427 bp->b_vp = savedvp;
428
429 return (error);
430 }
431
432
433 int
434 umap_print(ap)
435 struct vop_print_args /* {
436 struct vnode *a_vp;
437 } */ *ap;
438 {
439 struct vnode *vp = ap->a_vp;
440 printf("\ttag VT_UMAPFS, vp=%x, lowervp=%x\n", vp, UMAPVPTOLOWERVP(vp));
441 return (0);
442 }
443
444 int
445 umap_rename(ap)
446 struct vop_rename_args /* {
447 struct vnode *a_fdvp;
448 struct vnode *a_fvp;
449 struct componentname *a_fcnp;
450 struct vnode *a_tdvp;
451 struct vnode *a_tvp;
452 struct componentname *a_tcnp;
453 } */ *ap;
454 {
455 int error;
456 struct componentname *compnamep;
457 struct ucred *compcredp, *savecompcredp;
458 struct vnode *vp;
459
460 /*
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.
464 */
465
466 vp = ap->a_fdvp;
467 compnamep = ap->a_tcnp;
468 compcredp = compnamep->cn_cred;
469
470 savecompcredp = compcredp;
471 compcredp = compnamep->cn_cred = crdup(savecompcredp);
472
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);
476
477 /* Map all ids in the credential structure. */
478
479 umap_mapids(vp->v_mount, compcredp);
480
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);
484
485 error = umap_bypass(ap);
486
487 /* Restore the additional mapped componentname cred structure. */
488
489 crfree(compcredp);
490 compnamep->cn_cred = savecompcredp;
491
492 return error;
493 }
494
495 /*
496 * Global vfs data structures
497 */
498 /*
499 * XXX - strategy, bwrite are hand coded currently. They should
500 * go away with a merged buffer/block cache.
501 *
502 */
503
504 #define VOPFUNC int (*)(void *)
505
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 },
516
517 { (struct vnodeop_desc*) NULL, (int(*)()) NULL }
518 };
519 struct vnodeopv_desc umap_vnodeop_opv_desc =
520 { &umap_vnodeop_p, umap_vnodeop_entries };