]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/union/union_subr.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / miscfs / union / union_subr.c
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1994 Jan-Simon Pendry
31 * Copyright (c) 1994
32 * The Regents of the University of California. All rights reserved.
33 *
34 * This code is derived from software contributed to Berkeley by
35 * Jan-Simon Pendry.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)union_subr.c 8.20 (Berkeley) 5/20/95
66 */
2d21ac55
A
67/*
68 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
69 * support for mandatory and extensible security protections. This notice
70 * is included in support of clause 2.2 (b) of the Apple Public License,
71 * Version 2.0.
72 */
1c79356b
A
73
74#include <sys/param.h>
75#include <sys/systm.h>
91447636
A
76#include <sys/proc_internal.h>
77#include <sys/kauth.h>
1c79356b
A
78#include <sys/time.h>
79#include <sys/kernel.h>
91447636 80#include <sys/vnode_internal.h>
1c79356b
A
81#include <sys/namei.h>
82#include <sys/malloc.h>
2d21ac55 83#include <sys/file_internal.h>
1c79356b
A
84#include <sys/filedesc.h>
85#include <sys/queue.h>
91447636 86#include <sys/mount_internal.h>
1c79356b
A
87#include <sys/stat.h>
88#include <sys/ubc.h>
91447636 89#include <sys/uio_internal.h>
1c79356b 90#include <miscfs/union/union.h>
2d21ac55
A
91#include <sys/lock.h>
92#include <sys/kdebug.h>
93#if CONFIG_MACF
94#include <security/mac_framework.h>
1c79356b
A
95#endif
96
2d21ac55
A
97
98static int union_vn_close(struct vnode *vp, int fmode, vfs_context_t ctx);
99
1c79356b
A
100/* must be power of two, otherwise change UNION_HASH() */
101#define NHASH 32
102
103/* unsigned int ... */
104#define UNION_HASH(u, l) \
b0d623f7 105 (((((uintptr_t) (u)) + ((uintptr_t) l)) >> 8) & (NHASH-1))
1c79356b
A
106
107static LIST_HEAD(unhead, union_node) unhead[NHASH];
108static int unvplock[NHASH];
109
2d21ac55
A
110static lck_grp_t * union_lck_grp;
111static lck_grp_attr_t * union_lck_grp_attr;
112static lck_attr_t * union_lck_attr;
113static lck_mtx_t * union_mtxp;
114
115static int union_dircheck(struct vnode **, struct fileproc *, vfs_context_t ctx);
116static void union_newlower(struct union_node *, struct vnode *);
117static void union_newupper(struct union_node *, struct vnode *);
118
119
1c79356b 120int
2d21ac55 121union_init(__unused struct vfsconf *vfsp)
1c79356b
A
122{
123 int i;
124
2d21ac55
A
125 union_lck_grp_attr= lck_grp_attr_alloc_init();
126#if DIAGNOSTIC
127 lck_grp_attr_setstat(union_lck_grp_attr);
128#endif
129 union_lck_grp = lck_grp_alloc_init("union", union_lck_grp_attr);
130 union_lck_attr = lck_attr_alloc_init();
131#if DIAGNOSTIC
132 lck_attr_setdebug(union_lck_attr);
133#endif
134 union_mtxp = lck_mtx_alloc_init(union_lck_grp, union_lck_attr);
135
1c79356b
A
136 for (i = 0; i < NHASH; i++)
137 LIST_INIT(&unhead[i]);
138 bzero((caddr_t) unvplock, sizeof(unvplock));
2d21ac55
A
139 /* add the hook for getdirentries */
140 union_dircheckp = union_dircheck;
141
142 return (0);
1c79356b
A
143}
144
2d21ac55
A
145void
146union_lock()
147{
148 lck_mtx_lock(union_mtxp);
149}
150
151void
152union_unlock()
153{
154 lck_mtx_unlock(union_mtxp);
155}
156
157
1c79356b 158static int
2d21ac55 159union_list_lock(int ix)
1c79356b
A
160{
161
2d21ac55
A
162 if (unvplock[ix] & UNVP_LOCKED) {
163 unvplock[ix] |= UNVP_WANT;
164 msleep((caddr_t) &unvplock[ix], union_mtxp, PINOD, "union_list_lock", NULL);
1c79356b
A
165 return (1);
166 }
167
2d21ac55 168 unvplock[ix] |= UNVP_LOCKED;
1c79356b
A
169
170 return (0);
171}
172
173static void
2d21ac55 174union_list_unlock(int ix)
1c79356b
A
175{
176
2d21ac55 177 unvplock[ix] &= ~UNVP_LOCKED;
1c79356b 178
2d21ac55
A
179 if (unvplock[ix] & UNVP_WANT) {
180 unvplock[ix] &= ~UNVP_WANT;
1c79356b
A
181 wakeup((caddr_t) &unvplock[ix]);
182 }
183}
184
2d21ac55
A
185/*
186 * union_updatevp:
187 *
188 * The uppervp, if not NULL, must be referenced and not locked by us
189 * The lowervp, if not NULL, must be referenced.
190 *
191 * If uppervp and lowervp match pointers already installed, then
192 * nothing happens. The passed vp's (when matching) are not adjusted.
193 *
194 * This routine may only be called by union_newupper() and
195 * union_newlower().
196 */
197
198/* always called with union lock held */
1c79356b 199void
2d21ac55
A
200union_updatevp(struct union_node *un, struct vnode *uppervp,
201 struct vnode *lowervp)
1c79356b
A
202{
203 int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
204 int nhash = UNION_HASH(uppervp, lowervp);
205 int docache = (lowervp != NULLVP || uppervp != NULLVP);
91447636 206 int lhash, uhash;
2d21ac55
A
207 vnode_t freevp;
208 vnode_t freedirvp;
209 caddr_t freepath;
1c79356b
A
210
211 /*
212 * Ensure locking is ordered from lower to higher
213 * to avoid deadlocks.
214 */
215 if (nhash < ohash) {
216 lhash = nhash;
217 uhash = ohash;
218 } else {
219 lhash = ohash;
220 uhash = nhash;
221 }
222
2d21ac55 223 if (lhash != uhash) {
1c79356b
A
224 while (union_list_lock(lhash))
225 continue;
2d21ac55 226 }
1c79356b
A
227
228 while (union_list_lock(uhash))
229 continue;
230
231 if (ohash != nhash || !docache) {
232 if (un->un_flags & UN_CACHED) {
233 un->un_flags &= ~UN_CACHED;
234 LIST_REMOVE(un, un_cache);
235 }
236 }
237
238 if (ohash != nhash)
239 union_list_unlock(ohash);
240
241 if (un->un_lowervp != lowervp) {
2d21ac55
A
242 freevp = freedirvp = NULLVP;
243 freepath = (caddr_t)0;
1c79356b 244 if (un->un_lowervp) {
2d21ac55
A
245 freevp = un->un_lowervp;
246 un->un_lowervp = lowervp;
1c79356b 247 if (un->un_path) {
2d21ac55 248 freepath = un->un_path;
1c79356b
A
249 un->un_path = 0;
250 }
251 if (un->un_dirvp) {
2d21ac55 252 freedirvp = un->un_dirvp;
1c79356b
A
253 un->un_dirvp = NULLVP;
254 }
2d21ac55
A
255 union_unlock();
256 if (freevp)
257 vnode_put(freevp);
258 if (freedirvp)
259 vnode_put(freedirvp);
260 if (freepath)
261 _FREE(un->un_path, M_TEMP);
262 union_lock();
263 } else
264 un->un_lowervp = lowervp;
265 if (lowervp != NULLVP)
266 un->un_lowervid = vnode_vid(lowervp);
1c79356b
A
267 un->un_lowersz = VNOVAL;
268 }
269
270 if (un->un_uppervp != uppervp) {
2d21ac55
A
271 freevp = NULLVP;
272 if (un->un_uppervp) {
273 freevp = un->un_uppervp;
274 }
1c79356b 275 un->un_uppervp = uppervp;
2d21ac55
A
276 if (uppervp != NULLVP)
277 un->un_uppervid = vnode_vid(uppervp);
1c79356b 278 un->un_uppersz = VNOVAL;
2d21ac55
A
279 union_unlock();
280 if (freevp)
281 vnode_put(freevp);
282 union_lock();
1c79356b
A
283 }
284
285 if (docache && (ohash != nhash)) {
286 LIST_INSERT_HEAD(&unhead[nhash], un, un_cache);
287 un->un_flags |= UN_CACHED;
288 }
289
290 union_list_unlock(nhash);
291}
292
2d21ac55
A
293/*
294 * Set a new lowervp. The passed lowervp must be referenced and will be
295 * stored in the vp in a referenced state.
296 */
297/* always called with union lock held */
298
299static void
1c79356b
A
300union_newlower(un, lowervp)
301 struct union_node *un;
302 struct vnode *lowervp;
303{
1c79356b
A
304 union_updatevp(un, un->un_uppervp, lowervp);
305}
306
2d21ac55
A
307/*
308 * Set a new uppervp. The passed uppervp must be locked and will be
309 * stored in the vp in a locked state. The caller should not unlock
310 * uppervp.
311 */
312
313/* always called with union lock held */
314static void
1c79356b
A
315union_newupper(un, uppervp)
316 struct union_node *un;
317 struct vnode *uppervp;
318{
1c79356b
A
319 union_updatevp(un, uppervp, un->un_lowervp);
320}
321
322/*
323 * Keep track of size changes in the underlying vnodes.
324 * If the size changes, then callback to the vm layer
325 * giving priority to the upper layer size.
326 */
2d21ac55 327/* always called with union lock held */
1c79356b
A
328void
329union_newsize(vp, uppersz, lowersz)
330 struct vnode *vp;
331 off_t uppersz, lowersz;
332{
333 struct union_node *un;
334 off_t sz;
335
336 /* only interested in regular files */
337 if (vp->v_type != VREG)
338 return;
339
340 un = VTOUNION(vp);
341 sz = VNOVAL;
342
343 if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) {
344 un->un_uppersz = uppersz;
345 if (sz == VNOVAL)
346 sz = un->un_uppersz;
347 }
348
349 if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) {
350 un->un_lowersz = lowersz;
351 if (sz == VNOVAL)
352 sz = un->un_lowersz;
353 }
354
355 if (sz != VNOVAL) {
356#ifdef UNION_DIAGNOSTIC
357 printf("union: %s size now %ld\n",
358 uppersz != VNOVAL ? "upper" : "lower", (long) sz);
359#endif
2d21ac55 360 union_unlock();
91447636 361 ubc_setsize(vp, sz);
2d21ac55 362 union_lock();
1c79356b
A
363 }
364}
365
366/*
2d21ac55
A
367 * union_allocvp: allocate a union_node and associate it with a
368 * parent union_node and one or two vnodes.
369 *
370 * vpp Holds the returned vnode locked and referenced if no
371 * error occurs.
372 *
373 * mp Holds the mount point. mp may or may not be busied.
374 * allocvp() makes no changes to mp.
375 *
376 * dvp Holds the parent union_node to the one we wish to create.
377 * XXX may only be used to traverse an uncopied lowervp-based
378 * tree? XXX
1c79356b 379 *
2d21ac55
A
380 * dvp may or may not be locked. allocvp() makes no changes
381 * to dvp.
382 *
383 * upperdvp Holds the parent vnode to uppervp, generally used along
384 * with path component information to create a shadow of
385 * lowervp when uppervp does not exist.
386 *
387 * upperdvp is referenced but unlocked on entry, and will be
388 * dereferenced on return.
389 *
390 * uppervp Holds the new uppervp vnode to be stored in the
391 * union_node we are allocating. uppervp is referenced but
392 * not locked, and will be dereferenced on return.
393 *
394 * lowervp Holds the new lowervp vnode to be stored in the
395 * union_node we are allocating. lowervp is referenced but
396 * not locked, and will be dereferenced on return.
397 *
398 * cnp Holds path component information to be coupled with
399 * lowervp and upperdvp to allow unionfs to create an uppervp
400 * later on. Only used if lowervp is valid. The contents
401 * of cnp is only valid for the duration of the call.
402 *
403 * docache Determine whether this node should be entered in the
404 * cache or whether it should be destroyed as soon as possible.
405 *
406 * All union_nodes are maintained on a singly-linked
407 * list. New nodes are only allocated when they cannot
408 * be found on this list. Entries on the list are
1c79356b
A
409 * removed when the vfs reclaim entry is called.
410 *
2d21ac55 411 * A single lock is kept for the entire list. This is
1c79356b
A
412 * needed because the getnewvnode() function can block
413 * waiting for a vnode to become free, in which case there
414 * may be more than one process trying to get the same
2d21ac55
A
415 * vnode. This lock is only taken if we are going to
416 * call getnewvnode(), since the kernel itself is single-threaded.
1c79356b 417 *
2d21ac55
A
418 * If an entry is found on the list, then call vget() to
419 * take a reference. This is done because there may be
1c79356b
A
420 * zero references to it and so it needs to removed from
421 * the vnode free list.
422 */
2d21ac55
A
423
424/* always called with union lock held */
425
1c79356b 426int
2d21ac55
A
427union_allocvp(struct vnode **vpp,
428 struct mount *mp,
429 struct vnode *undvp,
430 struct vnode *dvp,
431 struct componentname *cnp,
432 struct vnode *uppervp,
433 struct vnode *lowervp,
434 int docache)
1c79356b
A
435{
436 int error;
2d21ac55
A
437 struct union_node *un = NULL;
438 struct union_node *unp;
1c79356b
A
439 struct vnode *xlowervp = NULLVP;
440 struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
2d21ac55 441 int hash = 0; /* protected by docache */
91447636 442 int markroot;
1c79356b 443 int try;
91447636
A
444 struct vnode_fsparam vfsp;
445 enum vtype vtype;
1c79356b
A
446
447 if (uppervp == NULLVP && lowervp == NULLVP)
448 panic("union: unidentifiable allocation");
449
2d21ac55
A
450 /*
451 * if both upper and lower vp are provided and are off different type
452 * consider lowervp as NULL
453 */
1c79356b
A
454 if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) {
455 xlowervp = lowervp;
456 lowervp = NULLVP;
457 }
458
459 /* detect the root vnode (and aliases) */
91447636 460 markroot = 0;
1c79356b
A
461 if ((uppervp == um->um_uppervp) &&
462 ((lowervp == NULLVP) || lowervp == um->um_lowervp)) {
463 if (lowervp == NULLVP) {
464 lowervp = um->um_lowervp;
2d21ac55
A
465 if (lowervp != NULLVP) {
466 union_unlock();
91447636 467 vnode_get(lowervp);
2d21ac55
A
468 union_lock();
469 }
1c79356b 470 }
91447636 471 markroot = VROOT;
1c79356b
A
472 }
473
474loop:
475 if (!docache) {
2d21ac55 476 un = NULL;
1c79356b
A
477 } else for (try = 0; try < 3; try++) {
478 switch (try) {
479 case 0:
480 if (lowervp == NULLVP)
481 continue;
482 hash = UNION_HASH(uppervp, lowervp);
483 break;
484
485 case 1:
486 if (uppervp == NULLVP)
487 continue;
488 hash = UNION_HASH(uppervp, NULLVP);
489 break;
490
491 case 2:
492 if (lowervp == NULLVP)
493 continue;
2d21ac55 494 /* Not sure how this path gets exercised ? */
1c79356b
A
495 hash = UNION_HASH(NULLVP, lowervp);
496 break;
497 }
498
499 while (union_list_lock(hash))
500 continue;
501
502 for (un = unhead[hash].lh_first; un != 0;
503 un = un->un_cache.le_next) {
504 if ((un->un_lowervp == lowervp ||
505 un->un_lowervp == NULLVP) &&
506 (un->un_uppervp == uppervp ||
507 un->un_uppervp == NULLVP) &&
2d21ac55 508 (un->un_mount == mp)) {
1c79356b
A
509 break;
510 }
511 }
512
513 union_list_unlock(hash);
514
515 if (un)
516 break;
517 }
518
519 if (un) {
520 /*
521 * Obtain a lock on the union_node.
522 * uppervp is locked, though un->un_uppervp
523 * may not be. this doesn't break the locking
524 * hierarchy since in the case that un->un_uppervp
91447636 525 * is not yet locked it will be vnode_put'd and replaced
1c79356b
A
526 * with uppervp.
527 */
528
2d21ac55
A
529 if (un->un_flags & UN_LOCKED) {
530 un->un_flags |= UN_WANT;
531 msleep((caddr_t) &un->un_flags, union_mtxp, PINOD, "union node locked", 0);
532 goto loop;
533 }
534 un->un_flags |= UN_LOCKED;
535
536 union_unlock();
537 if (UNIONTOV(un) == NULLVP)
538 panic("null vnode in union node\n");
539 if (vnode_get(UNIONTOV(un))) {
540 union_lock();
541 un->un_flags &= ~UN_LOCKED;
542 if ((un->un_flags & UN_WANT) == UN_WANT) {
543 un->un_flags &= ~UN_LOCKED;
544 wakeup(&un->un_flags);
1c79356b 545 }
2d21ac55 546 goto loop;
1c79356b 547 }
2d21ac55 548 union_lock();
1c79356b
A
549
550 /*
551 * At this point, the union_node is locked,
552 * un->un_uppervp may not be locked, and uppervp
553 * is locked or nil.
554 */
555
556 /*
557 * Save information about the upper layer.
558 */
559 if (uppervp != un->un_uppervp) {
560 union_newupper(un, uppervp);
561 } else if (uppervp) {
2d21ac55 562 union_unlock();
91447636 563 vnode_put(uppervp);
2d21ac55 564 union_lock();
1c79356b
A
565 }
566
567 /*
568 * Save information about the lower layer.
569 * This needs to keep track of pathname
570 * and directory information which union_vn_create
571 * might need.
572 */
573 if (lowervp != un->un_lowervp) {
574 union_newlower(un, lowervp);
575 if (cnp && (lowervp != NULLVP)) {
576 un->un_hash = cnp->cn_hash;
2d21ac55 577 union_unlock();
1c79356b
A
578 MALLOC(un->un_path, caddr_t, cnp->cn_namelen+1,
579 M_TEMP, M_WAITOK);
580 bcopy(cnp->cn_nameptr, un->un_path,
581 cnp->cn_namelen);
91447636 582 vnode_get(dvp);
2d21ac55
A
583 union_lock();
584 un->un_path[cnp->cn_namelen] = '\0';
1c79356b
A
585 un->un_dirvp = dvp;
586 }
587 } else if (lowervp) {
2d21ac55 588 union_unlock();
91447636 589 vnode_put(lowervp);
2d21ac55 590 union_lock();
1c79356b
A
591 }
592 *vpp = UNIONTOV(un);
2d21ac55
A
593 un->un_flags &= ~UN_LOCKED;
594 if ((un->un_flags & UN_WANT) == UN_WANT) {
595 un->un_flags &= ~UN_WANT;
596 wakeup(&un->un_flags);
597 }
1c79356b
A
598 return (0);
599 }
600
601 if (docache) {
602 /*
603 * otherwise lock the vp list while we call getnewvnode
604 * since that can block.
605 */
606 hash = UNION_HASH(uppervp, lowervp);
607
608 if (union_list_lock(hash))
609 goto loop;
610 }
611
2d21ac55 612 union_unlock();
1c79356b 613 MALLOC(unp, void *, sizeof(struct union_node), M_TEMP, M_WAITOK);
2d21ac55
A
614 union_lock();
615
616 bzero(unp, sizeof(struct union_node));
617 un = unp;
618 un->un_uppervp = uppervp;
619 if (uppervp != NULLVP)
620 un->un_uppervid = vnode_vid(uppervp);
621 un->un_uppersz = VNOVAL;
622 un->un_lowervp = lowervp;
623 if (lowervp != NULLVP)
624 un->un_lowervid = vnode_vid(lowervp);
625 un->un_lowersz = VNOVAL;
626 un->un_pvp = undvp;
627 if (undvp != NULLVP)
628 vnode_get(undvp);
629 un->un_dircache = 0;
630 un->un_openl = 0;
631 un->un_mount = mp;
632 un->un_flags = UN_LOCKED;
633#ifdef FAULTFS
634 if (UNION_FAULTIN(um))
635 un->un_flags |= UN_FAULTFS;
636#endif
637
638 if (docache) {
639 /* Insert with lock held */
640 LIST_INSERT_HEAD(&unhead[hash], un, un_cache);
641 un->un_flags |= UN_CACHED;
642 union_list_unlock(hash);
643 }
644
645 union_unlock();
91447636
A
646
647 if (uppervp)
648 vtype = uppervp->v_type;
649 else
650 vtype = lowervp->v_type;
2d21ac55
A
651
652 bzero(&vfsp, sizeof(struct vnode_fsparam));
91447636
A
653 vfsp.vnfs_mp = mp;
654 vfsp.vnfs_vtype = vtype;
655 vfsp.vnfs_str = "unionfs";
2d21ac55 656 vfsp.vnfs_dvp = undvp;
91447636
A
657 vfsp.vnfs_fsnode = unp;
658 vfsp.vnfs_cnp = cnp;
659 vfsp.vnfs_vops = union_vnodeop_p;
660 vfsp.vnfs_rdev = 0;
661 vfsp.vnfs_filesize = 0;
662 vfsp.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE;
663 vfsp.vnfs_marksystem = 0;
664 vfsp.vnfs_markroot = markroot;
665
666 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, vpp);
1c79356b 667 if (error) {
2d21ac55 668 /* XXXXX Is this right ???? XXXXXXX */
1c79356b 669 if (uppervp) {
91447636 670 vnode_put(uppervp);
1c79356b
A
671 }
672 if (lowervp)
91447636 673 vnode_put(lowervp);
1c79356b 674
2d21ac55
A
675 union_lock();
676 if (un->un_flags & UN_CACHED) {
677 un->un_flags &= ~UN_CACHED;
678 LIST_REMOVE(un, un_cache);
679 }
680 if (docache)
681 union_list_unlock(hash);
682
683 FREE(unp, M_TEMP);
684
685 return (error);
1c79356b
A
686 }
687
1c79356b
A
688 if (cnp && (lowervp != NULLVP)) {
689 un->un_hash = cnp->cn_hash;
690 un->un_path = _MALLOC(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
691 bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
692 un->un_path[cnp->cn_namelen] = '\0';
91447636 693 vnode_get(dvp);
1c79356b
A
694 un->un_dirvp = dvp;
695 } else {
696 un->un_hash = 0;
697 un->un_path = 0;
698 un->un_dirvp = 0;
699 }
700
1c79356b 701 if (xlowervp)
91447636 702 vnode_put(xlowervp);
1c79356b 703
2d21ac55
A
704 union_lock();
705
706 vnode_settag(*vpp, VT_UNION);
707 un->un_vnode = *vpp;
708 if (un->un_vnode->v_type == VDIR) {
709 if (un->un_uppervp == NULLVP) {
710 panic("faulting fs and no upper vp for dir?");
711 }
712
713 }
714
715
716 un->un_flags &= ~UN_LOCKED;
717 if ((un->un_flags & UN_WANT) == UN_WANT) {
718 un->un_flags &= ~UN_WANT;
719 wakeup(&un->un_flags);
720 }
721
722 return(error);
1c79356b 723
1c79356b
A
724}
725
2d21ac55 726/* always called with union lock held */
1c79356b 727int
2d21ac55 728union_freevp(struct vnode *vp)
1c79356b
A
729{
730 struct union_node *un = VTOUNION(vp);
731
732 if (un->un_flags & UN_CACHED) {
733 un->un_flags &= ~UN_CACHED;
734 LIST_REMOVE(un, un_cache);
735 }
736
2d21ac55 737 union_unlock();
1c79356b 738 if (un->un_pvp != NULLVP)
91447636 739 vnode_put(un->un_pvp);
1c79356b 740 if (un->un_uppervp != NULLVP)
91447636 741 vnode_put(un->un_uppervp);
1c79356b 742 if (un->un_lowervp != NULLVP)
91447636 743 vnode_put(un->un_lowervp);
1c79356b 744 if (un->un_dirvp != NULLVP)
91447636 745 vnode_put(un->un_dirvp);
1c79356b
A
746 if (un->un_path)
747 _FREE(un->un_path, M_TEMP);
748
749 FREE(vp->v_data, M_TEMP);
750 vp->v_data = 0;
2d21ac55 751 union_lock();
1c79356b
A
752
753 return (0);
754}
755
756/*
757 * copyfile. copy the vnode (fvp) to the vnode (tvp)
758 * using a sequence of reads and writes. both (fvp)
759 * and (tvp) are locked on entry and exit.
760 */
2d21ac55 761/* called with no union lock held */
1c79356b 762int
2d21ac55 763union_copyfile(struct vnode *fvp, struct vnode *tvp, vfs_context_t context)
1c79356b 764{
91447636 765 char *bufp;
b0d623f7
A
766 struct uio *auio;
767 char uio_buf [ UIO_SIZEOF(1) ];
1c79356b
A
768 int error = 0;
769
770 /*
771 * strategy:
772 * allocate a buffer of size MAXPHYSIO.
773 * loop doing reads and writes, keeping track
774 * of the current uio offset.
775 * give up at the first sign of trouble.
776 */
777
b0d623f7
A
778 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE,
779 UIO_READ /* will change */, &uio_buf, sizeof(uio_buf));
1c79356b 780
91447636 781 bufp = _MALLOC(MAXPHYSIO, M_TEMP, M_WAITOK);
b0d623f7
A
782 if (bufp == NULL) {
783 return ENOMEM;
784 }
1c79356b
A
785
786 /* ugly loop follows... */
787 do {
b0d623f7 788 off_t offset = uio_offset(auio);
1c79356b 789
b0d623f7
A
790 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
791 uio_addiov(auio, (uintptr_t)bufp, MAXPHYSIO);
792 error = VNOP_READ(fvp, auio, 0, context);
1c79356b
A
793
794 if (error == 0) {
b0d623f7
A
795 user_ssize_t resid = uio_resid(auio);
796
797 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
798 uio_addiov(auio, (uintptr_t)bufp, MAXPHYSIO - resid);
799
800 if (uio_resid(auio) == 0)
1c79356b
A
801 break;
802
803 do {
b0d623f7
A
804 error = VNOP_WRITE(tvp, auio, 0, context);
805 } while ((uio_resid(auio) > 0) && (error == 0));
1c79356b
A
806 }
807
808 } while (error == 0);
809
91447636 810 _FREE(bufp, M_TEMP);
1c79356b
A
811 return (error);
812}
813
814/*
815 * (un) is assumed to be locked on entry and remains
816 * locked on exit.
817 */
2d21ac55 818/* always called with union lock held */
1c79356b 819int
2d21ac55 820union_copyup(struct union_node *un, int docopy, vfs_context_t context)
1c79356b
A
821{
822 int error;
823 struct vnode *lvp, *uvp;
2d21ac55
A
824 struct vnode_attr vattr;
825 mode_t cmode = 0;
1c79356b 826
2d21ac55
A
827
828 lvp = un->un_lowervp;
1c79356b 829
2d21ac55 830 union_unlock();
91447636 831
2d21ac55
A
832 if (UNNODE_FAULTIN(un)) {
833 /* Need to inherit exec mode in faulting fs */
834 VATTR_INIT(&vattr);
835 VATTR_WANTED(&vattr, va_flags);
836 if (vnode_getattr(lvp, &vattr, context) == 0 )
837 cmode = vattr.va_mode;
838
839 }
840 error = union_vn_create(&uvp, un, cmode, context);
841 if (error) {
842 union_lock();
843 if (error == EEXIST) {
844 if (uvp != NULLVP) {
845 union_newupper(un, uvp);
846 error = 0;
847 }
848 }
849 return (error);
850 }
851
852 union_lock();
1c79356b
A
853 /* at this point, uppervp is locked */
854 union_newupper(un, uvp);
2d21ac55 855 union_unlock();
1c79356b 856
1c79356b
A
857
858 if (docopy) {
859 /*
860 * XX - should not ignore errors
91447636 861 * from vnop_close
1c79356b 862 */
2d21ac55 863 error = VNOP_OPEN(lvp, FREAD, context);
1c79356b 864 if (error == 0) {
2d21ac55
A
865 error = union_copyfile(lvp, uvp, context);
866 (void) VNOP_CLOSE(lvp, FREAD, context);
1c79356b
A
867 }
868#ifdef UNION_DIAGNOSTIC
869 if (error == 0)
870 uprintf("union: copied up %s\n", un->un_path);
871#endif
872
873 }
2d21ac55 874 union_vn_close(uvp, FWRITE, context);
1c79356b
A
875
876 /*
877 * Subsequent IOs will go to the top layer, so
878 * call close on the lower vnode and open on the
879 * upper vnode to ensure that the filesystem keeps
880 * its references counts right. This doesn't do
881 * the right thing with (cred) and (FREAD) though.
882 * Ignoring error returns is not right, either.
883 */
2d21ac55
A
884
885 /* No need to hold the lock as the union node should be locked for this(it is in faultin mode) */
1c79356b
A
886 if (error == 0) {
887 int i;
888
889 for (i = 0; i < un->un_openl; i++) {
2d21ac55
A
890 (void) VNOP_CLOSE(lvp, FREAD, context);
891 (void) VNOP_OPEN(uvp, FREAD, context);
1c79356b
A
892 }
893 un->un_openl = 0;
894 }
895
2d21ac55
A
896 union_lock();
897
1c79356b
A
898 return (error);
899
900}
901
2d21ac55
A
902
903int
904union_faultin_copyup(struct vnode **vpp, vnode_t udvp, vnode_t lvp, struct componentname * cnp, vfs_context_t context)
905{
906 int error;
907 struct vnode *uvp;
908 struct vnode_attr vattr;
909 struct vnode_attr *vap;
910 mode_t cmode = 0;
911 int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL);
912 struct proc * p = vfs_context_proc(context);
913 struct componentname cn;
914
915
916 vap = &vattr;
917 VATTR_INIT(vap);
918 VATTR_WANTED(vap, va_flags);
919 if (vnode_getattr(lvp, vap, context) == 0 )
920 cmode = vattr.va_mode;
921
922 *vpp = NULLVP;
923
924
925 if (cmode == (mode_t)0)
926 cmode = UN_FILEMODE & ~p->p_fd->fd_cmask;
927 else
928 cmode = cmode & ~p->p_fd->fd_cmask;
929
930
931 /*
932 * Build a new componentname structure (for the same
933 * reasons outlines in union_mkshadow()).
934 * The difference here is that the file is owned by
935 * the current user, rather than by the person who
936 * did the mount, since the current user needs to be
937 * able to write the file (that's why it is being
938 * copied in the first place).
939 */
940 bzero(&cn, sizeof(struct componentname));
941
942 cn.cn_namelen = cnp->cn_namelen;
943 cn.cn_pnbuf = (caddr_t) _MALLOC_ZONE(cn.cn_namelen+1,
944 M_NAMEI, M_WAITOK);
945 cn.cn_pnlen = cn.cn_namelen+1;
946 bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cn.cn_namelen+1);
947 cn.cn_nameiop = CREATE;
948 cn.cn_flags = (HASBUF|SAVENAME|SAVESTART|ISLASTCN|UNIONCREATED);
949 cn.cn_context = context;
950 cn.cn_nameptr = cn.cn_pnbuf;
951 cn.cn_hash = 0;
952 cn.cn_consume = 0;
953
954 /*
955 * Pass dvp unlocked and referenced on call to relookup().
956 *
957 * If an error occurs, dvp will be returned unlocked and dereferenced.
958 */
959 if ((error = relookup(udvp, &uvp, &cn)) != 0) {
960 goto out;
961 }
962
963 /*
964 * If no error occurs, dvp will be returned locked with the reference
965 * left as before, and vpp will be returned referenced and locked.
966 */
967 if (uvp) {
968 *vpp = uvp;
969 error = EEXIST;
970 goto out;
971 }
972
973 /*
974 * Good - there was no race to create the file
975 * so go ahead and create it. The permissions
976 * on the file will be 0666 modified by the
977 * current user's umask. Access to the file, while
978 * it is unioned, will require access to the top *and*
979 * bottom files. Access when not unioned will simply
980 * require access to the top-level file.
981 *
982 * TODO: confirm choice of access permissions.
983 * decide on authorisation behaviour
984 */
985
986 VATTR_INIT(vap);
987 VATTR_SET(vap, va_type, VREG);
988 VATTR_SET(vap, va_mode, cmode);
989
990 cn.cn_flags |= (UNIONCREATED);
991 if ((error = vn_create(udvp, &uvp, &cn, vap, 0, context)) != 0) {
992 goto out;
993 }
994
995
996 if ((error = VNOP_OPEN(uvp, fmode, context)) != 0) {
997 vn_clearunionwait(uvp, 0);
998 vnode_recycle(uvp);
999 vnode_put(uvp);
1000 goto out;
1001 }
1002
1003 error = vnode_ref_ext(uvp, fmode);
1004 if (error ) {
1005 vn_clearunionwait(uvp, 0);
1006 VNOP_CLOSE(uvp, fmode, context);
1007 vnode_recycle(uvp);
1008 vnode_put(uvp);
1009 goto out;
1010 }
1011
1012
1013 /*
1014 * XX - should not ignore errors
1015 * from vnop_close
1016 */
1017 error = VNOP_OPEN(lvp, FREAD, context);
1018 if (error == 0) {
1019 error = union_copyfile(lvp, uvp, context);
1020 (void) VNOP_CLOSE(lvp, FREAD, context);
1021 }
1022
1023 VNOP_CLOSE(uvp, fmode, context);
1024 vnode_rele_ext(uvp, fmode, 0);
1025 vn_clearunionwait(uvp, 0);
1026
1027 *vpp = uvp;
1028out:
1029 if ((cn.cn_flags & HASBUF) == HASBUF) {
1030 FREE_ZONE(cn.cn_pnbuf, cn.cn_pnlen, M_NAMEI);
1031 cn.cn_flags &= ~HASBUF;
1032 }
1033 return (error);
1034}
1035
1036
1037/*
1038 * union_relookup:
1039 *
1040 * dvp should be locked on entry and will be locked on return. No
1041 * net change in the ref count will occur.
1042 *
1043 * If an error is returned, *vpp will be invalid, otherwise it
1044 * will hold a locked, referenced vnode. If *vpp == dvp then
1045 * remember that only one exclusive lock is held.
1046 */
1047
1048/* No union lock held for this call */
1c79356b 1049static int
2d21ac55
A
1050union_relookup(
1051#ifdef XXX_HELP_ME
1052 struct union_mount *um,
1053#else /* !XXX_HELP_ME */
1054 __unused struct union_mount *um,
1055#endif /* !XXX_HELP_ME */
1056 struct vnode *dvp,
1057 struct vnode **vpp,
1058 struct componentname *cnp,
1059 struct componentname *cn,
1060 char *path,
1061 int pathlen)
1c79356b
A
1062{
1063 int error;
1064
1065 /*
1066 * A new componentname structure must be faked up because
1067 * there is no way to know where the upper level cnp came
1068 * from or what it is being used for. This must duplicate
1069 * some of the work done by NDINIT, some of the work done
1070 * by namei, some of the work done by lookup and some of
91447636 1071 * the work done by vnop_lookup when given a CREATE flag.
1c79356b 1072 * Conclusion: Horrible.
1c79356b
A
1073 */
1074 cn->cn_namelen = pathlen;
1075 cn->cn_pnbuf = _MALLOC_ZONE(cn->cn_namelen+1, M_NAMEI, M_WAITOK);
1076 cn->cn_pnlen = cn->cn_namelen+1;
1077 bcopy(path, cn->cn_pnbuf, cn->cn_namelen);
1078 cn->cn_pnbuf[cn->cn_namelen] = '\0';
1079
1080 cn->cn_nameiop = CREATE;
2d21ac55 1081 cn->cn_flags = (HASBUF|SAVENAME|SAVESTART|ISLASTCN );
91447636 1082#ifdef XXX_HELP_ME
1c79356b
A
1083 cn->cn_proc = cnp->cn_proc;
1084 if (um->um_op == UNMNT_ABOVE)
1085 cn->cn_cred = cnp->cn_cred;
1086 else
1087 cn->cn_cred = um->um_cred;
91447636
A
1088#endif
1089 cn->cn_context = cnp->cn_context; /* XXX !UNMNT_ABOVE case ??? */
1c79356b 1090 cn->cn_nameptr = cn->cn_pnbuf;
2d21ac55 1091 cn->cn_hash = 0;
1c79356b
A
1092 cn->cn_consume = cnp->cn_consume;
1093
91447636 1094 vnode_get(dvp);
1c79356b 1095 error = relookup(dvp, vpp, cn);
2d21ac55 1096 vnode_put(dvp);
1c79356b
A
1097
1098 return (error);
1099}
1100
1101/*
1102 * Create a shadow directory in the upper layer.
1103 * The new vnode is returned locked.
1104 *
1105 * (um) points to the union mount structure for access to the
1106 * the mounting process's credentials.
2d21ac55
A
1107 * (dvp) is the directory in which to create the shadow directory,
1108 * It is locked (but not ref'd) on entry and return.
1109 * (cnp) is the component name to be created.
1c79356b 1110 * (vpp) is the returned newly created shadow directory, which
2d21ac55 1111 * is returned locked and ref'd
1c79356b 1112 */
2d21ac55 1113/* No union lock held for this call */
1c79356b
A
1114int
1115union_mkshadow(um, dvp, cnp, vpp)
1116 struct union_mount *um;
1117 struct vnode *dvp;
1118 struct componentname *cnp;
1119 struct vnode **vpp;
1120{
1121 int error;
91447636 1122 struct vnode_attr va;
1c79356b
A
1123 struct componentname cn;
1124
2d21ac55
A
1125 bzero(&cn, sizeof(struct componentname));
1126
1127
1c79356b
A
1128 error = union_relookup(um, dvp, vpp, cnp, &cn,
1129 cnp->cn_nameptr, cnp->cn_namelen);
2d21ac55
A
1130 if (error)
1131 goto out;
1c79356b
A
1132
1133 if (*vpp) {
2d21ac55
A
1134 error = EEXIST;
1135 goto out;
1c79356b
A
1136 }
1137
1138 /*
2d21ac55 1139 * Policy: when creating the shadow directory in the
1c79356b
A
1140 * upper layer, create it owned by the user who did
1141 * the mount, group from parent directory, and mode
1142 * 777 modified by umask (ie mostly identical to the
1143 * mkdir syscall). (jsp, kb)
1144 */
2d21ac55 1145
91447636
A
1146 VATTR_INIT(&va);
1147 VATTR_SET(&va, va_type, VDIR);
1148 VATTR_SET(&va, va_mode, um->um_cmode);
1c79356b 1149
91447636 1150 error = vn_create(dvp, vpp, &cn, &va, 0, cnp->cn_context);
2d21ac55
A
1151out:
1152 if ((cn.cn_flags & HASBUF) == HASBUF) {
1153 FREE_ZONE(cn.cn_pnbuf, cn.cn_pnlen, M_NAMEI);
1154 cn.cn_flags &= ~HASBUF;
1155 }
1c79356b
A
1156 return (error);
1157}
1158
1159/*
1160 * Create a whiteout entry in the upper layer.
1161 *
1162 * (um) points to the union mount structure for access to the
1163 * the mounting process's credentials.
1164 * (dvp) is the directory in which to create the whiteout.
1165 * it is locked on entry and exit.
1166 * (cnp) is the componentname to be created.
1167 */
2d21ac55 1168/* No union lock held for this call */
1c79356b
A
1169int
1170union_mkwhiteout(um, dvp, cnp, path)
1171 struct union_mount *um;
1172 struct vnode *dvp;
1173 struct componentname *cnp;
1174 char *path;
1175{
1176 int error;
1c79356b
A
1177 struct vnode *wvp;
1178 struct componentname cn;
1179
2d21ac55
A
1180 bzero(&cn, sizeof(struct componentname));
1181
1c79356b
A
1182 error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path));
1183 if (error) {
2d21ac55 1184 goto out;
1c79356b 1185 }
1c79356b 1186 if (wvp) {
2d21ac55
A
1187 error = EEXIST;
1188 goto out;
1c79356b
A
1189 }
1190
91447636 1191 error = VNOP_WHITEOUT(dvp, &cn, CREATE, cnp->cn_context);
1c79356b 1192
2d21ac55
A
1193out:
1194 if ((cn.cn_flags & HASBUF) == HASBUF) {
1195 FREE_ZONE(cn.cn_pnbuf, cn.cn_pnlen, M_NAMEI);
1196 cn.cn_flags &= ~HASBUF;
1197 }
1c79356b
A
1198 return (error);
1199}
1200
2d21ac55 1201
1c79356b
A
1202/*
1203 * union_vn_create: creates and opens a new shadow file
2d21ac55
A
1204 * on the upper union layer. This function is similar
1205 * in spirit to calling vn_open() but it avoids calling namei().
1206 * The problem with calling namei() is that a) it locks too many
1c79356b 1207 * things, and b) it doesn't start at the "right" directory,
2d21ac55
A
1208 * whereas relookup() is told where to start.
1209 *
1210 * On entry, the vnode associated with un is locked. It remains locked
1211 * on return.
1212 *
1213 * If no error occurs, *vpp contains a locked referenced vnode for your
1214 * use. If an error occurs *vpp iis undefined.
1c79356b 1215 */
2d21ac55 1216/* called with no union lock held */
1c79356b 1217int
2d21ac55 1218union_vn_create(struct vnode **vpp, struct union_node *un, mode_t cmode, vfs_context_t context)
1c79356b
A
1219{
1220 struct vnode *vp;
91447636
A
1221 struct vnode_attr vat;
1222 struct vnode_attr *vap = &vat;
1c79356b
A
1223 int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL);
1224 int error;
2d21ac55 1225 struct proc * p = vfs_context_proc(context);
1c79356b
A
1226 struct componentname cn;
1227
2d21ac55 1228 bzero(&cn, sizeof(struct componentname));
1c79356b
A
1229 *vpp = NULLVP;
1230
2d21ac55
A
1231 if (cmode == (mode_t)0)
1232 cmode = UN_FILEMODE & ~p->p_fd->fd_cmask;
1233 else
1234 cmode = cmode & ~p->p_fd->fd_cmask;
1235
91447636 1236
1c79356b
A
1237 /*
1238 * Build a new componentname structure (for the same
2d21ac55 1239 * reasons outlines in union_mkshadow()).
1c79356b
A
1240 * The difference here is that the file is owned by
1241 * the current user, rather than by the person who
1242 * did the mount, since the current user needs to be
1243 * able to write the file (that's why it is being
1244 * copied in the first place).
1245 */
1246 cn.cn_namelen = strlen(un->un_path);
1247 cn.cn_pnbuf = (caddr_t) _MALLOC_ZONE(cn.cn_namelen+1,
1248 M_NAMEI, M_WAITOK);
1249 cn.cn_pnlen = cn.cn_namelen+1;
1250 bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1);
1251 cn.cn_nameiop = CREATE;
2d21ac55
A
1252 if (UNNODE_FAULTIN(un))
1253 cn.cn_flags = (HASBUF|SAVENAME|SAVESTART|ISLASTCN|UNIONCREATED);
1254 else
1255 cn.cn_flags = (HASBUF|SAVENAME|SAVESTART|ISLASTCN);
1256 cn.cn_context = context;
1c79356b
A
1257 cn.cn_nameptr = cn.cn_pnbuf;
1258 cn.cn_hash = un->un_hash;
1259 cn.cn_consume = 0;
1260
2d21ac55
A
1261 /*
1262 * Pass dvp unlocked and referenced on call to relookup().
1263 *
1264 * If an error occurs, dvp will be returned unlocked and dereferenced.
1265 */
91447636 1266 vnode_get(un->un_dirvp);
2d21ac55
A
1267 if ((error = relookup(un->un_dirvp, &vp, &cn)) != 0) {
1268 vnode_put(un->un_dirvp);
1269 goto out;
0c530ab8 1270 }
91447636 1271 vnode_put(un->un_dirvp);
1c79356b 1272
2d21ac55
A
1273 /*
1274 * If no error occurs, dvp will be returned locked with the reference
1275 * left as before, and vpp will be returned referenced and locked.
1276 */
1c79356b 1277 if (vp) {
2d21ac55
A
1278 *vpp = vp;
1279 error = EEXIST;
1280 goto out;
1c79356b
A
1281 }
1282
1283 /*
1284 * Good - there was no race to create the file
1285 * so go ahead and create it. The permissions
1286 * on the file will be 0666 modified by the
1287 * current user's umask. Access to the file, while
1288 * it is unioned, will require access to the top *and*
1289 * bottom files. Access when not unioned will simply
1290 * require access to the top-level file.
91447636 1291 *
1c79356b 1292 * TODO: confirm choice of access permissions.
91447636 1293 * decide on authorisation behaviour
1c79356b 1294 */
91447636
A
1295
1296 VATTR_INIT(vap);
1297 VATTR_SET(vap, va_type, VREG);
1298 VATTR_SET(vap, va_mode, cmode);
1299
2d21ac55
A
1300 if ((error = vn_create(un->un_dirvp, &vp, &cn, vap, 0, context)) != 0) {
1301 goto out;
0c530ab8 1302 }
1c79356b 1303
2d21ac55 1304 if ((error = VNOP_OPEN(vp, fmode, context)) != 0) {
91447636 1305 vnode_put(vp);
2d21ac55 1306 goto out;
1c79356b
A
1307 }
1308
91447636 1309 vnode_lock(vp);
1c79356b
A
1310 if (++vp->v_writecount <= 0)
1311 panic("union: v_writecount");
91447636 1312 vnode_unlock(vp);
1c79356b 1313 *vpp = vp;
2d21ac55
A
1314 error = 0;
1315
1316out:
1317 if ((cn.cn_flags & HASBUF) == HASBUF) {
1318 FREE_ZONE(cn.cn_pnbuf, cn.cn_pnlen, M_NAMEI);
1319 cn.cn_flags &= ~HASBUF;
1320 }
1321 return(error);
1c79356b
A
1322}
1323
2d21ac55
A
1324/* called with no union lock held */
1325static int
1326union_vn_close(struct vnode *vp, int fmode, vfs_context_t context)
1c79356b
A
1327{
1328
91447636
A
1329 if (fmode & FWRITE) {
1330 vnode_lock(vp);
1c79356b 1331 --vp->v_writecount;
91447636
A
1332 vnode_unlock(vp);
1333 }
2d21ac55 1334 return (VNOP_CLOSE(vp, fmode, context));
1c79356b
A
1335}
1336
2d21ac55
A
1337/*
1338 * union_removed_upper:
1339 *
1340 * An upper-only file/directory has been removed; un-cache it so
1341 * that unionfs vnode gets reclaimed and the last uppervp reference
1342 * disappears.
1343 *
1344 * Called with union_node unlocked.
1345 */
1346/* always called with union lock held */
1c79356b
A
1347void
1348union_removed_upper(un)
1349 struct union_node *un;
1350{
1c79356b
A
1351 union_newupper(un, NULLVP);
1352 if (un->un_flags & UN_CACHED) {
1353 un->un_flags &= ~UN_CACHED;
1354 LIST_REMOVE(un, un_cache);
1355 }
1356
1c79356b
A
1357}
1358
1359#if 0
1360struct vnode *
1361union_lowervp(vp)
1362 struct vnode *vp;
1363{
1364 struct union_node *un = VTOUNION(vp);
1365
1366 if ((un->un_lowervp != NULLVP) &&
1367 (vp->v_type == un->un_lowervp->v_type)) {
91447636 1368 if (vnode_get(un->un_lowervp) == 0)
1c79356b
A
1369 return (un->un_lowervp);
1370 }
1371
1372 return (NULLVP);
1373}
1374#endif
1375
1376/*
2d21ac55 1377 * Determine whether a whiteout is needed
1c79356b
A
1378 * during a remove/rmdir operation.
1379 */
2d21ac55 1380/* called with no union lock held */
1c79356b 1381int
91447636 1382union_dowhiteout(struct union_node *un, vfs_context_t ctx)
1c79356b 1383{
91447636 1384 struct vnode_attr va;
1c79356b 1385
2d21ac55
A
1386 if (UNNODE_FAULTIN(un))
1387 return(0);
1388
1389 if ((un->un_lowervp != NULLVP) )
1c79356b
A
1390 return (1);
1391
91447636
A
1392 VATTR_INIT(&va);
1393 VATTR_WANTED(&va, va_flags);
1394 if (vnode_getattr(un->un_uppervp, &va, ctx) == 0 &&
1c79356b
A
1395 (va.va_flags & OPAQUE))
1396 return (1);
1397
1398 return (0);
1399}
1400
2d21ac55 1401/* called with no union lock held */
1c79356b 1402static void
2d21ac55 1403union_dircache_r(struct vnode *vp, struct vnode ***vppp, int *cntp)
1c79356b
A
1404{
1405 struct union_node *un;
1406
1407 if (vp->v_op != union_vnodeop_p) {
1408 if (vppp) {
91447636 1409 vnode_get(vp);
1c79356b
A
1410 *(*vppp)++ = vp;
1411 if (--(*cntp) == 0)
1412 panic("union: dircache table too small");
1413 } else {
1414 (*cntp)++;
1415 }
1416
1417 return;
1418 }
1419
1420 un = VTOUNION(vp);
1421 if (un->un_uppervp != NULLVP)
1422 union_dircache_r(un->un_uppervp, vppp, cntp);
1423 if (un->un_lowervp != NULLVP)
1424 union_dircache_r(un->un_lowervp, vppp, cntp);
1425}
1426
2d21ac55 1427/* called with no union lock held */
1c79356b 1428struct vnode *
2d21ac55 1429union_dircache(struct vnode *vp, __unused vfs_context_t context)
1c79356b 1430{
91447636 1431 int count;
2d21ac55 1432 struct vnode *nvp, *lvp;
1c79356b 1433 struct vnode **vpp;
2d21ac55 1434 struct vnode **dircache, **newdircache;
1c79356b
A
1435 struct union_node *un;
1436 int error;
2d21ac55 1437 int alloced = 0;
1c79356b 1438
2d21ac55
A
1439 union_lock();
1440 newdircache = NULL;
1c79356b
A
1441
1442 nvp = NULLVP;
2d21ac55 1443 un = VTOUNION(vp);
1c79356b 1444
2d21ac55 1445 dircache = un->un_dircache;
1c79356b 1446 if (dircache == 0) {
2d21ac55 1447 union_unlock();
91447636
A
1448 count = 0;
1449 union_dircache_r(vp, 0, &count);
1450 count++;
2d21ac55
A
1451#if 0
1452 /* too bad; we need Union now! */
1453#if MAC_XXX
1454 panic("MAC Framework doesn't support unionfs (yet)\n");
1455#endif /* MAC */
1456#endif
1457
1c79356b 1458 dircache = (struct vnode **)
91447636 1459 _MALLOC(count * sizeof(struct vnode *),
1c79356b 1460 M_TEMP, M_WAITOK);
b0d623f7
A
1461 if (dircache == NULL) {
1462 goto out;
1463 }
2d21ac55
A
1464 newdircache = dircache;
1465 alloced = 1;
1c79356b 1466 vpp = dircache;
91447636 1467 union_dircache_r(vp, &vpp, &count);
1c79356b
A
1468 *vpp = NULLVP;
1469 vpp = dircache + 1;
2d21ac55 1470 union_lock();
1c79356b
A
1471 } else {
1472 vpp = dircache;
1473 do {
2d21ac55 1474 if (*vpp++ == un->un_uppervp)
1c79356b
A
1475 break;
1476 } while (*vpp != NULLVP);
1477 }
1478
2d21ac55
A
1479 lvp = *vpp;
1480 union_unlock();
1481 if (lvp == NULLVP) {
1c79356b 1482 goto out;
2d21ac55 1483 }
1c79356b 1484
2d21ac55
A
1485 vnode_get(lvp);
1486 union_lock();
1487
1488 error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, lvp, NULLVP, 0);
1489 if (error) {
1490 union_unlock();
1491 vnode_put(lvp);
1c79356b 1492 goto out;
2d21ac55 1493 }
1c79356b 1494
2d21ac55 1495 un->un_dircache = 0;
1c79356b 1496 un = VTOUNION(nvp);
2d21ac55
A
1497#if 0
1498 if ((alloced != 0) && (un->un_dircache != 0)) {
1499 union_unlock();
1500 for (vpp = newdircache; *vpp != NULLVP; vpp++)
1501 vnode_put(*vpp);
1502 _FREE(newdircache, M_TEMP);
1503 newdircache = NULL;
1504 union_lock();
1505 if (nvp != NULLVP)
1506 union_freevp(nvp);
1507 goto loop;
1508 }
1509#endif
1c79356b 1510 un->un_dircache = dircache;
2d21ac55
A
1511 un->un_flags |= UN_DIRENVN;
1512
1513 newdircache = NULL;
1514 union_unlock();
1515 return (nvp);
1c79356b
A
1516
1517out:
2d21ac55
A
1518 /*
1519 * If we allocated a new dircache and couldn't attach
1520 * it to a new vp, free the resources we allocated.
1521 */
1522 if (newdircache) {
1523 for (vpp = newdircache; *vpp != NULLVP; vpp++)
1524 vnode_put(*vpp);
1525 _FREE(newdircache, M_TEMP);
1526 }
1527 return (NULLVP);
1528}
1529
1530/*
1531 * Module glue to remove #ifdef UNION from vfs_syscalls.c
1532 */
1533/* Called with no union lock, the union_dircache takes locks when necessary */
1534static int
1535union_dircheck(struct vnode **vpp, struct fileproc *fp, vfs_context_t ctx)
1536{
1537 int error = 0;
1538 vnode_t vp = *vpp;
1539
1540 if (vp->v_op == union_vnodeop_p) {
1541 struct vnode *lvp;
1542
1543 lvp = union_dircache(vp, ctx);
1544 if (lvp != NULLVP) {
1545 struct vnode_attr va;
1546 /*
1547 * If the directory is opaque,
1548 * then don't show lower entries
1549 */
1550 VATTR_INIT(&va);
1551 VATTR_WANTED(&va, va_flags);
1552 error = vnode_getattr(vp, &va, ctx);
1553 if (va.va_flags & OPAQUE) {
1554 vnode_put(lvp);
1555 lvp = NULL;
1556 }
1557 }
1558
1559 if (lvp != NULLVP) {
1560#if CONFIG_MACF
1561 error = mac_vnode_check_open(ctx, lvp, FREAD);
1562 if (error) {
1563 vnode_put(lvp);
1564 return(error);
1565 }
1566#endif /* MAC */
1567 error = VNOP_OPEN(lvp, FREAD, ctx);
1568 if (error) {
1569 vnode_put(lvp);
1570 return(error);
1571 }
1572 vnode_ref(lvp);
1573 fp->f_fglob->fg_data = (caddr_t) lvp;
1574 fp->f_fglob->fg_offset = 0;
1575
1576 error = VNOP_CLOSE(vp, FREAD, ctx);
1577 vnode_rele(vp);
1578 vnode_put(vp);
1579 if (error)
1580 return(error);
1581
1582 *vpp = lvp;
1583 return -1; /* goto unionread */
1584 }
1585 }
1586 return error;
1c79356b 1587}
2d21ac55
A
1588
1589/* called from inactive with union lock held */
1590void
1591union_dircache_free(struct union_node *un)
1592{
1593 struct vnode **vpp;
1594
1595 vpp = un->un_dircache;
1596 un->un_dircache = NULL;
1597 union_unlock();
1598
1599 for (; *vpp != NULLVP; vpp++)
1600 vnode_put(*vpp);
1601 _FREE(un->un_dircache, M_TEMP);
1602 union_lock();
1603}
1604