1 /* $NetBSD: union_subr.c,v 1.34 2008/12/17 20:51:35 cegger Exp $ */
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#)union_subr.c 8.20 (Berkeley) 5/20/95
38 * Copyright (c) 1994 Jan-Simon Pendry
40 * This code is derived from software contributed to Berkeley by
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * @(#)union_subr.c 8.20 (Berkeley) 5/20/95
74 #include <sys/cdefs.h>
75 __KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.34 2008/12/17 20:51:35 cegger Exp $");
77 #include <sys/param.h>
78 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/vnode.h>
83 #include <sys/namei.h>
84 #include <sys/malloc.h>
86 #include <sys/filedesc.h>
87 #include <sys/queue.h>
88 #include <sys/mount.h>
90 #include <sys/kauth.h>
92 #include <uvm/uvm_extern.h>
94 #include <fs/union/union.h>
96 /* must be power of two, otherwise change UNION_HASH() */
99 /* unsigned int ... */
100 #define UNION_HASH(u, l) \
101 (((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1))
103 static LIST_HEAD(unhead
, union_node
) unhead
[NHASH
];
104 static int unvplock
[NHASH
];
106 static int union_list_lock(int);
107 static void union_list_unlock(int);
108 void union_updatevp(struct union_node
*, struct vnode
*, struct vnode
*);
109 static int union_relookup(struct union_mount
*, struct vnode
*,
110 struct vnode
**, struct componentname
*,
111 struct componentname
*, const char *, int);
112 int union_vn_close(struct vnode
*, int, kauth_cred_t
, struct lwp
*);
113 static void union_dircache_r(struct vnode
*, struct vnode
***, int *);
114 struct vnode
*union_dircache(struct vnode
*, struct lwp
*);
121 for (i
= 0; i
< NHASH
; i
++)
122 LIST_INIT(&unhead
[i
]);
123 memset(unvplock
, 0, sizeof(unvplock
));
127 * Free global unionfs resources.
133 /* Make sure to unset the readdir hook. */
134 vn_union_readdir_hook
= NULL
;
138 union_list_lock(int ix
)
141 if (unvplock
[ix
] & UN_LOCKED
) {
142 unvplock
[ix
] |= UN_WANTED
;
143 (void) tsleep(&unvplock
[ix
], PINOD
, "unionlk", 0);
147 unvplock
[ix
] |= UN_LOCKED
;
153 union_list_unlock(int ix
)
156 unvplock
[ix
] &= ~UN_LOCKED
;
158 if (unvplock
[ix
] & UN_WANTED
) {
159 unvplock
[ix
] &= ~UN_WANTED
;
160 wakeup(&unvplock
[ix
]);
165 union_updatevp(struct union_node
*un
, struct vnode
*uppervp
,
166 struct vnode
*lowervp
)
168 int ohash
= UNION_HASH(un
->un_uppervp
, un
->un_lowervp
);
169 int nhash
= UNION_HASH(uppervp
, lowervp
);
170 int docache
= (lowervp
!= NULLVP
|| uppervp
!= NULLVP
);
174 * Ensure locking is ordered from lower to higher
175 * to avoid deadlocks.
186 while (union_list_lock(lhash
))
189 while (union_list_lock(uhash
))
192 if (ohash
!= nhash
|| !docache
) {
193 if (un
->un_flags
& UN_CACHED
) {
194 un
->un_flags
&= ~UN_CACHED
;
195 LIST_REMOVE(un
, un_cache
);
200 union_list_unlock(ohash
);
202 if (un
->un_lowervp
!= lowervp
) {
203 if (un
->un_lowervp
) {
204 vrele(un
->un_lowervp
);
206 free(un
->un_path
, M_TEMP
);
211 un
->un_dirvp
= NULLVP
;
214 un
->un_lowervp
= lowervp
;
215 un
->un_lowersz
= VNOVAL
;
218 if (un
->un_uppervp
!= uppervp
) {
220 vrele(un
->un_uppervp
);
222 un
->un_uppervp
= uppervp
;
223 un
->un_uppersz
= VNOVAL
;
226 if (docache
&& (ohash
!= nhash
)) {
227 LIST_INSERT_HEAD(&unhead
[nhash
], un
, un_cache
);
228 un
->un_flags
|= UN_CACHED
;
231 union_list_unlock(nhash
);
235 union_newlower(struct union_node
*un
, struct vnode
*lowervp
)
238 union_updatevp(un
, un
->un_uppervp
, lowervp
);
242 union_newupper(struct union_node
*un
, struct vnode
*uppervp
)
245 union_updatevp(un
, uppervp
, un
->un_lowervp
);
249 * Keep track of size changes in the underlying vnodes.
250 * If the size changes, then callback to the vm layer
251 * giving priority to the upper layer size.
254 union_newsize(struct vnode
*vp
, off_t uppersz
, off_t lowersz
)
256 struct union_node
*un
;
259 /* only interested in regular files */
260 if (vp
->v_type
!= VREG
) {
261 uvm_vnp_setsize(vp
, 0);
268 if ((uppersz
!= VNOVAL
) && (un
->un_uppersz
!= uppersz
)) {
269 un
->un_uppersz
= uppersz
;
274 if ((lowersz
!= VNOVAL
) && (un
->un_lowersz
!= lowersz
)) {
275 un
->un_lowersz
= lowersz
;
281 #ifdef UNION_DIAGNOSTIC
282 printf("union: %s size now %qd\n",
283 uppersz
!= VNOVAL
? "upper" : "lower", sz
);
285 uvm_vnp_setsize(vp
, sz
);
290 * allocate a union_node/vnode pair. the vnode is
291 * referenced and locked. the new vnode is returned
292 * via (vpp). (mp) is the mountpoint of the union filesystem,
293 * (dvp) is the parent directory where the upper layer object
294 * should exist (but doesn't) and (cnp) is the componentname
295 * information which is partially copied to allow the upper
296 * layer object to be created at a later time. (uppervp)
297 * and (lowervp) reference the upper and lower layer objects
298 * being mapped. either, but not both, can be nil.
299 * if supplied, (uppervp) is locked.
300 * the reference is either maintained in the new union_node
301 * object which is allocated, or they are vrele'd.
303 * all union_nodes are maintained on a singly-linked
304 * list. new nodes are only allocated when they cannot
305 * be found on this list. entries on the list are
306 * removed when the vfs reclaim entry is called.
308 * a single lock is kept for the entire list. this is
309 * needed because the getnewvnode() function can block
310 * waiting for a vnode to become free, in which case there
311 * may be more than one process trying to get the same
312 * vnode. this lock is only taken if we are going to
313 * call getnewvnode, since the kernel itself is single-threaded.
315 * if an entry is found on the list, then call vget() to
316 * take a reference. this is done because there may be
317 * zero references to it and so it needs to removed from
318 * the vnode free list.
324 struct vnode
*undvp
, /* parent union vnode */
325 struct vnode
*dvp
, /* may be null */
326 struct componentname
*cnp
, /* may be null */
327 struct vnode
*uppervp
, /* may be null */
328 struct vnode
*lowervp
, /* may be null */
333 struct union_node
*un
= NULL
;
334 struct vnode
*xlowervp
= NULLVP
;
335 struct union_mount
*um
= MOUNTTOUNIONMOUNT(mp
);
336 voff_t uppersz
, lowersz
;
341 if (uppervp
== NULLVP
&& lowervp
== NULLVP
)
342 panic("union: unidentifiable allocation");
344 if (uppervp
&& lowervp
&& (uppervp
->v_type
!= lowervp
->v_type
)) {
349 /* detect the root vnode (and aliases) */
352 if ((uppervp
== um
->um_uppervp
) &&
353 ((lowervp
== NULLVP
) || lowervp
== um
->um_lowervp
)) {
354 if (lowervp
== NULLVP
) {
355 lowervp
= um
->um_lowervp
;
356 if (lowervp
!= NULLVP
)
366 } else for (try = 0; try < 3; try++) {
369 if (lowervp
== NULLVP
)
371 hash
= UNION_HASH(uppervp
, lowervp
);
375 if (uppervp
== NULLVP
)
377 hash
= UNION_HASH(uppervp
, NULLVP
);
381 if (lowervp
== NULLVP
)
383 hash
= UNION_HASH(NULLVP
, lowervp
);
387 while (union_list_lock(hash
))
390 for (un
= unhead
[hash
].lh_first
; un
!= 0;
391 un
= un
->un_cache
.le_next
) {
392 if ((un
->un_lowervp
== lowervp
||
393 un
->un_lowervp
== NULLVP
) &&
394 (un
->un_uppervp
== uppervp
||
395 un
->un_uppervp
== NULLVP
) &&
396 (UNIONTOV(un
)->v_mount
== mp
)) {
397 if (vget(UNIONTOV(un
), 0)) {
398 union_list_unlock(hash
);
405 union_list_unlock(hash
);
413 * Obtain a lock on the union_node.
414 * uppervp is locked, though un->un_uppervp
415 * may not be. this doesn't break the locking
416 * hierarchy since in the case that un->un_uppervp
417 * is not yet locked it will be vrele'd and replaced
421 if ((dvp
!= NULLVP
) && (uppervp
== dvp
)) {
423 * Access ``.'', so (un) will already
424 * be locked. Since this process has
425 * the lock on (uppervp) no other
426 * process can hold the lock on (un).
429 if ((un
->un_flags
& UN_LOCKED
) == 0)
430 panic("union: . not locked");
431 else if (curproc
&& un
->un_pid
!= curproc
->p_pid
&&
432 un
->un_pid
> -1 && curproc
->p_pid
> -1)
433 panic("union: allocvp not lock owner");
436 if (un
->un_flags
& UN_LOCKED
) {
438 un
->un_flags
|= UN_WANTED
;
439 (void) tsleep(&un
->un_flags
, PINOD
,
443 un
->un_flags
|= UN_LOCKED
;
447 un
->un_pid
= curproc
->p_pid
;
454 * At this point, the union_node is locked,
455 * un->un_uppervp may not be locked, and uppervp
460 * Save information about the upper layer.
462 if (uppervp
!= un
->un_uppervp
) {
463 union_newupper(un
, uppervp
);
464 } else if (uppervp
) {
468 if (un
->un_uppervp
) {
469 un
->un_flags
|= UN_ULOCK
;
470 un
->un_flags
&= ~UN_KLOCK
;
474 * Save information about the lower layer.
475 * This needs to keep track of pathname
476 * and directory information which union_vn_create
479 if (lowervp
!= un
->un_lowervp
) {
480 union_newlower(un
, lowervp
);
481 if (cnp
&& (lowervp
!= NULLVP
)) {
482 un
->un_hash
= cnp
->cn_hash
;
483 un
->un_path
= malloc(cnp
->cn_namelen
+1,
485 memcpy(un
->un_path
, cnp
->cn_nameptr
,
487 un
->un_path
[cnp
->cn_namelen
] = '\0';
491 } else if (lowervp
) {
498 uppersz
= lowersz
= VNOVAL
;
499 if (uppervp
!= NULLVP
)
500 if (VOP_GETATTR(uppervp
, &va
, FSCRED
) == 0)
501 uppersz
= va
.va_size
;
502 if (lowervp
!= NULLVP
)
503 if (VOP_GETATTR(lowervp
, &va
, FSCRED
) == 0)
504 lowersz
= va
.va_size
;
508 * otherwise lock the vp list while we call getnewvnode
509 * since that can block.
511 hash
= UNION_HASH(uppervp
, lowervp
);
513 if (union_list_lock(hash
))
517 error
= getnewvnode(VT_UNION
, mp
, union_vnodeop_p
, vpp
);
531 (*vpp
)->v_data
= malloc(sizeof(struct union_node
), M_TEMP
, M_WAITOK
);
533 (*vpp
)->v_vflag
|= vflag
;
534 (*vpp
)->v_iflag
|= iflag
;
535 (*vpp
)->v_vnlock
= NULL
; /* Make upper layers call VOP_LOCK */
537 (*vpp
)->v_type
= uppervp
->v_type
;
539 (*vpp
)->v_type
= lowervp
->v_type
;
542 un
->un_uppervp
= uppervp
;
543 un
->un_lowervp
= lowervp
;
549 un
->un_flags
= UN_LOCKED
;
551 un
->un_uppersz
= VNOVAL
;
552 un
->un_lowersz
= VNOVAL
;
553 union_newsize(*vpp
, uppersz
, lowersz
);
556 un
->un_flags
|= UN_ULOCK
;
559 un
->un_pid
= curproc
->p_pid
;
563 if (dvp
&& cnp
&& (lowervp
!= NULLVP
)) {
564 un
->un_hash
= cnp
->cn_hash
;
565 un
->un_path
= malloc(cnp
->cn_namelen
+1, M_TEMP
, M_WAITOK
);
566 memcpy(un
->un_path
, cnp
->cn_nameptr
, cnp
->cn_namelen
);
567 un
->un_path
[cnp
->cn_namelen
] = '\0';
577 LIST_INSERT_HEAD(&unhead
[hash
], un
, un_cache
);
578 un
->un_flags
|= UN_CACHED
;
586 union_list_unlock(hash
);
592 union_freevp(struct vnode
*vp
)
594 struct union_node
*un
= VTOUNION(vp
);
596 if (un
->un_flags
& UN_CACHED
) {
597 un
->un_flags
&= ~UN_CACHED
;
598 LIST_REMOVE(un
, un_cache
);
601 if (un
->un_pvp
!= NULLVP
)
603 if (un
->un_uppervp
!= NULLVP
)
604 vrele(un
->un_uppervp
);
605 if (un
->un_lowervp
!= NULLVP
)
606 vrele(un
->un_lowervp
);
607 if (un
->un_dirvp
!= NULLVP
)
610 free(un
->un_path
, M_TEMP
);
612 free(vp
->v_data
, M_TEMP
);
619 * copyfile. copy the vnode (fvp) to the vnode (tvp)
620 * using a sequence of reads and writes. both (fvp)
621 * and (tvp) are locked on entry and exit.
624 union_copyfile(struct vnode
*fvp
, struct vnode
*tvp
, kauth_cred_t cred
,
634 * allocate a buffer of size MAXBSIZE.
635 * loop doing reads and writes, keeping track
636 * of the current uio offset.
637 * give up at the first sign of trouble.
641 UIO_SETUP_SYSSPACE(&uio
);
643 VOP_UNLOCK(fvp
, 0); /* XXX */
644 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
); /* XXX */
645 VOP_UNLOCK(tvp
, 0); /* XXX */
646 vn_lock(tvp
, LK_EXCLUSIVE
| LK_RETRY
); /* XXX */
648 tbuf
= malloc(MAXBSIZE
, M_TEMP
, M_WAITOK
);
650 /* ugly loop follows... */
652 off_t offset
= uio
.uio_offset
;
657 iov
.iov_len
= MAXBSIZE
;
658 uio
.uio_resid
= iov
.iov_len
;
659 uio
.uio_rw
= UIO_READ
;
660 error
= VOP_READ(fvp
, &uio
, 0, cred
);
666 iov
.iov_len
= MAXBSIZE
- uio
.uio_resid
;
667 uio
.uio_offset
= offset
;
668 uio
.uio_rw
= UIO_WRITE
;
669 uio
.uio_resid
= iov
.iov_len
;
671 if (uio
.uio_resid
== 0)
675 error
= VOP_WRITE(tvp
, &uio
, 0, cred
);
676 } while ((uio
.uio_resid
> 0) && (error
== 0));
679 } while (error
== 0);
686 * (un) is assumed to be locked on entry and remains
690 union_copyup(struct union_node
*un
, int docopy
, kauth_cred_t cred
,
694 struct vnode
*lvp
, *uvp
;
695 struct vattr lvattr
, uvattr
;
697 error
= union_vn_create(&uvp
, un
, l
);
701 /* at this point, uppervp is locked */
702 union_newupper(un
, uvp
);
703 un
->un_flags
|= UN_ULOCK
;
705 lvp
= un
->un_lowervp
;
709 * XX - should not ignore errors
712 vn_lock(lvp
, LK_EXCLUSIVE
| LK_RETRY
);
714 error
= VOP_GETATTR(lvp
, &lvattr
, cred
);
716 error
= VOP_OPEN(lvp
, FREAD
, cred
);
718 error
= union_copyfile(lvp
, uvp
, cred
, l
);
719 (void) VOP_CLOSE(lvp
, FREAD
, cred
);
722 /* Copy permissions up too */
724 uvattr
.va_mode
= lvattr
.va_mode
;
725 uvattr
.va_flags
= lvattr
.va_flags
;
726 error
= VOP_SETATTR(uvp
, &uvattr
, cred
);
729 #ifdef UNION_DIAGNOSTIC
731 uprintf("union: copied up %s\n", un
->un_path
);
735 union_vn_close(uvp
, FWRITE
, cred
, l
);
738 * Subsequent IOs will go to the top layer, so
739 * call close on the lower vnode and open on the
740 * upper vnode to ensure that the filesystem keeps
741 * its references counts right. This doesn't do
742 * the right thing with (cred) and (FREAD) though.
743 * Ignoring error returns is not right, either.
748 vn_lock(lvp
, LK_EXCLUSIVE
| LK_RETRY
);
749 for (i
= 0; i
< un
->un_openl
; i
++) {
750 (void) VOP_CLOSE(lvp
, FREAD
, cred
);
751 (void) VOP_OPEN(uvp
, FREAD
, cred
);
763 struct union_mount
*um
,
766 struct componentname
*cnp
,
767 struct componentname
*cn
,
774 * A new componentname structure must be faked up because
775 * there is no way to know where the upper level cnp came
776 * from or what it is being used for. This must duplicate
777 * some of the work done by NDINIT, some of the work done
778 * by namei, some of the work done by lookup and some of
779 * the work done by VOP_LOOKUP when given a CREATE flag.
780 * Conclusion: Horrible.
782 * The pathname buffer will be PNBUF_PUT'd by VOP_MKDIR.
784 cn
->cn_namelen
= pathlen
;
785 if ((cn
->cn_namelen
+ 1) > MAXPATHLEN
)
786 return (ENAMETOOLONG
);
787 cn
->cn_pnbuf
= PNBUF_GET();
788 memcpy(cn
->cn_pnbuf
, path
, cn
->cn_namelen
);
789 cn
->cn_pnbuf
[cn
->cn_namelen
] = '\0';
791 cn
->cn_nameiop
= CREATE
;
792 cn
->cn_flags
= (LOCKPARENT
|HASBUF
|SAVENAME
|ISLASTCN
);
793 if (um
->um_op
== UNMNT_ABOVE
)
794 cn
->cn_cred
= cnp
->cn_cred
;
796 cn
->cn_cred
= um
->um_cred
;
797 cn
->cn_nameptr
= cn
->cn_pnbuf
;
798 cn
->cn_hash
= cnp
->cn_hash
;
799 cn
->cn_consume
= cnp
->cn_consume
;
801 error
= relookup(dvp
, vpp
, cn
);
803 PNBUF_PUT(cn
->cn_pnbuf
);
811 * Create a shadow directory in the upper layer.
812 * The new vnode is returned locked.
814 * (um) points to the union mount structure for access to the
815 * the mounting process's credentials.
816 * (dvp) is the directory in which to create the shadow directory.
817 * it is unlocked on entry and exit.
818 * (cnp) is the componentname to be created.
819 * (vpp) is the returned newly created shadow directory, which
820 * is returned locked.
822 * N.B. We still attempt to create shadow directories even if the union
823 * is mounted read-only, which is a little nonintuitive.
826 union_mkshadow(struct union_mount
*um
, struct vnode
*dvp
,
827 struct componentname
*cnp
, struct vnode
**vpp
)
831 struct componentname cn
;
833 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
834 error
= union_relookup(um
, dvp
, vpp
, cnp
, &cn
,
835 cnp
->cn_nameptr
, cnp
->cn_namelen
);
842 VOP_ABORTOP(dvp
, &cn
);
851 * policy: when creating the shadow directory in the
852 * upper layer, create it owned by the user who did
853 * the mount, group from parent directory, and mode
854 * 777 modified by umask (ie mostly identical to the
855 * mkdir syscall). (jsp, kb)
860 va
.va_mode
= um
->um_cmode
;
863 error
= VOP_MKDIR(dvp
, vpp
, &cn
, &va
);
868 * Create a whiteout entry in the upper layer.
870 * (um) points to the union mount structure for access to the
871 * the mounting process's credentials.
872 * (dvp) is the directory in which to create the whiteout.
873 * it is locked on entry and exit.
874 * (cnp) is the componentname to be created.
877 union_mkwhiteout(struct union_mount
*um
, struct vnode
*dvp
,
878 struct componentname
*cnp
, char *path
)
882 struct componentname cn
;
885 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
886 error
= union_relookup(um
, dvp
, &wvp
, cnp
, &cn
, path
, strlen(path
));
891 VOP_ABORTOP(dvp
, &cn
);
898 error
= VOP_WHITEOUT(dvp
, &cn
, CREATE
);
900 VOP_ABORTOP(dvp
, &cn
);
906 * union_vn_create: creates and opens a new shadow file
907 * on the upper union layer. this function is similar
908 * in spirit to calling vn_open but it avoids calling namei().
909 * the problem with calling namei is that a) it locks too many
910 * things, and b) it doesn't start at the "right" directory,
911 * whereas relookup is told where to start.
914 union_vn_create(struct vnode
**vpp
, struct union_node
*un
, struct lwp
*l
)
917 kauth_cred_t cred
= l
->l_cred
;
919 struct vattr
*vap
= &vat
;
920 int fmode
= FFLAGS(O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
);
922 int cmode
= UN_FILEMODE
& ~l
->l_proc
->p_cwdi
->cwdi_cmask
;
923 struct componentname cn
;
928 * Build a new componentname structure (for the same
929 * reasons outlines in union_mkshadow).
930 * The difference here is that the file is owned by
931 * the current user, rather than by the person who
932 * did the mount, since the current user needs to be
933 * able to write the file (that's why it is being
934 * copied in the first place).
936 cn
.cn_namelen
= strlen(un
->un_path
);
937 if ((cn
.cn_namelen
+ 1) > MAXPATHLEN
)
938 return (ENAMETOOLONG
);
939 cn
.cn_pnbuf
= PNBUF_GET();
940 memcpy(cn
.cn_pnbuf
, un
->un_path
, cn
.cn_namelen
+1);
941 cn
.cn_nameiop
= CREATE
;
942 cn
.cn_flags
= (LOCKPARENT
|HASBUF
|SAVENAME
|ISLASTCN
);
943 cn
.cn_cred
= l
->l_cred
;
944 cn
.cn_nameptr
= cn
.cn_pnbuf
;
945 cn
.cn_hash
= un
->un_hash
;
948 vn_lock(un
->un_dirvp
, LK_EXCLUSIVE
| LK_RETRY
);
949 error
= relookup(un
->un_dirvp
, &vp
, &cn
);
951 VOP_UNLOCK(un
->un_dirvp
, 0);
956 VOP_ABORTOP(un
->un_dirvp
, &cn
);
957 if (un
->un_dirvp
!= vp
)
958 VOP_UNLOCK(un
->un_dirvp
, 0);
964 * Good - there was no race to create the file
965 * so go ahead and create it. The permissions
966 * on the file will be 0666 modified by the
967 * current user's umask. Access to the file, while
968 * it is unioned, will require access to the top *and*
969 * bottom files. Access when not unioned will simply
970 * require access to the top-level file.
971 * TODO: confirm choice of access permissions.
975 vap
->va_mode
= cmode
;
977 if ((error
= VOP_CREATE(un
->un_dirvp
, &vp
, &cn
, vap
)) != 0)
980 if ((error
= VOP_OPEN(vp
, fmode
, cred
)) != 0) {
991 union_vn_close(struct vnode
*vp
, int fmode
, kauth_cred_t cred
, struct lwp
*l
)
996 return (VOP_CLOSE(vp
, fmode
, cred
));
1000 union_removed_upper(struct union_node
*un
)
1004 * We do not set the uppervp to NULLVP here, because lowervp
1005 * may also be NULLVP, so this routine would end up creating
1006 * a bogus union node with no upper or lower VP (that causes
1007 * pain in many places that assume at least one VP exists).
1008 * Since we've removed this node from the cache hash chains,
1009 * it won't be found again. When all current holders
1010 * release it, union_inactive() will vgone() it.
1012 union_diruncache(un
);
1014 union_newupper(un
, NULLVP
);
1017 if (un
->un_flags
& UN_CACHED
) {
1018 un
->un_flags
&= ~UN_CACHED
;
1019 LIST_REMOVE(un
, un_cache
);
1022 if (un
->un_flags
& UN_ULOCK
) {
1023 un
->un_flags
&= ~UN_ULOCK
;
1024 VOP_UNLOCK(un
->un_uppervp
, 0);
1030 union_lowervp(struct vnode
*vp
)
1032 struct union_node
*un
= VTOUNION(vp
);
1034 if ((un
->un_lowervp
!= NULLVP
) &&
1035 (vp
->v_type
== un
->un_lowervp
->v_type
)) {
1036 if (vget(un
->un_lowervp
, 0) == 0)
1037 return (un
->un_lowervp
);
1045 * determine whether a whiteout is needed
1046 * during a remove/rmdir operation.
1049 union_dowhiteout(struct union_node
*un
, kauth_cred_t cred
)
1053 if (un
->un_lowervp
!= NULLVP
)
1056 if (VOP_GETATTR(un
->un_uppervp
, &va
, cred
) == 0 &&
1057 (va
.va_flags
& OPAQUE
))
1064 union_dircache_r(struct vnode
*vp
, struct vnode
***vppp
, int *cntp
)
1066 struct union_node
*un
;
1068 if (vp
->v_op
!= union_vnodeop_p
) {
1073 panic("union: dircache table too small");
1082 if (un
->un_uppervp
!= NULLVP
)
1083 union_dircache_r(un
->un_uppervp
, vppp
, cntp
);
1084 if (un
->un_lowervp
!= NULLVP
)
1085 union_dircache_r(un
->un_lowervp
, vppp
, cntp
);
1089 union_dircache(struct vnode
*vp
, struct lwp
*l
)
1092 struct vnode
*nvp
= NULLVP
;
1094 struct vnode
**dircache
;
1097 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
1098 dircache
= VTOUNION(vp
)->un_dircache
;
1102 if (dircache
== 0) {
1104 union_dircache_r(vp
, 0, &cnt
);
1106 dircache
= (struct vnode
**)
1107 malloc(cnt
* sizeof(struct vnode
*),
1110 union_dircache_r(vp
, &vpp
, &cnt
);
1111 VTOUNION(vp
)->un_dircache
= dircache
;
1117 if (*vpp
++ == VTOUNION(vp
)->un_uppervp
)
1119 } while (*vpp
!= NULLVP
);
1125 vn_lock(*vpp
, LK_EXCLUSIVE
| LK_RETRY
);
1127 error
= union_allocvp(&nvp
, vp
->v_mount
, NULLVP
, NULLVP
, 0, *vpp
, NULLVP
, 0);
1129 VTOUNION(vp
)->un_dircache
= 0;
1130 VTOUNION(nvp
)->un_dircache
= dircache
;
1139 union_diruncache(struct union_node
*un
)
1143 if (un
->un_dircache
!= 0) {
1144 for (vpp
= un
->un_dircache
; *vpp
!= NULLVP
; vpp
++)
1146 free(un
->un_dircache
, M_TEMP
);
1147 un
->un_dircache
= 0;
1152 * This hook is called from vn_readdir() to switch to lower directory
1153 * entry after the upper directory is read.
1156 union_readdirhook(struct vnode
**vpp
, struct file
*fp
, struct lwp
*l
)
1158 struct vnode
*vp
= *vpp
, *lvp
;
1162 if (vp
->v_op
!= union_vnodeop_p
)
1165 if ((lvp
= union_dircache(vp
, l
)) == NULLVP
)
1169 * If the directory is opaque,
1170 * then don't show lower entries
1172 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
);
1173 if (error
|| (va
.va_flags
& OPAQUE
)) {
1178 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
);
1186 error
= vn_close(vp
, FREAD
, fp
->f_cred
);