2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
28 * Copyright (c) 1992, 1993, 1994, 1995
29 * The Regents of the University of California. All rights reserved.
31 * This code is derived from software contributed to Berkeley by
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95
65 #include <sys/param.h>
66 #include <sys/systm.h>
71 #include <sys/types.h>
72 #include <sys/vnode.h>
73 #include <sys/mount.h>
74 #include <sys/namei.h>
75 #include <sys/malloc.h>
77 #include <sys/queue.h>
79 #include <miscfs/union/union.h>
80 #include <vfs/vfs_support.h>
83 #define FIXUP(un, p) { \
84 if (((un)->un_flags & UN_ULOCK) == 0) { \
91 struct union_node
*un
;
95 vn_lock(un
->un_uppervp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
96 un
->un_flags
|= UN_ULOCK
;
100 union_lookup1(udvp
, dvpp
, vpp
, cnp
)
104 struct componentname
*cnp
;
107 struct proc
*p
= cnp
->cn_proc
;
115 * If stepping up the directory tree, check for going
116 * back across the mount point, in which case do what
117 * lookup would do by stepping back down the mount
120 if (cnp
->cn_flags
& ISDOTDOT
) {
121 while ((dvp
!= udvp
) && (dvp
->v_flag
& VROOT
)) {
123 * Don't do the NOCROSSMOUNT check
124 * at this level. By definition,
125 * union fs deals with namespaces, not
129 *dvpp
= dvp
= dvp
->v_mount
->mnt_vnodecovered
;
132 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
136 error
= VOP_LOOKUP(dvp
, &tdvp
, cnp
);
141 * The parent directory will have been unlocked, unless lookup
142 * found the last component. In which case, re-lock the node
143 * here to allow it to be unlocked again (phew) in union_lookup.
145 if (dvp
!= tdvp
&& !(cnp
->cn_flags
& ISLASTCN
))
146 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
151 * Lastly check if the current node is a mount point in
152 * which case walk up the mount hierarchy making sure not to
153 * bump into the root of the mount tree (ie. dvp != udvp).
155 while (dvp
!= udvp
&& (dvp
->v_type
== VDIR
) &&
156 (mp
= dvp
->v_mountedhere
)) {
157 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
161 error
= VFS_ROOT(mp
, &tdvp
);
178 struct vop_lookup_args
/* {
179 struct vnodeop_desc *a_desc;
181 struct vnode **a_vpp;
182 struct componentname *a_cnp;
187 struct vnode
*uppervp
, *lowervp
;
188 struct vnode
*upperdvp
, *lowerdvp
;
189 struct vnode
*dvp
= ap
->a_dvp
;
190 struct union_node
*dun
= VTOUNION(dvp
);
191 struct componentname
*cnp
= ap
->a_cnp
;
192 struct proc
*p
= cnp
->cn_proc
;
193 int lockparent
= cnp
->cn_flags
& LOCKPARENT
;
194 int rdonly
= cnp
->cn_flags
& RDONLY
;
195 struct union_mount
*um
= MOUNTTOUNIONMOUNT(dvp
->v_mount
);
196 struct ucred
*saved_cred
;
201 if (cnp
->cn_namelen
== 3 &&
202 cnp
->cn_nameptr
[2] == '.' &&
203 cnp
->cn_nameptr
[1] == '.' &&
204 cnp
->cn_nameptr
[0] == '.') {
205 dvp
= *ap
->a_vpp
= LOWERVP(ap
->a_dvp
);
209 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
210 if (!lockparent
|| !(cnp
->cn_flags
& ISLASTCN
))
211 VOP_UNLOCK(ap
->a_dvp
, 0, p
);
216 cnp
->cn_flags
|= LOCKPARENT
;
218 upperdvp
= dun
->un_uppervp
;
219 lowerdvp
= dun
->un_lowervp
;
225 * do the lookup in the upper level.
226 * if that level comsumes additional pathnames,
227 * then assume that something special is going
228 * on and just return that vnode.
230 if (upperdvp
!= NULLVP
) {
232 uerror
= union_lookup1(um
->um_uppervp
, &upperdvp
,
234 /*if (uppervp == upperdvp)
235 dun->un_flags |= UN_KLOCK;*/
237 if (cnp
->cn_consume
!= 0) {
238 *ap
->a_vpp
= uppervp
;
240 cnp
->cn_flags
&= ~LOCKPARENT
;
243 if (uerror
== ENOENT
|| uerror
== EJUSTRETURN
) {
244 if (cnp
->cn_flags
& ISWHITEOUT
) {
246 } else if (lowerdvp
!= NULLVP
) {
247 lerror
= VOP_GETATTR(upperdvp
, &va
,
248 cnp
->cn_cred
, cnp
->cn_proc
);
249 if (lerror
== 0 && (va
.va_flags
& OPAQUE
))
258 * in a similar way to the upper layer, do the lookup
259 * in the lower layer. this time, if there is some
260 * component magic going on, then vput whatever we got
261 * back from the upper layer and return the lower vnode
264 if (lowerdvp
!= NULLVP
&& !iswhiteout
) {
267 vn_lock(lowerdvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
270 * Only do a LOOKUP on the bottom node, since
271 * we won't be making changes to it anyway.
273 nameiop
= cnp
->cn_nameiop
;
274 cnp
->cn_nameiop
= LOOKUP
;
275 if (um
->um_op
== UNMNT_BELOW
) {
276 saved_cred
= cnp
->cn_cred
;
277 cnp
->cn_cred
= um
->um_cred
;
279 lerror
= union_lookup1(um
->um_lowervp
, &lowerdvp
,
281 if (um
->um_op
== UNMNT_BELOW
)
282 cnp
->cn_cred
= saved_cred
;
283 cnp
->cn_nameiop
= nameiop
;
285 if (lowervp
!= lowerdvp
)
286 VOP_UNLOCK(lowerdvp
, 0, p
);
288 if (cnp
->cn_consume
!= 0) {
289 if (uppervp
!= NULLVP
) {
290 if (uppervp
== upperdvp
)
296 *ap
->a_vpp
= lowervp
;
298 cnp
->cn_flags
&= ~LOCKPARENT
;
303 if ((cnp
->cn_flags
& ISDOTDOT
) && dun
->un_pvp
!= NULLVP
) {
304 lowervp
= LOWERVP(dun
->un_pvp
);
305 if (lowervp
!= NULLVP
) {
307 vn_lock(lowervp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
314 cnp
->cn_flags
&= ~LOCKPARENT
;
317 * at this point, we have uerror and lerror indicating
318 * possible errors with the lookups in the upper and lower
319 * layers. additionally, uppervp and lowervp are (locked)
320 * references to existing vnodes in the upper and lower layers.
322 * there are now three cases to consider.
323 * 1. if both layers returned an error, then return whatever
324 * error the upper layer generated.
326 * 2. if the top layer failed and the bottom layer succeeded
327 * then two subcases occur.
328 * a. the bottom vnode is not a directory, in which
329 * case just return a new union vnode referencing
330 * an empty top layer and the existing bottom layer.
331 * b. the bottom vnode is a directory, in which case
332 * create a new directory in the top-level and
333 * continue as in case 3.
335 * 3. if the top layer succeeded then return a new union
336 * vnode referencing whatever the new top layer and
337 * whatever the bottom layer returned.
343 if ((uerror
!= 0) && (lerror
!= 0)) {
348 if (uerror
!= 0 /* && (lerror == 0) */ ) {
349 if (lowervp
->v_type
== VDIR
) { /* case 2b. */
350 dun
->un_flags
&= ~UN_ULOCK
;
351 VOP_UNLOCK(upperdvp
, 0, p
);
352 uerror
= union_mkshadow(um
, upperdvp
, cnp
, &uppervp
);
353 vn_lock(upperdvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
354 dun
->un_flags
|= UN_ULOCK
;
357 if (lowervp
!= NULLVP
) {
366 if (lowervp
!= NULLVP
)
367 VOP_UNLOCK(lowervp
, 0, p
);
369 error
= union_allocvp(ap
->a_vpp
, dvp
->v_mount
, dvp
, upperdvp
, cnp
,
370 uppervp
, lowervp
, 1);
373 if (uppervp
!= NULLVP
)
375 if (lowervp
!= NULLVP
)
378 if (*ap
->a_vpp
!= dvp
)
379 if (!lockparent
|| !(cnp
->cn_flags
& ISLASTCN
))
380 VOP_UNLOCK(dvp
, 0, p
);
388 struct vop_create_args
/* {
390 struct vnode **a_vpp;
391 struct componentname *a_cnp;
395 struct union_node
*un
= VTOUNION(ap
->a_dvp
);
396 struct vnode
*dvp
= un
->un_uppervp
;
397 struct componentname
*cnp
= ap
->a_cnp
;
398 struct proc
*p
= cnp
->cn_proc
;
408 un
->un_flags
|= UN_KLOCK
;
409 mp
= ap
->a_dvp
->v_mount
;
411 error
= VOP_CREATE(dvp
, &vp
, cnp
, ap
->a_vap
);
415 error
= union_allocvp(ap
->a_vpp
, mp
, NULLVP
, NULLVP
, cnp
, vp
,
428 struct vop_whiteout_args
/* {
430 struct componentname *a_cnp;
434 struct union_node
*un
= VTOUNION(ap
->a_dvp
);
435 struct componentname
*cnp
= ap
->a_cnp
;
436 struct proc
*p
= cnp
->cn_proc
;
438 if (un
->un_uppervp
== NULLVP
)
442 return (VOP_WHITEOUT(un
->un_uppervp
, cnp
, ap
->a_flags
));
447 struct vop_mknod_args
/* {
449 struct vnode **a_vpp;
450 struct componentname *a_cnp;
454 struct union_node
*un
= VTOUNION(ap
->a_dvp
);
455 struct vnode
*dvp
= un
->un_uppervp
;
456 struct componentname
*cnp
= ap
->a_cnp
;
457 struct proc
*p
= cnp
->cn_proc
;
467 un
->un_flags
|= UN_KLOCK
;
468 mp
= ap
->a_dvp
->v_mount
;
470 error
= VOP_MKNOD(dvp
, &vp
, cnp
, ap
->a_vap
);
475 error
= union_allocvp(ap
->a_vpp
, mp
, NULLVP
, NULLVP
,
489 struct vop_open_args
/* {
490 struct vnodeop_desc *a_desc;
493 struct ucred *a_cred;
497 struct union_node
*un
= VTOUNION(ap
->a_vp
);
499 int mode
= ap
->a_mode
;
500 struct ucred
*cred
= ap
->a_cred
;
501 struct proc
*p
= ap
->a_p
;
505 * If there is an existing upper vp then simply open that.
507 tvp
= un
->un_uppervp
;
510 * If the lower vnode is being opened for writing, then
511 * copy the file contents to the upper vnode and open that,
512 * otherwise can simply open the lower vnode.
514 tvp
= un
->un_lowervp
;
515 if ((ap
->a_mode
& FWRITE
) && (tvp
->v_type
== VREG
)) {
516 error
= union_copyup(un
, (mode
&O_TRUNC
) == 0, cred
, p
);
518 error
= VOP_OPEN(un
->un_uppervp
, mode
, cred
, p
);
523 * Just open the lower vnode
526 vn_lock(tvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
527 error
= VOP_OPEN(tvp
, mode
, cred
, p
);
528 VOP_UNLOCK(tvp
, 0, p
);
535 error
= VOP_OPEN(tvp
, mode
, cred
, p
);
542 struct vop_close_args
/* {
545 struct ucred *a_cred;
549 struct union_node
*un
= VTOUNION(ap
->a_vp
);
552 if ((vp
= un
->un_uppervp
) == NULLVP
) {
553 #ifdef UNION_DIAGNOSTIC
554 if (un
->un_openl
<= 0)
555 panic("union: un_openl cnt");
562 return (VCALL(vp
, VOFFSET(vop_close
), ap
));
566 * Check access permission on the union vnode.
567 * The access check being enforced is to check
568 * against both the underlying vnode, and any
569 * copied vnode. This ensures that no additional
570 * file permissions are given away simply because
571 * the user caused an implicit file copy.
575 struct vop_access_args
/* {
576 struct vnodeop_desc *a_desc;
579 struct ucred *a_cred;
583 struct union_node
*un
= VTOUNION(ap
->a_vp
);
584 struct proc
*p
= ap
->a_p
;
588 if ((vp
= un
->un_uppervp
) != NULLVP
) {
591 return (VCALL(vp
, VOFFSET(vop_access
), ap
));
594 if ((vp
= un
->un_lowervp
) != NULLVP
) {
595 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
597 error
= VCALL(vp
, VOFFSET(vop_access
), ap
);
599 struct union_mount
*um
= MOUNTTOUNIONMOUNT(vp
->v_mount
);
601 if (um
->um_op
== UNMNT_BELOW
) {
602 ap
->a_cred
= um
->um_cred
;
603 error
= VCALL(vp
, VOFFSET(vop_access
), ap
);
606 VOP_UNLOCK(vp
, 0, p
);
615 * We handle getattr only to change the fsid and
620 struct vop_getattr_args
/* {
623 struct ucred *a_cred;
628 struct union_node
*un
= VTOUNION(ap
->a_vp
);
629 struct vnode
*vp
= un
->un_uppervp
;
630 struct proc
*p
= ap
->a_p
;
636 * Some programs walk the filesystem hierarchy by counting
637 * links to directories to avoid stat'ing all the time.
638 * This means the link count on directories needs to be "correct".
639 * The only way to do that is to call getattr on both layers
640 * and fix up the link count. The link count will not necessarily
641 * be accurate but will be large enough to defeat the tree walkers.
649 * It's not clear whether VOP_GETATTR is to be
650 * called with the vnode locked or not. stat() calls
651 * it with (vp) locked, and fstat calls it with
653 * In the mean time, compensate here by checking
654 * the union_node's lock flag.
656 if (un
->un_flags
& UN_LOCKED
)
659 error
= VOP_GETATTR(vp
, vap
, ap
->a_cred
, ap
->a_p
);
662 union_newsize(ap
->a_vp
, vap
->va_size
, VNOVAL
);
667 } else if (vp
->v_type
== VDIR
) {
675 error
= VOP_GETATTR(vp
, vap
, ap
->a_cred
, ap
->a_p
);
678 union_newsize(ap
->a_vp
, VNOVAL
, vap
->va_size
);
681 if ((vap
!= ap
->a_vap
) && (vap
->va_type
== VDIR
))
682 ap
->a_vap
->va_nlink
+= vap
->va_nlink
;
684 ap
->a_vap
->va_fsid
= ap
->a_vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
690 struct vop_setattr_args
/* {
693 struct ucred *a_cred;
697 struct union_node
*un
= VTOUNION(ap
->a_vp
);
698 struct proc
*p
= ap
->a_p
;
702 * Handle case of truncating lower object to zero size,
703 * by creating a zero length upper object. This is to
704 * handle the case of open with O_TRUNC and O_CREAT.
706 if ((un
->un_uppervp
== NULLVP
) &&
707 /* assert(un->un_lowervp != NULLVP) */
708 (un
->un_lowervp
->v_type
== VREG
)) {
709 error
= union_copyup(un
, (ap
->a_vap
->va_size
!= 0),
710 ap
->a_cred
, ap
->a_p
);
716 * Try to set attributes in upper layer,
717 * otherwise return read-only filesystem error.
719 if (un
->un_uppervp
!= NULLVP
) {
721 error
= VOP_SETATTR(un
->un_uppervp
, ap
->a_vap
,
722 ap
->a_cred
, ap
->a_p
);
723 if ((error
== 0) && (ap
->a_vap
->va_size
!= VNOVAL
))
724 union_newsize(ap
->a_vp
, ap
->a_vap
->va_size
, VNOVAL
);
734 struct vop_read_args
/* {
738 struct ucred *a_cred;
742 struct proc
*p
= ap
->a_uio
->uio_procp
;
743 struct vnode
*vp
= OTHERVP(ap
->a_vp
);
744 int dolock
= (vp
== LOWERVP(ap
->a_vp
));
747 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
749 FIXUP(VTOUNION(ap
->a_vp
), p
);
750 error
= VOP_READ(vp
, ap
->a_uio
, ap
->a_ioflag
, ap
->a_cred
);
752 VOP_UNLOCK(vp
, 0, p
);
756 * perhaps the size of the underlying object has changed under
757 * our feet. take advantage of the offset information present
758 * in the uio structure.
761 struct union_node
*un
= VTOUNION(ap
->a_vp
);
762 off_t cur
= ap
->a_uio
->uio_offset
;
764 if (vp
== un
->un_uppervp
) {
765 if (cur
> un
->un_uppersz
)
766 union_newsize(ap
->a_vp
, cur
, VNOVAL
);
768 if (cur
> un
->un_lowersz
)
769 union_newsize(ap
->a_vp
, VNOVAL
, cur
);
778 struct vop_read_args
/* {
782 struct ucred *a_cred;
787 struct union_node
*un
= VTOUNION(ap
->a_vp
);
788 struct proc
*p
= ap
->a_uio
->uio_procp
;
790 vp
= UPPERVP(ap
->a_vp
);
792 panic("union: missing upper layer in write");
795 error
= VOP_WRITE(vp
, ap
->a_uio
, ap
->a_ioflag
, ap
->a_cred
);
798 * the size of the underlying object may be changed by the
802 off_t cur
= ap
->a_uio
->uio_offset
;
804 if (cur
> un
->un_uppersz
)
805 union_newsize(ap
->a_vp
, cur
, VNOVAL
);
812 struct vop_lease_args
/* {
815 struct ucred *a_cred;
819 register struct vnode
*ovp
= OTHERVP(ap
->a_vp
);
822 return (VCALL(ovp
, VOFFSET(vop_lease
), ap
));
827 struct vop_ioctl_args
/* {
832 struct ucred *a_cred;
836 register struct vnode
*ovp
= OTHERVP(ap
->a_vp
);
839 return (VCALL(ovp
, VOFFSET(vop_ioctl
), ap
));
844 struct vop_select_args
/* {
848 struct ucred *a_cred;
853 register struct vnode
*ovp
= OTHERVP(ap
->a_vp
);
856 return (VCALL(ovp
, VOFFSET(vop_select
), ap
));
861 struct vop_revoke_args
/* {
867 struct vnode
*vp
= ap
->a_vp
;
870 VOP_REVOKE(UPPERVP(vp
), ap
->a_flags
);
872 VOP_REVOKE(LOWERVP(vp
), ap
->a_flags
);
878 struct vop_mmap_args
/* {
881 struct ucred *a_cred;
885 register struct vnode
*ovp
= OTHERVP(ap
->a_vp
);
888 return (VCALL(ovp
, VOFFSET(vop_mmap
), ap
));
893 struct vop_fsync_args
/* {
895 struct ucred *a_cred;
901 struct proc
*p
= ap
->a_p
;
902 struct vnode
*targetvp
= OTHERVP(ap
->a_vp
);
904 if (targetvp
!= NULLVP
) {
905 int dolock
= (targetvp
== LOWERVP(ap
->a_vp
));
908 vn_lock(targetvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
910 FIXUP(VTOUNION(ap
->a_vp
), p
);
911 error
= VOP_FSYNC(targetvp
, ap
->a_cred
, ap
->a_waitfor
, p
);
913 VOP_UNLOCK(targetvp
, 0, p
);
921 struct vop_seek_args
/* {
925 struct ucred *a_cred;
928 register struct vnode
*ovp
= OTHERVP(ap
->a_vp
);
931 return (VCALL(ovp
, VOFFSET(vop_seek
), ap
));
936 struct vop_remove_args
/* {
939 struct componentname *a_cnp;
943 struct union_node
*dun
= VTOUNION(ap
->a_dvp
);
944 struct union_node
*un
= VTOUNION(ap
->a_vp
);
945 struct componentname
*cnp
= ap
->a_cnp
;
946 struct proc
*p
= cnp
->cn_proc
;
948 if (dun
->un_uppervp
== NULLVP
)
949 panic("union remove: null upper vnode");
951 if (un
->un_uppervp
!= NULLVP
) {
952 struct vnode
*dvp
= dun
->un_uppervp
;
953 struct vnode
*vp
= un
->un_uppervp
;
957 dun
->un_flags
|= UN_KLOCK
;
961 un
->un_flags
|= UN_KLOCK
;
964 if (union_dowhiteout(un
, cnp
->cn_cred
, cnp
->cn_proc
))
965 cnp
->cn_flags
|= DOWHITEOUT
;
966 error
= VOP_REMOVE(dvp
, vp
, cnp
);
968 union_removed_upper(un
);
971 error
= union_mkwhiteout(
972 MOUNTTOUNIONMOUNT(UNIONTOV(dun
)->v_mount
),
973 dun
->un_uppervp
, ap
->a_cnp
, un
->un_path
);
983 struct vop_link_args
/* {
985 struct vnode *a_tdvp;
986 struct componentname *a_cnp;
990 struct componentname
*cnp
= ap
->a_cnp
;
991 struct proc
*p
= cnp
->cn_proc
;
992 struct union_node
*un
;
996 un
= VTOUNION(ap
->a_tdvp
);
998 if (ap
->a_tdvp
->v_op
!= ap
->a_vp
->v_op
) {
1001 struct union_node
*tun
= VTOUNION(ap
->a_vp
);
1002 if (tun
->un_uppervp
== NULLVP
) {
1003 vn_lock(ap
->a_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1004 if (un
->un_uppervp
== tun
->un_dirvp
) {
1005 un
->un_flags
&= ~UN_ULOCK
;
1006 VOP_UNLOCK(un
->un_uppervp
, 0, p
);
1008 error
= union_copyup(tun
, 1, cnp
->cn_cred
, p
);
1009 if (un
->un_uppervp
== tun
->un_dirvp
) {
1010 vn_lock(un
->un_uppervp
,
1011 LK_EXCLUSIVE
| LK_RETRY
, p
);
1012 un
->un_flags
|= UN_ULOCK
;
1014 VOP_UNLOCK(ap
->a_vp
, 0, p
);
1016 vp
= tun
->un_uppervp
;
1019 tdvp
= un
->un_uppervp
;
1030 un
->un_flags
|= UN_KLOCK
;
1033 return (VOP_LINK(vp
, tdvp
, cnp
));
1038 struct vop_rename_args
/* {
1039 struct vnode *a_fdvp;
1040 struct vnode *a_fvp;
1041 struct componentname *a_fcnp;
1042 struct vnode *a_tdvp;
1043 struct vnode *a_tvp;
1044 struct componentname *a_tcnp;
1049 struct vnode
*fdvp
= ap
->a_fdvp
;
1050 struct vnode
*fvp
= ap
->a_fvp
;
1051 struct vnode
*tdvp
= ap
->a_tdvp
;
1052 struct vnode
*tvp
= ap
->a_tvp
;
1054 if (fdvp
->v_op
== union_vnodeop_p
) { /* always true */
1055 struct union_node
*un
= VTOUNION(fdvp
);
1056 if (un
->un_uppervp
== NULLVP
) {
1058 * this should never happen in normal
1059 * operation but might if there was
1060 * a problem creating the top-level shadow
1067 fdvp
= un
->un_uppervp
;
1072 if (fvp
->v_op
== union_vnodeop_p
) { /* always true */
1073 struct union_node
*un
= VTOUNION(fvp
);
1074 if (un
->un_uppervp
== NULLVP
) {
1075 /* XXX: should do a copyup */
1080 if (un
->un_lowervp
!= NULLVP
)
1081 ap
->a_fcnp
->cn_flags
|= DOWHITEOUT
;
1083 fvp
= un
->un_uppervp
;
1088 if (tdvp
->v_op
== union_vnodeop_p
) {
1089 struct union_node
*un
= VTOUNION(tdvp
);
1090 if (un
->un_uppervp
== NULLVP
) {
1092 * this should never happen in normal
1093 * operation but might if there was
1094 * a problem creating the top-level shadow
1101 tdvp
= un
->un_uppervp
;
1103 un
->un_flags
|= UN_KLOCK
;
1107 if (tvp
!= NULLVP
&& tvp
->v_op
== union_vnodeop_p
) {
1108 struct union_node
*un
= VTOUNION(tvp
);
1110 tvp
= un
->un_uppervp
;
1111 if (tvp
!= NULLVP
) {
1113 un
->un_flags
|= UN_KLOCK
;
1118 return (VOP_RENAME(fdvp
, fvp
, ap
->a_fcnp
, tdvp
, tvp
, ap
->a_tcnp
));
1132 struct vop_mkdir_args
/* {
1133 struct vnode *a_dvp;
1134 struct vnode **a_vpp;
1135 struct componentname *a_cnp;
1136 struct vattr *a_vap;
1139 struct union_node
*un
= VTOUNION(ap
->a_dvp
);
1140 struct vnode
*dvp
= un
->un_uppervp
;
1141 struct componentname
*cnp
= ap
->a_cnp
;
1142 struct proc
*p
= cnp
->cn_proc
;
1144 if (dvp
!= NULLVP
) {
1150 un
->un_flags
|= UN_KLOCK
;
1151 VOP_UNLOCK(ap
->a_dvp
, 0, p
);
1152 error
= VOP_MKDIR(dvp
, &vp
, cnp
, ap
->a_vap
);
1158 error
= union_allocvp(ap
->a_vpp
, ap
->a_dvp
->v_mount
, ap
->a_dvp
,
1159 NULLVP
, cnp
, vp
, NULLVP
, 1);
1172 struct vop_rmdir_args
/* {
1173 struct vnode *a_dvp;
1175 struct componentname *a_cnp;
1179 struct union_node
*dun
= VTOUNION(ap
->a_dvp
);
1180 struct union_node
*un
= VTOUNION(ap
->a_vp
);
1181 struct componentname
*cnp
= ap
->a_cnp
;
1182 struct proc
*p
= cnp
->cn_proc
;
1184 if (dun
->un_uppervp
== NULLVP
)
1185 panic("union rmdir: null upper vnode");
1187 if (un
->un_uppervp
!= NULLVP
) {
1188 struct vnode
*dvp
= dun
->un_uppervp
;
1189 struct vnode
*vp
= un
->un_uppervp
;
1193 dun
->un_flags
|= UN_KLOCK
;
1197 un
->un_flags
|= UN_KLOCK
;
1200 if (union_dowhiteout(un
, cnp
->cn_cred
, cnp
->cn_proc
))
1201 cnp
->cn_flags
|= DOWHITEOUT
;
1202 error
= VOP_RMDIR(dvp
, vp
, ap
->a_cnp
);
1204 union_removed_upper(un
);
1207 error
= union_mkwhiteout(
1208 MOUNTTOUNIONMOUNT(UNIONTOV(dun
)->v_mount
),
1209 dun
->un_uppervp
, ap
->a_cnp
, un
->un_path
);
1219 struct vop_symlink_args
/* {
1220 struct vnode *a_dvp;
1221 struct vnode **a_vpp;
1222 struct componentname *a_cnp;
1223 struct vattr *a_vap;
1227 struct union_node
*un
= VTOUNION(ap
->a_dvp
);
1228 struct vnode
*dvp
= un
->un_uppervp
;
1229 struct componentname
*cnp
= ap
->a_cnp
;
1230 struct proc
*p
= cnp
->cn_proc
;
1232 if (dvp
!= NULLVP
) {
1235 struct mount
*mp
= ap
->a_dvp
->v_mount
;
1239 un
->un_flags
|= UN_KLOCK
;
1241 error
= VOP_SYMLINK(dvp
, &vp
, cnp
, ap
->a_vap
, ap
->a_target
);
1242 *ap
->a_vpp
= NULLVP
;
1251 * union_readdir works in concert with getdirentries and
1252 * readdir(3) to provide a list of entries in the unioned
1253 * directories. getdirentries is responsible for walking
1254 * down the union stack. readdir(3) is responsible for
1255 * eliminating duplicate names from the returned data stream.
1259 struct vop_readdir_args
/* {
1260 struct vnodeop_desc *a_desc;
1263 struct ucred *a_cred;
1269 struct union_node
*un
= VTOUNION(ap
->a_vp
);
1270 struct vnode
*uvp
= un
->un_uppervp
;
1271 struct proc
*p
= ap
->a_uio
->uio_procp
;
1278 return (VCALL(uvp
, VOFFSET(vop_readdir
), ap
));
1283 struct vop_readlink_args
/* {
1286 struct ucred *a_cred;
1290 struct uio
*uio
= ap
->a_uio
;
1291 struct proc
*p
= uio
->uio_procp
;
1292 struct vnode
*vp
= OTHERVP(ap
->a_vp
);
1293 int dolock
= (vp
== LOWERVP(ap
->a_vp
));
1296 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1298 FIXUP(VTOUNION(ap
->a_vp
), p
);
1300 error
= VCALL(vp
, VOFFSET(vop_readlink
), ap
);
1302 VOP_UNLOCK(vp
, 0, p
);
1309 struct vop_abortop_args
/* {
1310 struct vnode *a_dvp;
1311 struct componentname *a_cnp;
1315 struct componentname
*cnp
= ap
->a_cnp
;
1316 struct proc
*p
= cnp
->cn_proc
;
1317 struct vnode
*vp
= OTHERVP(ap
->a_dvp
);
1318 struct union_node
*un
= VTOUNION(ap
->a_dvp
);
1319 int islocked
= un
->un_flags
& UN_LOCKED
;
1320 int dolock
= (vp
== LOWERVP(ap
->a_dvp
));
1324 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1326 FIXUP(VTOUNION(ap
->a_dvp
), p
);
1329 error
= VCALL(vp
, VOFFSET(vop_abortop
), ap
);
1330 if (islocked
&& dolock
)
1331 VOP_UNLOCK(vp
, 0, p
);
1338 struct vop_inactive_args
/* {
1343 struct vnode
*vp
= ap
->a_vp
;
1344 struct proc
*p
= ap
->a_p
;
1345 struct union_node
*un
= VTOUNION(vp
);
1349 * Do nothing (and _don't_ bypass).
1350 * Wait to vrele lowervp until reclaim,
1351 * so that until then our union_node is in the
1352 * cache and reusable.
1354 * NEEDSWORK: Someday, consider inactive'ing
1355 * the lowervp and then trying to reactivate it
1356 * with capabilities (v_id)
1357 * like they do in the name lookup cache code.
1358 * That's too much work for now.
1361 if (un
->un_dircache
!= 0) {
1362 for (vpp
= un
->un_dircache
; *vpp
!= NULLVP
; vpp
++)
1364 _FREE(un
->un_dircache
, M_TEMP
);
1365 un
->un_dircache
= 0;
1368 VOP_UNLOCK(vp
, 0, p
);
1370 if ((un
->un_flags
& UN_CACHED
) == 0)
1378 struct vop_reclaim_args
/* {
1383 union_freevp(ap
->a_vp
);
1390 struct vop_lock_args
*ap
;
1392 struct vnode
*vp
= ap
->a_vp
;
1393 struct proc
*p
= ap
->a_p
;
1394 int flags
= ap
->a_flags
;
1395 struct union_node
*un
;
1401 * Need to do real lockmgr-style locking here.
1402 * in the mean time, draining won't work quite right,
1403 * which could lead to a few race conditions.
1404 * the following test was here, but is not quite right, we
1405 * still need to take the lock:
1406 if ((flags & LK_TYPE_MASK) == LK_DRAIN)
1409 flags
&= ~LK_INTERLOCK
;
1414 if (un
->un_uppervp
!= NULLVP
) {
1415 if (((un
->un_flags
& UN_ULOCK
) == 0) &&
1416 (vp
->v_usecount
!= 0)) {
1417 error
= vn_lock(un
->un_uppervp
, flags
, p
);
1420 un
->un_flags
|= UN_ULOCK
;
1423 if (un
->un_flags
& UN_KLOCK
) {
1424 vprint("union: dangling klock", vp
);
1425 panic("union: dangling upper lock (%lx)", vp
);
1430 if (un
->un_flags
& UN_LOCKED
) {
1432 if (current_proc() && un
->un_pid
== current_proc()->p_pid
&&
1433 un
->un_pid
> -1 && current_proc()->p_pid
> -1)
1434 panic("union: locking against myself");
1436 un
->un_flags
|= UN_WANT
;
1437 tsleep((caddr_t
)&un
->un_flags
, PINOD
, "unionlk2", 0);
1443 un
->un_pid
= current_proc()->p_pid
;
1448 un
->un_flags
|= UN_LOCKED
;
1453 * When operations want to vput() a union node yet retain a lock on
1454 * the upper vnode (say, to do some further operations like link(),
1455 * mkdir(), ...), they set UN_KLOCK on the union node, then call
1456 * vput() which calls VOP_UNLOCK() and comes here. union_unlock()
1457 * unlocks the union node (leaving the upper vnode alone), clears the
1458 * KLOCK flag, and then returns to vput(). The caller then does whatever
1459 * is left to do with the upper vnode, and ensures that it gets unlocked.
1461 * If UN_KLOCK isn't set, then the upper vnode is unlocked here.
1465 struct vop_unlock_args
/* {
1471 struct union_node
*un
= VTOUNION(ap
->a_vp
);
1472 struct proc
*p
= ap
->a_p
;
1475 if ((un
->un_flags
& UN_LOCKED
) == 0)
1476 panic("union: unlock unlocked node");
1477 if (current_proc() && un
->un_pid
!= current_proc()->p_pid
&&
1478 current_proc()->p_pid
> -1 && un
->un_pid
> -1)
1479 panic("union: unlocking other process's union node");
1482 un
->un_flags
&= ~UN_LOCKED
;
1484 if ((un
->un_flags
& (UN_ULOCK
|UN_KLOCK
)) == UN_ULOCK
)
1485 VOP_UNLOCK(un
->un_uppervp
, 0, p
);
1487 un
->un_flags
&= ~(UN_ULOCK
|UN_KLOCK
);
1489 if (un
->un_flags
& UN_WANT
) {
1490 un
->un_flags
&= ~UN_WANT
;
1491 wakeup((caddr_t
) &un
->un_flags
);
1504 struct vop_bmap_args
/* {
1507 struct vnode **a_vpp;
1513 struct proc
*p
= current_proc(); /* XXX */
1514 struct vnode
*vp
= OTHERVP(ap
->a_vp
);
1515 int dolock
= (vp
== LOWERVP(ap
->a_vp
));
1518 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1520 FIXUP(VTOUNION(ap
->a_vp
), p
);
1522 error
= VCALL(vp
, VOFFSET(vop_bmap
), ap
);
1524 VOP_UNLOCK(vp
, 0, p
);
1531 struct vop_cmap_args
/* {
1541 struct proc
*p
= current_proc(); /* XXX */
1542 struct vnode
*vp
= OTHERVP(ap
->a_vp
);
1543 int dolock
= (vp
== LOWERVP(ap
->a_vp
));
1546 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1548 FIXUP(VTOUNION(ap
->a_vp
), p
);
1550 error
= VCALL(vp
, VOFFSET(vop_cmap
), ap
);
1552 VOP_UNLOCK(vp
, 0, p
);
1559 struct vop_print_args
/* {
1563 struct vnode
*vp
= ap
->a_vp
;
1565 printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n",
1566 vp
, UPPERVP(vp
), LOWERVP(vp
));
1567 if (UPPERVP(vp
) != NULLVP
)
1568 vprint("union: upper", UPPERVP(vp
));
1569 if (LOWERVP(vp
) != NULLVP
)
1570 vprint("union: lower", LOWERVP(vp
));
1577 struct vop_islocked_args
/* {
1582 return ((VTOUNION(ap
->a_vp
)->un_flags
& UN_LOCKED
) ? 1 : 0);
1587 struct vop_pathconf_args
/* {
1594 struct proc
*p
= current_proc(); /* XXX */
1595 struct vnode
*vp
= OTHERVP(ap
->a_vp
);
1596 int dolock
= (vp
== LOWERVP(ap
->a_vp
));
1599 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1601 FIXUP(VTOUNION(ap
->a_vp
), p
);
1603 error
= VCALL(vp
, VOFFSET(vop_pathconf
), ap
);
1605 VOP_UNLOCK(vp
, 0, p
);
1612 struct vop_advlock_args
/* {
1620 register struct vnode
*ovp
= OTHERVP(ap
->a_vp
);
1623 return (VCALL(ovp
, VOFFSET(vop_advlock
), ap
));
1628 * XXX - vop_strategy must be hand coded because it has no
1629 * vnode in its arguments.
1630 * This goes away with a merged VM/buffer cache.
1634 struct vop_strategy_args
/* {
1638 struct buf
*bp
= ap
->a_bp
;
1640 struct vnode
*savedvp
;
1643 bp
->b_vp
= OTHERVP(bp
->b_vp
);
1646 if (bp
->b_vp
== NULLVP
)
1647 panic("union_strategy: nil vp");
1648 if (((bp
->b_flags
& B_READ
) == 0) &&
1649 (bp
->b_vp
== LOWERVP(savedvp
)))
1650 panic("union_strategy: writing to lowervp");
1653 error
= VOP_STRATEGY(bp
);
1661 struct vop_pagein_args
/* {
1664 vm_offset_t a_pl_offset,
1667 struct ucred *a_cred,
1672 struct proc
*p
= current_proc();
1673 struct vnode
*vp
= OTHERVP(ap
->a_vp
);
1675 error
= VOP_PAGEIN(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
,
1676 ap
->a_size
, ap
->a_cred
,ap
->a_flags
);
1680 * perhaps the size of the underlying object has changed under
1681 * our feet. take advantage of the offset information present
1682 * in the uio structure.
1685 struct union_node
*un
= VTOUNION(ap
->a_vp
);
1686 off_t cur
= ap
->a_f_offset
+ (off_t
)ap
->a_pl_offset
;
1688 if (vp
== un
->un_uppervp
) {
1689 if (cur
> un
->un_uppersz
)
1690 union_newsize(ap
->a_vp
, cur
, VNOVAL
);
1692 if (cur
> un
->un_lowersz
)
1693 union_newsize(ap
->a_vp
, VNOVAL
, cur
);
1702 struct vop_pageout_args
/* {
1705 vm_offset_t a_pl_offset,
1708 struct ucred *a_cred,
1714 struct union_node
*un
= VTOUNION(ap
->a_vp
);
1716 vp
= UPPERVP(ap
->a_vp
);
1718 panic("union: missing upper layer in pageout");
1720 error
= VOP_PAGEOUT(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
,
1721 ap
->a_size
, ap
->a_cred
,ap
->a_flags
);
1724 * the size of the underlying object may be changed by the
1728 off_t cur
= ap
->a_f_offset
+ (off_t
)ap
->a_pl_offset
;
1730 if (cur
> un
->un_uppersz
)
1731 union_newsize(ap
->a_vp
, cur
, VNOVAL
);
1737 /* Blktooff derives file offset for the given logical block number */
1740 struct vop_blktooff_args
/* {
1747 struct vnode
*vp
= OTHERVP(ap
->a_vp
);
1749 error
= VOP_BLKTOOFF(vp
, ap
->a_lblkno
, ap
->a_offset
);
1754 /* offtoblk derives file offset for the given logical block number */
1757 struct vop_offtoblk_args
/* {
1764 struct vnode
*vp
= OTHERVP(ap
->a_vp
);
1766 error
= VOP_OFFTOBLK(vp
, ap
->a_offset
, ap
->a_lblkno
);
1771 #define VOPFUNC int (*)(void *)
1774 * Global vfs data structures
1776 int (**union_vnodeop_p
)(void *);
1777 struct vnodeopv_entry_desc union_vnodeop_entries
[] = {
1778 { &vop_default_desc
, (VOPFUNC
)vn_default_error
},
1779 { &vop_lookup_desc
, (VOPFUNC
)union_lookup
}, /* lookup */
1780 { &vop_create_desc
, (VOPFUNC
)union_create
}, /* create */
1781 { &vop_whiteout_desc
, (VOPFUNC
)union_whiteout
}, /* whiteout */
1782 { &vop_mknod_desc
, (VOPFUNC
)union_mknod
}, /* mknod */
1783 { &vop_open_desc
, (VOPFUNC
)union_open
}, /* open */
1784 { &vop_close_desc
, (VOPFUNC
)union_close
}, /* close */
1785 { &vop_access_desc
, (VOPFUNC
)union_access
}, /* access */
1786 { &vop_getattr_desc
, (VOPFUNC
)union_getattr
}, /* getattr */
1787 { &vop_setattr_desc
, (VOPFUNC
)union_setattr
}, /* setattr */
1788 { &vop_read_desc
, (VOPFUNC
)union_read
}, /* read */
1789 { &vop_write_desc
, (VOPFUNC
)union_write
}, /* write */
1790 { &vop_lease_desc
, (VOPFUNC
)union_lease
}, /* lease */
1791 { &vop_ioctl_desc
, (VOPFUNC
)union_ioctl
}, /* ioctl */
1792 { &vop_select_desc
, (VOPFUNC
)union_select
}, /* select */
1793 { &vop_revoke_desc
, (VOPFUNC
)union_revoke
}, /* revoke */
1794 { &vop_mmap_desc
, (VOPFUNC
)union_mmap
}, /* mmap */
1795 { &vop_fsync_desc
, (VOPFUNC
)union_fsync
}, /* fsync */
1796 { &vop_seek_desc
, (VOPFUNC
)union_seek
}, /* seek */
1797 { &vop_remove_desc
, (VOPFUNC
)union_remove
}, /* remove */
1798 { &vop_link_desc
, (VOPFUNC
)union_link
}, /* link */
1799 { &vop_rename_desc
, (VOPFUNC
)union_rename
}, /* rename */
1800 { &vop_mkdir_desc
, (VOPFUNC
)union_mkdir
}, /* mkdir */
1801 { &vop_rmdir_desc
, (VOPFUNC
)union_rmdir
}, /* rmdir */
1802 { &vop_symlink_desc
, (VOPFUNC
)union_symlink
}, /* symlink */
1803 { &vop_readdir_desc
, (VOPFUNC
)union_readdir
}, /* readdir */
1804 { &vop_readlink_desc
, (VOPFUNC
)union_readlink
}, /* readlink */
1805 { &vop_abortop_desc
, (VOPFUNC
)union_abortop
}, /* abortop */
1806 { &vop_inactive_desc
, (VOPFUNC
)union_inactive
}, /* inactive */
1807 { &vop_reclaim_desc
, (VOPFUNC
)union_reclaim
}, /* reclaim */
1808 { &vop_lock_desc
, (VOPFUNC
)union_lock
}, /* lock */
1809 { &vop_unlock_desc
, (VOPFUNC
)union_unlock
}, /* unlock */
1810 { &vop_bmap_desc
, (VOPFUNC
)union_bmap
}, /* bmap */
1811 { &vop_strategy_desc
, (VOPFUNC
)union_strategy
}, /* strategy */
1812 { &vop_print_desc
, (VOPFUNC
)union_print
}, /* print */
1813 { &vop_islocked_desc
, (VOPFUNC
)union_islocked
}, /* islocked */
1814 { &vop_pathconf_desc
, (VOPFUNC
)union_pathconf
}, /* pathconf */
1815 { &vop_advlock_desc
, (VOPFUNC
)union_advlock
}, /* advlock */
1817 { &vop_blkatoff_desc
, (VOPFUNC
)union_blkatoff
}, /* blkatoff */
1818 { &vop_valloc_desc
, (VOPFUNC
)union_valloc
}, /* valloc */
1819 { &vop_vfree_desc
, (VOPFUNC
)union_vfree
}, /* vfree */
1820 { &vop_truncate_desc
, (VOPFUNC
)union_truncate
}, /* truncate */
1821 { &vop_update_desc
, (VOPFUNC
)union_update
}, /* update */
1822 { &vop_bwrite_desc
, (VOPFUNC
)union_bwrite
}, /* bwrite */
1824 { &vop_pagein_desc
, (VOPFUNC
)union_pagein
}, /* Pagein */
1825 { &vop_pageout_desc
, (VOPFUNC
)union_pageout
}, /* Pageout */
1826 { &vop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
1827 { &vop_blktooff_desc
, (VOPFUNC
)union_blktooff
}, /* blktooff */
1828 { &vop_offtoblk_desc
, (VOPFUNC
)union_offtoblk
}, /* offtoblk */
1829 { &vop_cmap_desc
, (VOPFUNC
)union_cmap
}, /* cmap */
1830 { (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
1832 struct vnodeopv_desc union_vnodeop_opv_desc
=
1833 { &union_vnodeop_p
, union_vnodeop_entries
};