2 * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
3 * Copyright (c) 1992, 1993, 1994, 1995
4 * The Regents of the University of California.
5 * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
6 * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org>
9 * This code is derived from software contributed to Berkeley by
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95
37 * $FreeBSD: src/sys/fs/unionfs/union_vnops.c,v 1.152 2008/01/13 14:44:06 attilio Exp $
41 #include <sys/param.h>
42 #include <sys/systm.h>
44 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/mount.h>
48 #include <sys/mutex.h>
49 #include <sys/namei.h>
50 #include <sys/sysctl.h>
51 #include <sys/vnode.h>
52 #include <sys/fcntl.h>
54 #include <sys/dirent.h>
57 #include <fs/unionfs/unionfs.h>
60 #define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args)
61 #define UNIONFS_IDBG_RENAME
63 #define UNIONFS_INTERNAL_DEBUG(msg, args...)
67 unionfs_lookup(void *v
)
69 struct vop_lookup_args
*ap
= v
;
72 int error
, uerror
, lerror
;
74 u_long cnflags
, cnflagsbk
;
75 struct unionfs_node
*dunp
;
76 struct vnode
*dvp
, *udvp
, *ldvp
, *vp
, *uvp
, *lvp
, *dtmpvp
;
78 struct componentname
*cnp
;
82 error
= uerror
= lerror
= ENOENT
;
84 nameiop
= cnp
->cn_nameiop
;
85 cnflags
= cnp
->cn_flags
;
87 dunp
= VTOUNIONFS(dvp
);
88 udvp
= dunp
->un_uppervp
;
89 ldvp
= dunp
->un_lowervp
;
90 vp
= uvp
= lvp
= NULLVP
;
91 *(ap
->a_vpp
) = NULLVP
;
93 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop
, cnflags
, cnp
->cn_nameptr
);
95 if (dvp
->v_type
!= VDIR
)
99 * If read-only and op is not LOOKUP, will return EROFS.
101 if ((cnflags
& ISLASTCN
) &&
102 (dvp
->v_mount
->mnt_flag
& MNT_RDONLY
) &&
109 if (cnflags
& ISDOTDOT
) {
110 if (LOOKUP
!= nameiop
&& udvp
== NULLVP
)
113 if (udvp
!= NULLVP
) {
121 error
= VOP_LOOKUP(dtmpvp
, &vp
, cnp
);
123 if (dtmpvp
== udvp
&& ldvp
!= NULLVP
) {
125 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
130 * Exchange lock and reference from vp to
131 * dunp->un_dvp. vp is upper/lower vnode, but it
132 * will need to return the unionfs vnode.
134 if (nameiop
== DELETE
|| nameiop
== RENAME
)
139 *(ap
->a_vpp
) = dunp
->un_dvp
;
142 vn_lock(dunp
->un_dvp
, LK_EXCLUSIVE
| LK_RETRY
);
143 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
144 } else if (error
== ENOENT
&& (cnflags
& MAKEENTRY
) &&
146 cache_enter(dvp
, NULLVP
, cnp
);
148 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error
);
156 if (udvp
!= NULLVP
) {
157 uerror
= VOP_LOOKUP(udvp
, &uvp
, cnp
);
160 if (udvp
== uvp
) { /* is dot */
165 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror
);
172 if (uerror
== ENOENT
|| uerror
== EJUSTRETURN
)
173 if (cnp
->cn_flags
& ISWHITEOUT
)
174 iswhiteout
= 1; /* don't lookup lower */
175 if (iswhiteout
== 0 && ldvp
!= NULLVP
)
176 if (VOP_GETATTR(udvp
, &va
, cnp
->cn_cred
) == 0 &&
177 (va
.va_flags
& OPAQUE
))
178 iswhiteout
= 1; /* don't lookup lower */
180 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout
, cnp
->cn_nameptr
);
187 if (ldvp
!= NULLVP
&& !(cnflags
& DOWHITEOUT
) && iswhiteout
== 0) {
188 /* always op is LOOKUP */
189 cnp
->cn_nameiop
= LOOKUP
;
190 cnflagsbk
= cnp
->cn_flags
;
191 cnp
->cn_flags
= cnflags
;
193 lerror
= VOP_LOOKUP(ldvp
, &lvp
, cnp
);
195 cnp
->cn_nameiop
= nameiop
;
196 if (udvp
!= NULLVP
&& (uerror
== 0 || uerror
== EJUSTRETURN
))
197 cnp
->cn_flags
= cnflagsbk
;
200 if (ldvp
== lvp
) { /* is dot */
202 vrele(uvp
); /* no need? */
207 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror
);
216 * check lookup result
218 if (uvp
== NULLVP
&& lvp
== NULLVP
) {
219 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n",
220 (udvp
!= NULLVP
? uerror
: lerror
));
221 return (udvp
!= NULLVP
? uerror
: lerror
);
227 if (uvp
!= NULLVP
&& lvp
!= NULLVP
&& uvp
->v_type
!= lvp
->v_type
) {
235 if (uerror
!= 0 && uerror
!= EJUSTRETURN
&& udvp
!= NULLVP
&&
236 lerror
== 0 && lvp
!= NULLVP
&& lvp
->v_type
== VDIR
&&
237 !(dvp
->v_mount
->mnt_flag
& MNT_RDONLY
) &&
238 (1 < cnp
->cn_namelen
|| '.' != *(cnp
->cn_nameptr
))) {
239 /* get unionfs vnode in order to create a new shadow dir. */
240 error
= unionfs_nodeget(dvp
->v_mount
, NULLVP
, lvp
, dvp
, &vp
,
243 goto unionfs_lookup_out
;
244 error
= unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp
->v_mount
),
245 udvp
, VTOUNIONFS(vp
), cnp
);
247 UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir.");
249 goto unionfs_lookup_out
;
261 goto unionfs_lookup_out
;
262 error
= unionfs_nodeget(dvp
->v_mount
, uvp
, lvp
, dvp
, &vp
, cnp
);
264 UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode.");
265 goto unionfs_lookup_out
;
271 if (cnflags
& MAKEENTRY
)
272 cache_enter(dvp
, vp
, cnp
);
274 /* XXXAD lock status on error */
281 if (error
== ENOENT
&& (cnflags
& MAKEENTRY
) && nameiop
!= CREATE
)
282 cache_enter(dvp
, NULLVP
, cnp
);
284 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error
);
290 unionfs_create(void *v
)
292 struct vop_create_args
*ap
= v
;
293 struct unionfs_node
*dunp
;
294 struct componentname
*cnp
;
299 UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");
301 dunp
= VTOUNIONFS(ap
->a_dvp
);
303 udvp
= dunp
->un_uppervp
;
306 if (udvp
!= NULLVP
) {
307 if ((error
= VOP_CREATE(udvp
, &vp
, cnp
, ap
->a_vap
)) == 0) {
308 error
= unionfs_nodeget(ap
->a_dvp
->v_mount
, vp
, NULLVP
,
309 ap
->a_dvp
, ap
->a_vpp
, cnp
);
318 UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error
);
324 unionfs_whiteout(void *v
)
326 struct vop_whiteout_args
*ap
= v
;
327 struct unionfs_node
*dunp
;
328 struct componentname
*cnp
;
332 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n");
334 dunp
= VTOUNIONFS(ap
->a_dvp
);
336 udvp
= dunp
->un_uppervp
;
339 if (udvp
!= NULLVP
) {
340 switch (ap
->a_flags
) {
344 error
= VOP_WHITEOUT(udvp
, cnp
, ap
->a_flags
);
352 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error
);
358 unionfs_mknod(void *v
)
360 struct vop_mknod_args
*ap
= v
;
361 struct unionfs_node
*dunp
;
362 struct componentname
*cnp
;
367 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n");
369 dunp
= VTOUNIONFS(ap
->a_dvp
);
371 udvp
= dunp
->un_uppervp
;
374 if (udvp
!= NULLVP
) {
375 if ((error
= VOP_MKNOD(udvp
, &vp
, cnp
, ap
->a_vap
)) == 0) {
376 error
= unionfs_nodeget(ap
->a_dvp
->v_mount
, vp
, NULLVP
,
377 ap
->a_dvp
, ap
->a_vpp
, cnp
);
386 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error
);
392 unionfs_open(void *v
)
394 struct vop_open_args
*ap
= v
;
396 struct unionfs_node
*unp
;
397 struct unionfs_node_status
*unsp
;
400 struct vnode
*targetvp
;
403 UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n");
406 unp
= VTOUNIONFS(ap
->a_vp
);
407 uvp
= unp
->un_uppervp
;
408 lvp
= unp
->un_lowervp
;
412 unionfs_get_node_status(unp
, &unsp
);
414 if (unsp
->uns_lower_opencnt
> 0 || unsp
->uns_upper_opencnt
> 0) {
415 /* vnode is already opend. */
416 if (unsp
->uns_upper_opencnt
> 0)
421 if (targetvp
== lvp
&&
422 (ap
->a_mode
& FWRITE
) && lvp
->v_type
== VREG
)
425 if (targetvp
== NULLVP
) {
427 if ((ap
->a_mode
& FWRITE
) && lvp
->v_type
== VREG
) {
428 error
= unionfs_copyfile(unp
,
429 !(ap
->a_mode
& O_TRUNC
), cred
);
431 goto unionfs_open_abort
;
432 targetvp
= uvp
= unp
->un_uppervp
;
439 error
= VOP_OPEN(targetvp
, ap
->a_mode
, cred
);
441 if (targetvp
== uvp
) {
442 if (uvp
->v_type
== VDIR
&& lvp
!= NULLVP
&&
443 unsp
->uns_lower_opencnt
<= 0) {
444 /* open lower for readdir */
445 error
= VOP_OPEN(lvp
, FREAD
, cred
);
447 VOP_CLOSE(uvp
, ap
->a_mode
, cred
);
448 goto unionfs_open_abort
;
450 unsp
->uns_node_flag
|= UNS_OPENL_4_READDIR
;
451 unsp
->uns_lower_opencnt
++;
453 unsp
->uns_upper_opencnt
++;
455 unsp
->uns_lower_opencnt
++;
456 unsp
->uns_lower_openmode
= ap
->a_mode
;
462 unionfs_tryrem_node_status(unp
, unsp
);
464 UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error
);
470 unionfs_close(void *v
)
472 struct vop_close_args
*ap
= v
;
475 struct unionfs_node
*unp
;
476 struct unionfs_node_status
*unsp
;
480 UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");
483 unp
= VTOUNIONFS(ap
->a_vp
);
486 if (VOP_ISLOCKED(ap
->a_vp
) != LK_EXCLUSIVE
) {
487 vn_lock(ap
->a_vp
, LK_EXCLUSIVE
| LK_RETRY
);
490 unionfs_get_node_status(unp
, &unsp
);
492 if (unsp
->uns_lower_opencnt
<= 0 && unsp
->uns_upper_opencnt
<= 0) {
494 printf("unionfs_close: warning: open count is 0\n");
496 if (unp
->un_uppervp
!= NULLVP
)
497 ovp
= unp
->un_uppervp
;
499 ovp
= unp
->un_lowervp
;
500 } else if (unsp
->uns_upper_opencnt
> 0)
501 ovp
= unp
->un_uppervp
;
503 ovp
= unp
->un_lowervp
;
505 error
= VOP_CLOSE(ovp
, ap
->a_fflag
, cred
);
508 goto unionfs_close_abort
;
510 if (ovp
== unp
->un_uppervp
) {
511 unsp
->uns_upper_opencnt
--;
512 if (unsp
->uns_upper_opencnt
== 0) {
513 if (unsp
->uns_node_flag
& UNS_OPENL_4_READDIR
) {
514 VOP_CLOSE(unp
->un_lowervp
, FREAD
, cred
);
515 unsp
->uns_node_flag
&= ~UNS_OPENL_4_READDIR
;
516 unsp
->uns_lower_opencnt
--;
520 unsp
->uns_lower_opencnt
--;
523 unionfs_tryrem_node_status(unp
, unsp
);
526 VOP_UNLOCK(ap
->a_vp
, 0);
528 UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error
);
534 * Check the access mode toward shadow file/dir.
537 unionfs_check_corrected_access(u_short mode
, struct vattr
*va
, kauth_cred_t cred
)
541 uid_t uid
; /* upper side vnode's uid */
542 gid_t gid
; /* upper side vnode's gid */
543 u_short vmode
; /* upper side vnode's mode */
552 if (kauth_cred_getuid(cred
) == uid
) {
559 return ((vmode
& mask
) == mask
? 0 : EACCES
);
563 error
= kauth_cred_ismember_gid(cred
, gid
, &result
);
573 return ((vmode
& mask
) == mask
? 0 : EACCES
);
584 return ((vmode
& mask
) == mask
? 0 : EACCES
);
588 unionfs_access(void *v
)
590 struct vop_access_args
*ap
= v
;
591 struct unionfs_mount
*ump
;
592 struct unionfs_node
*unp
;
599 UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n");
601 ump
= MOUNTTOUNIONFSMOUNT(ap
->a_vp
->v_mount
);
602 unp
= VTOUNIONFS(ap
->a_vp
);
603 uvp
= unp
->un_uppervp
;
604 lvp
= unp
->un_lowervp
;
608 if ((mode
& VWRITE
) &&
609 (ap
->a_vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
610 switch (ap
->a_vp
->v_type
) {
621 error
= VOP_ACCESS(uvp
, mode
, ap
->a_cred
);
623 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error
);
630 if (ump
->um_uppervp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
631 switch (ap
->a_vp
->v_type
) {
639 } else if (ap
->a_vp
->v_type
== VREG
|| ap
->a_vp
->v_type
== VDIR
) {
640 /* check shadow file/dir */
641 if (ump
->um_copymode
!= UNIONFS_TRANSPARENT
) {
642 error
= unionfs_create_uppervattr(ump
,
643 lvp
, &va
, ap
->a_cred
);
647 error
= unionfs_check_corrected_access(
648 mode
, &va
, ap
->a_cred
);
654 mode
|= VREAD
; /* will copy to upper */
656 error
= VOP_ACCESS(lvp
, mode
, ap
->a_cred
);
659 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error
);
665 unionfs_getattr(void *v
)
667 struct vop_getattr_args
*ap
= v
;
669 struct unionfs_node
*unp
;
670 struct unionfs_mount
*ump
;
675 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
677 unp
= VTOUNIONFS(ap
->a_vp
);
678 ump
= MOUNTTOUNIONFSMOUNT(ap
->a_vp
->v_mount
);
679 uvp
= unp
->un_uppervp
;
680 lvp
= unp
->un_lowervp
;
683 if ((error
= VOP_GETATTR(uvp
, ap
->a_vap
, ap
->a_cred
)) == 0)
684 ap
->a_vap
->va_fsid
= ap
->a_vp
->v_mount
->mnt_stat
.f_fsid
;
686 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
687 ap
->a_vap
->va_mode
, ap
->a_vap
->va_uid
,
688 ap
->a_vap
->va_gid
, error
);
693 error
= VOP_GETATTR(lvp
, ap
->a_vap
, ap
->a_cred
);
695 if (error
== 0 && !(ump
->um_uppervp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
696 /* correct the attr toward shadow file/dir. */
697 if (ap
->a_vp
->v_type
== VREG
|| ap
->a_vp
->v_type
== VDIR
) {
698 unionfs_create_uppervattr_core(ump
, ap
->a_vap
, &va
);
699 ap
->a_vap
->va_mode
= va
.va_mode
;
700 ap
->a_vap
->va_uid
= va
.va_uid
;
701 ap
->a_vap
->va_gid
= va
.va_gid
;
706 ap
->a_vap
->va_fsid
= ap
->a_vp
->v_mount
->mnt_stat
.f_fsid
;
708 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
709 ap
->a_vap
->va_mode
, ap
->a_vap
->va_uid
, ap
->a_vap
->va_gid
, error
);
715 unionfs_setattr(void *v
)
717 struct vop_setattr_args
*ap
= v
;
719 struct unionfs_node
*unp
;
724 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n");
727 unp
= VTOUNIONFS(ap
->a_vp
);
728 uvp
= unp
->un_uppervp
;
729 lvp
= unp
->un_lowervp
;
732 if ((ap
->a_vp
->v_mount
->mnt_flag
& MNT_RDONLY
) &&
733 (vap
->va_flags
!= VNOVAL
|| vap
->va_uid
!= (uid_t
)VNOVAL
||
734 vap
->va_gid
!= (gid_t
)VNOVAL
|| vap
->va_atime
.tv_sec
!= VNOVAL
||
735 vap
->va_mtime
.tv_sec
!= VNOVAL
|| vap
->va_mode
!= (mode_t
)VNOVAL
))
738 if (uvp
== NULLVP
&& lvp
->v_type
== VREG
) {
739 error
= unionfs_copyfile(unp
, (vap
->va_size
!= 0),
743 uvp
= unp
->un_uppervp
;
747 error
= VOP_SETATTR(uvp
, vap
, ap
->a_cred
);
749 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error
);
755 unionfs_read(void *v
)
757 struct vop_read_args
*ap
= v
;
759 struct unionfs_node
*unp
;
762 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */
764 unp
= VTOUNIONFS(ap
->a_vp
);
765 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
767 error
= VOP_READ(tvp
, ap
->a_uio
, ap
->a_ioflag
, ap
->a_cred
);
769 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */
775 unionfs_write(void *v
)
777 struct vop_write_args
*ap
= v
;
779 struct unionfs_node
*unp
;
782 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */
784 unp
= VTOUNIONFS(ap
->a_vp
);
785 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
787 error
= VOP_WRITE(tvp
, ap
->a_uio
, ap
->a_ioflag
, ap
->a_cred
);
789 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */
795 unionfs_ioctl(void *v
)
797 struct vop_ioctl_args
*ap
= v
;
799 struct unionfs_node
*unp
;
800 struct unionfs_node_status
*unsp
;
803 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n");
805 vn_lock(ap
->a_vp
, LK_EXCLUSIVE
| LK_RETRY
);
806 unp
= VTOUNIONFS(ap
->a_vp
);
807 unionfs_get_node_status(unp
, &unsp
);
808 ovp
= (unsp
->uns_upper_opencnt
? unp
->un_uppervp
: unp
->un_lowervp
);
809 unionfs_tryrem_node_status(unp
, unsp
);
810 VOP_UNLOCK(ap
->a_vp
, 0);
815 error
= VOP_IOCTL(ovp
, ap
->a_command
, ap
->a_data
, ap
->a_fflag
,
818 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: lease (%d)\n", error
);
824 unionfs_poll(void *v
)
826 struct vop_poll_args
*ap
= v
;
827 struct unionfs_node
*unp
;
828 struct unionfs_node_status
*unsp
;
831 vn_lock(ap
->a_vp
, LK_EXCLUSIVE
| LK_RETRY
);
832 unp
= VTOUNIONFS(ap
->a_vp
);
833 unionfs_get_node_status(unp
, &unsp
);
834 ovp
= (unsp
->uns_upper_opencnt
? unp
->un_uppervp
: unp
->un_lowervp
);
835 unionfs_tryrem_node_status(unp
, unsp
);
836 VOP_UNLOCK(ap
->a_vp
, 0);
841 return (VOP_POLL(ovp
, ap
->a_events
));
845 unionfs_fsync(void *v
)
847 struct vop_fsync_args
*ap
= v
;
848 struct unionfs_node
*unp
;
849 struct unionfs_node_status
*unsp
;
852 unp
= VTOUNIONFS(ap
->a_vp
);
853 unionfs_get_node_status(unp
, &unsp
);
854 ovp
= (unsp
->uns_upper_opencnt
? unp
->un_uppervp
: unp
->un_lowervp
);
855 unionfs_tryrem_node_status(unp
, unsp
);
860 return (VOP_FSYNC(ovp
, ap
->a_cred
, ap
->a_flags
, ap
->a_offlo
, ap
->a_offhi
));
864 unionfs_remove(void *v
)
866 struct vop_remove_args
*ap
= v
;
868 struct unionfs_node
*dunp
;
869 struct unionfs_node
*unp
;
870 struct unionfs_mount
*ump
;
874 struct componentname
*cnp
;
876 UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n");
879 dunp
= VTOUNIONFS(ap
->a_dvp
);
880 unp
= VTOUNIONFS(ap
->a_vp
);
881 udvp
= dunp
->un_uppervp
;
882 uvp
= unp
->un_uppervp
;
883 lvp
= unp
->un_lowervp
;
890 ump
= MOUNTTOUNIONFSMOUNT(ap
->a_vp
->v_mount
);
891 if (ump
->um_whitemode
== UNIONFS_WHITE_ALWAYS
|| lvp
!= NULLVP
)
892 cnp
->cn_flags
|= DOWHITEOUT
;
893 error
= VOP_REMOVE(udvp
, uvp
, cnp
);
894 } else if (lvp
!= NULLVP
)
895 error
= unionfs_mkwhiteout(udvp
, cnp
, unp
->un_path
);
897 UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error
);
903 unionfs_link(void *v
)
906 struct vop_link_args
*ap
= v
;
909 struct unionfs_node
*dunp
;
910 struct unionfs_node
*unp
;
913 struct componentname
*cnp
;
915 UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");
919 dunp
= VTOUNIONFS(ap
->a_tdvp
);
921 udvp
= dunp
->un_uppervp
;
928 if (ap
->a_vp
->v_op
!= unionfs_vnodeop_p
)
931 unp
= VTOUNIONFS(ap
->a_vp
);
933 if (unp
->un_uppervp
== NULLVP
) {
934 if (ap
->a_vp
->v_type
!= VREG
)
937 error
= unionfs_copyfile(unp
, 1, cnp
->cn_cred
);
942 uvp
= unp
->un_uppervp
;
945 if (needrelookup
!= 0)
946 error
= unionfs_relookup_for_create(ap
->a_tdvp
, cnp
);
949 error
= VOP_LINK(udvp
, uvp
, cnp
);
951 UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error
);
961 unionfs_rename(void *v
)
963 struct vop_rename_args
*ap
= v
;
967 struct componentname
*fcnp
;
970 struct componentname
*tcnp
;
974 /* rename target vnodes */
981 struct unionfs_mount
*ump
;
982 struct unionfs_node
*unp
;
984 UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n");
1002 if (!(fcnp
->cn_flags
& HASBUF
) || !(tcnp
->cn_flags
& HASBUF
))
1003 panic("unionfs_rename: no name");
1006 /* check for cross device rename */
1007 if (fvp
->v_mount
!= tdvp
->v_mount
||
1008 (tvp
!= NULLVP
&& fvp
->v_mount
!= tvp
->v_mount
)) {
1010 goto unionfs_rename_abort
;
1013 /* Renaming a file to itself has no effect. */
1015 goto unionfs_rename_abort
;
1018 * from/to vnode is unionfs node.
1021 unp
= VTOUNIONFS(fdvp
);
1022 #ifdef UNIONFS_IDBG_RENAME
1023 UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp
, unp
->un_uppervp
, unp
->un_lowervp
);
1025 if (unp
->un_uppervp
== NULLVP
) {
1027 goto unionfs_rename_abort
;
1029 rfdvp
= unp
->un_uppervp
;
1032 unp
= VTOUNIONFS(fvp
);
1033 #ifdef UNIONFS_IDBG_RENAME
1034 UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp
, unp
->un_uppervp
, unp
->un_lowervp
);
1036 ump
= MOUNTTOUNIONFSMOUNT(fvp
->v_mount
);
1037 if (unp
->un_uppervp
== NULLVP
) {
1038 switch (fvp
->v_type
) {
1040 if ((error
= vn_lock(fvp
, LK_EXCLUSIVE
)) != 0)
1041 goto unionfs_rename_abort
;
1042 error
= unionfs_copyfile(unp
, 1, fcnp
->cn_cred
);
1045 goto unionfs_rename_abort
;
1048 if ((error
= vn_lock(fvp
, LK_EXCLUSIVE
)) != 0)
1049 goto unionfs_rename_abort
;
1050 error
= unionfs_mkshadowdir(ump
, rfdvp
, unp
, fcnp
);
1053 goto unionfs_rename_abort
;
1057 goto unionfs_rename_abort
;
1063 if (unp
->un_lowervp
!= NULLVP
)
1064 fcnp
->cn_flags
|= DOWHITEOUT
;
1065 rfvp
= unp
->un_uppervp
;
1068 unp
= VTOUNIONFS(tdvp
);
1069 #ifdef UNIONFS_IDBG_RENAME
1070 UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp
, unp
->un_uppervp
, unp
->un_lowervp
);
1072 if (unp
->un_uppervp
== NULLVP
) {
1074 goto unionfs_rename_abort
;
1076 rtdvp
= unp
->un_uppervp
;
1077 ltdvp
= unp
->un_lowervp
;
1083 } else if (tvp
!= NULLVP
) {
1084 unp
= VTOUNIONFS(tvp
);
1085 #ifdef UNIONFS_IDBG_RENAME
1086 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp
, unp
->un_uppervp
, unp
->un_lowervp
);
1088 if (unp
->un_uppervp
== NULLVP
)
1091 if (tvp
->v_type
== VDIR
) {
1093 goto unionfs_rename_abort
;
1095 rtvp
= unp
->un_uppervp
;
1096 ltvp
= unp
->un_lowervp
;
1101 if (needrelookup
!= 0) {
1102 if ((error
= vn_lock(fdvp
, LK_EXCLUSIVE
)) != 0)
1103 goto unionfs_rename_abort
;
1104 error
= unionfs_relookup_for_delete(fdvp
, fcnp
);
1105 VOP_UNLOCK(fdvp
, 0);
1107 goto unionfs_rename_abort
;
1109 /* Locke of tvp is canceled in order to avoid recursive lock. */
1110 if (tvp
!= NULLVP
&& tvp
!= tdvp
)
1112 error
= unionfs_relookup_for_rename(tdvp
, tcnp
);
1113 if (tvp
!= NULLVP
&& tvp
!= tdvp
)
1114 vn_lock(tvp
, LK_EXCLUSIVE
| LK_RETRY
);
1116 goto unionfs_rename_abort
;
1119 error
= VOP_RENAME(rfdvp
, rfvp
, fcnp
, rtdvp
, rtvp
, tcnp
);
1122 if (rtvp
!= NULLVP
&& rtvp
->v_type
== VDIR
)
1124 if (fvp
->v_type
== VDIR
&& fdvp
!= tdvp
)
1132 if (ltdvp
!= NULLVP
)
1133 VOP_UNLOCK(ltdvp
, 0);
1137 VOP_UNLOCK(ltvp
, 0);
1138 if (tvp
!= rtvp
&& tvp
!= NULLVP
) {
1145 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error
);
1149 unionfs_rename_abort
:
1157 if (tvp
!= rtvp
&& rtvp
!= NULLVP
)
1159 if (tvp
!= NULLVP
) {
1168 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error
);
1174 unionfs_mkdir(void *v
)
1176 struct vop_mkdir_args
*ap
= v
;
1178 struct unionfs_node
*dunp
;
1179 struct componentname
*cnp
;
1184 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1187 dunp
= VTOUNIONFS(ap
->a_dvp
);
1189 udvp
= dunp
->un_uppervp
;
1191 if (udvp
!= NULLVP
) {
1193 if (!(cnp
->cn_flags
& ISWHITEOUT
)) {
1194 error
= VOP_GETATTR(udvp
, &va
, cnp
->cn_cred
);
1197 if (va
.va_flags
& OPAQUE
)
1198 cnp
->cn_flags
|= ISWHITEOUT
;
1201 if ((error
= VOP_MKDIR(udvp
, &uvp
, cnp
, ap
->a_vap
)) == 0) {
1202 error
= unionfs_nodeget(ap
->a_dvp
->v_mount
, uvp
, NULLVP
,
1203 ap
->a_dvp
, ap
->a_vpp
, cnp
);
1212 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error
);
1218 unionfs_rmdir(void *v
)
1220 struct vop_rmdir_args
*ap
= v
;
1222 struct unionfs_node
*dunp
;
1223 struct unionfs_node
*unp
;
1224 struct unionfs_mount
*ump
;
1225 struct componentname
*cnp
;
1230 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1233 dunp
= VTOUNIONFS(ap
->a_dvp
);
1234 unp
= VTOUNIONFS(ap
->a_vp
);
1236 udvp
= dunp
->un_uppervp
;
1237 uvp
= unp
->un_uppervp
;
1238 lvp
= unp
->un_lowervp
;
1244 return (EOPNOTSUPP
);
1246 if (uvp
!= NULLVP
) {
1247 if (lvp
!= NULLVP
) {
1248 error
= unionfs_check_rmdir(ap
->a_vp
, cnp
->cn_cred
);
1252 ump
= MOUNTTOUNIONFSMOUNT(ap
->a_vp
->v_mount
);
1253 if (ump
->um_whitemode
== UNIONFS_WHITE_ALWAYS
|| lvp
!= NULLVP
)
1254 cnp
->cn_flags
|= DOWHITEOUT
;
1255 error
= VOP_RMDIR(udvp
, uvp
, cnp
);
1257 else if (lvp
!= NULLVP
)
1258 error
= unionfs_mkwhiteout(udvp
, cnp
, unp
->un_path
);
1261 cache_purge(ap
->a_dvp
);
1262 cache_purge(ap
->a_vp
);
1265 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error
);
1271 unionfs_symlink(void *v
)
1273 struct vop_symlink_args
*ap
= v
;
1275 struct unionfs_node
*dunp
;
1276 struct componentname
*cnp
;
1280 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1283 dunp
= VTOUNIONFS(ap
->a_dvp
);
1285 udvp
= dunp
->un_uppervp
;
1287 if (udvp
!= NULLVP
) {
1288 error
= VOP_SYMLINK(udvp
, &uvp
, cnp
, ap
->a_vap
, ap
->a_target
);
1290 error
= unionfs_nodeget(ap
->a_dvp
->v_mount
, uvp
, NULLVP
,
1291 ap
->a_dvp
, ap
->a_vpp
, cnp
);
1300 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error
);
1306 unionfs_readdir(void *v
)
1308 struct vop_readdir_args
*ap
= v
;
1312 struct unionfs_node
*unp
;
1313 struct unionfs_node_status
*unsp
;
1322 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1327 unp
= VTOUNIONFS(ap
->a_vp
);
1329 uvp
= unp
->un_uppervp
;
1330 lvp
= unp
->un_lowervp
;
1334 if (ap
->a_vp
->v_type
!= VDIR
)
1338 if (uvp
!= NULLVP
&& lvp
!= NULLVP
) {
1339 if ((error
= VOP_GETATTR(uvp
, &va
, ap
->a_cred
)) != 0)
1340 goto unionfs_readdir_exit
;
1341 if (va
.va_flags
& OPAQUE
)
1345 /* check the open count. unionfs needs to open before readdir. */
1346 VOP_UNLOCK(ap
->a_vp
, 0);
1347 vn_lock(ap
->a_vp
, LK_EXCLUSIVE
| LK_RETRY
);
1348 unionfs_get_node_status(unp
, &unsp
);
1349 if ((uvp
!= NULLVP
&& unsp
->uns_upper_opencnt
<= 0) ||
1350 (lvp
!= NULLVP
&& unsp
->uns_lower_opencnt
<= 0)) {
1351 unionfs_tryrem_node_status(unp
, unsp
);
1355 goto unionfs_readdir_exit
;
1358 if (uvp
!= NULLVP
&& lvp
== NULLVP
) {
1359 error
= VOP_READDIR(uvp
, uio
, ap
->a_cred
, ap
->a_eofflag
,
1360 ap
->a_cookies
, ap
->a_ncookies
);
1361 unsp
->uns_readdir_status
= 0;
1363 goto unionfs_readdir_exit
;
1367 if (uvp
== NULLVP
&& lvp
!= NULLVP
) {
1368 error
= VOP_READDIR(lvp
, uio
, ap
->a_cred
, ap
->a_eofflag
,
1369 ap
->a_cookies
, ap
->a_ncookies
);
1370 unsp
->uns_readdir_status
= 2;
1372 goto unionfs_readdir_exit
;
1376 * readdir upper and lower
1378 KASSERT(uvp
!= NULLVP
);
1379 KASSERT(lvp
!= NULLVP
);
1380 if (uio
->uio_offset
== 0)
1381 unsp
->uns_readdir_status
= 0;
1383 if (unsp
->uns_readdir_status
== 0) {
1385 error
= VOP_READDIR(uvp
, uio
, ap
->a_cred
, &eofflag
,
1386 ap
->a_cookies
, ap
->a_ncookies
);
1388 if (error
!= 0 || eofflag
== 0)
1389 goto unionfs_readdir_exit
;
1390 unsp
->uns_readdir_status
= 1;
1393 * ufs(and other fs) needs size of uio_resid larger than
1395 * size of DIRBLKSIZ equals DEV_BSIZE.
1396 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1398 if (uio
->uio_resid
<= (uio
->uio_resid
& (DEV_BSIZE
-1)))
1399 goto unionfs_readdir_exit
;
1403 * It prepares to readdir in lower.
1405 if (ap
->a_ncookies
!= NULL
) {
1406 ncookies_bk
= *(ap
->a_ncookies
);
1407 *(ap
->a_ncookies
) = 0;
1409 if (ap
->a_cookies
!= NULL
) {
1410 cookies_bk
= *(ap
->a_cookies
);
1411 *(ap
->a_cookies
) = NULL
;
1415 /* initialize for readdir in lower */
1416 if (unsp
->uns_readdir_status
== 1) {
1417 unsp
->uns_readdir_status
= 2;
1418 uio
->uio_offset
= 0;
1421 if (lvp
== NULLVP
) {
1423 goto unionfs_readdir_exit
;
1426 error
= VOP_READDIR(lvp
, uio
, ap
->a_cred
, ap
->a_eofflag
,
1427 ap
->a_cookies
, ap
->a_ncookies
);
1429 if (cookies_bk
!= NULL
) {
1432 off_t
*newcookies
, *pos
;
1434 size
= *(ap
->a_ncookies
) + ncookies_bk
;
1435 newcookies
= (off_t
*) malloc(size
* sizeof(off_t
),
1439 memcpy(pos
, cookies_bk
, ncookies_bk
* sizeof(off_t
));
1440 pos
+= ncookies_bk
* sizeof(off_t
);
1441 memcpy(pos
, *(ap
->a_cookies
), *(ap
->a_ncookies
) * sizeof(off_t
));
1442 free(cookies_bk
, M_TEMP
);
1443 free(*(ap
->a_cookies
), M_TEMP
);
1444 *(ap
->a_ncookies
) = size
;
1445 *(ap
->a_cookies
) = newcookies
;
1448 unionfs_readdir_exit
:
1449 if (error
!= 0 && ap
->a_eofflag
!= NULL
)
1450 *(ap
->a_eofflag
) = 1;
1452 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error
);
1458 unionfs_readlink(void *v
)
1460 struct vop_readlink_args
*ap
= v
;
1462 struct unionfs_node
*unp
;
1465 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
1467 unp
= VTOUNIONFS(ap
->a_vp
);
1468 vp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1470 error
= VOP_READLINK(vp
, ap
->a_uio
, ap
->a_cred
);
1472 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error
);
1478 unionfs_inactive(void *v
)
1480 struct vop_inactive_args
*ap
= v
;
1481 *ap
->a_recycle
= true;
1482 VOP_UNLOCK(ap
->a_vp
, 0);
1487 unionfs_reclaim(void *v
)
1489 struct vop_reclaim_args
*ap
= v
;
1491 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
1493 unionfs_noderem(ap
->a_vp
);
1495 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
1501 unionfs_print(void *v
)
1503 struct vop_print_args
*ap
= v
;
1504 struct unionfs_node
*unp
;
1505 /* struct unionfs_node_status *unsp; */
1507 unp
= VTOUNIONFS(ap
->a_vp
);
1508 /* unionfs_get_node_status(unp, &unsp); */
1510 printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
1511 ap
->a_vp
, unp
->un_uppervp
, unp
->un_lowervp
);
1513 printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
1514 unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
1517 if (unp
->un_uppervp
!= NULLVP
)
1518 vprint("unionfs: upper", unp
->un_uppervp
);
1519 if (unp
->un_lowervp
!= NULLVP
)
1520 vprint("unionfs: lower", unp
->un_lowervp
);
1526 unionfs_lock(void *v
)
1528 struct vop_lock_args
*ap
= v
;
1533 struct unionfs_node
*unp
;
1535 unp
= VTOUNIONFS(ap
->a_vp
);
1536 lvp
= unp
->un_lowervp
;
1537 uvp
= unp
->un_uppervp
;
1538 flags
= ap
->a_flags
;
1541 if ((flags
& LK_INTERLOCK
) != 0) {
1542 mutex_exit(&ap
->a_vp
->v_interlock
);
1543 flags
&= ~LK_INTERLOCK
;
1546 if (lvp
!= NULLVP
) {
1547 error
= VOP_LOCK(lvp
, flags
);
1549 if (error
== 0 && uvp
!= NULLVP
) {
1550 error
= VOP_LOCK(uvp
, flags
);
1560 unionfs_unlock(void *v
)
1562 struct vop_unlock_args
*ap
= v
;
1566 struct unionfs_node
*unp
;
1568 unp
= VTOUNIONFS(ap
->a_vp
);
1569 lvp
= unp
->un_lowervp
;
1570 uvp
= unp
->un_uppervp
;
1573 if (lvp
!= NULLVP
) {
1574 error
= VOP_UNLOCK(lvp
, ap
->a_flags
);
1576 if (error
== 0 && uvp
!= NULLVP
) {
1577 error
= VOP_UNLOCK(uvp
, ap
->a_flags
);
1584 unionfs_pathconf(void *v
)
1586 struct vop_pathconf_args
*ap
= v
;
1587 struct unionfs_node
*unp
;
1590 unp
= VTOUNIONFS(ap
->a_vp
);
1591 vp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1593 return (VOP_PATHCONF(vp
, ap
->a_name
, ap
->a_retval
));
1597 unionfs_advlock(void *v
)
1599 struct vop_advlock_args
*ap
= v
;
1601 struct unionfs_node
*unp
;
1602 struct unionfs_node_status
*unsp
;
1607 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
1610 cred
= kauth_cred_get();
1612 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
1614 unp
= VTOUNIONFS(ap
->a_vp
);
1615 uvp
= unp
->un_uppervp
;
1617 if (uvp
== NULLVP
) {
1618 error
= unionfs_copyfile(unp
, 1, cred
);
1620 goto unionfs_advlock_abort
;
1621 uvp
= unp
->un_uppervp
;
1623 unionfs_get_node_status(unp
, &unsp
);
1624 if (unsp
->uns_lower_opencnt
> 0) {
1625 /* try reopen the vnode */
1626 error
= VOP_OPEN(uvp
, unsp
->uns_lower_openmode
, cred
);
1628 goto unionfs_advlock_abort
;
1629 unsp
->uns_upper_opencnt
++;
1630 VOP_CLOSE(unp
->un_lowervp
, unsp
->uns_lower_openmode
, cred
);
1631 unsp
->uns_lower_opencnt
--;
1633 unionfs_tryrem_node_status(unp
, unsp
);
1638 error
= VOP_ADVLOCK(uvp
, ap
->a_id
, ap
->a_op
, ap
->a_fl
, ap
->a_flags
);
1640 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error
);
1644 unionfs_advlock_abort
:
1647 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error
);
1653 unionfs_strategy(void *v
)
1655 struct vop_strategy_args
*ap
= v
;
1656 struct unionfs_node
*unp
;
1659 unp
= VTOUNIONFS(ap
->a_vp
);
1660 vp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1664 panic("unionfs_strategy: nullvp");
1665 if ((ap
->a_bp
->b_flags
& B_READ
) == 0 && vp
== unp
->un_lowervp
)
1666 panic("unionfs_strategy: writing to lowervp");
1669 return (VOP_STRATEGY(vp
, ap
->a_bp
));
1673 unionfs_kqfilter(void *v
)
1675 struct vop_kqfilter_args
*ap
= v
;
1676 struct unionfs_node
*unp
;
1679 unp
= VTOUNIONFS(ap
->a_vp
);
1680 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1682 return VOP_KQFILTER(tvp
, ap
->a_kn
);
1686 unionfs_bmap(void *v
)
1688 struct vop_bmap_args
*ap
= v
;
1689 struct unionfs_node
*unp
;
1692 unp
= VTOUNIONFS(ap
->a_vp
);
1693 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1695 return VOP_BMAP(tvp
, ap
->a_bn
, ap
->a_vpp
, ap
->a_bnp
, ap
->a_runp
);
1699 unionfs_mmap(void *v
)
1701 struct vop_mmap_args
*ap
= v
;
1702 struct unionfs_node
*unp
;
1705 unp
= VTOUNIONFS(ap
->a_vp
);
1706 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1708 return VOP_MMAP(tvp
, ap
->a_prot
, ap
->a_cred
);
1712 unionfs_abortop(void *v
)
1714 struct vop_abortop_args
*ap
= v
;
1715 struct unionfs_node
*unp
;
1718 unp
= VTOUNIONFS(ap
->a_dvp
);
1719 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1721 return VOP_ABORTOP(tvp
, ap
->a_cnp
);
1725 unionfs_islocked(void *v
)
1727 struct vop_islocked_args
*ap
= v
;
1728 struct unionfs_node
*unp
;
1731 unp
= VTOUNIONFS(ap
->a_vp
);
1732 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1734 return VOP_ISLOCKED(tvp
);
1738 unionfs_seek(void *v
)
1740 struct vop_seek_args
*ap
= v
;
1741 struct unionfs_node
*unp
;
1744 unp
= VTOUNIONFS(ap
->a_vp
);
1745 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1747 return VOP_SEEK(tvp
, ap
->a_oldoff
, ap
->a_newoff
, ap
->a_cred
);
1751 unionfs_putpages(void *v
)
1753 struct vop_putpages_args
*ap
= v
;
1754 struct unionfs_node
*unp
;
1757 unp
= VTOUNIONFS(ap
->a_vp
);
1758 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1760 mutex_exit(&ap
->a_vp
->v_interlock
);
1761 if (ap
->a_flags
& PGO_RECLAIM
) {
1764 mutex_enter(&tvp
->v_interlock
);
1766 return VOP_PUTPAGES(tvp
, ap
->a_offlo
, ap
->a_offhi
, ap
->a_flags
);
1770 unionfs_getpages(void *v
)
1772 struct vop_getpages_args
*ap
= v
;
1773 struct unionfs_node
*unp
;
1776 unp
= VTOUNIONFS(ap
->a_vp
);
1777 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1779 if (ap
->a_flags
& PGO_LOCKED
) {
1782 mutex_exit(&ap
->a_vp
->v_interlock
);
1783 mutex_enter(&tvp
->v_interlock
);
1785 return VOP_GETPAGES(tvp
, ap
->a_offset
, ap
->a_m
, ap
->a_count
,
1786 ap
->a_centeridx
, ap
->a_access_type
, ap
->a_advice
, ap
->a_flags
);
1790 unionfs_revoke(void *v
)
1792 struct vop_revoke_args
*ap
= v
;
1793 struct unionfs_node
*unp
;
1797 unp
= VTOUNIONFS(ap
->a_vp
);
1798 tvp
= (unp
->un_uppervp
!= NULLVP
? unp
->un_uppervp
: unp
->un_lowervp
);
1800 error
= VOP_REVOKE(tvp
, ap
->a_flags
);
1802 vgone(ap
->a_vp
); /* ??? */
1808 * Global vfs data structures
1810 int (**unionfs_vnodeop_p
)(void *);
1811 const struct vnodeopv_entry_desc unionfs_vnodeop_entries
[] = {
1812 { &vop_default_desc
, vn_default_error
},
1813 { &vop_lookup_desc
, unionfs_lookup
}, /* lookup */
1814 { &vop_create_desc
, unionfs_create
}, /* create */
1815 { &vop_whiteout_desc
, unionfs_whiteout
}, /* whiteout */
1816 { &vop_mknod_desc
, unionfs_mknod
}, /* mknod */
1817 { &vop_open_desc
, unionfs_open
}, /* open */
1818 { &vop_close_desc
, unionfs_close
}, /* close */
1819 { &vop_access_desc
, unionfs_access
}, /* access */
1820 { &vop_getattr_desc
, unionfs_getattr
}, /* getattr */
1821 { &vop_setattr_desc
, unionfs_setattr
}, /* setattr */
1822 { &vop_read_desc
, unionfs_read
}, /* read */
1823 { &vop_write_desc
, unionfs_write
}, /* write */
1824 { &vop_ioctl_desc
, unionfs_ioctl
}, /* ioctl */
1825 { &vop_poll_desc
, unionfs_poll
}, /* select */
1826 { &vop_revoke_desc
, unionfs_revoke
}, /* revoke */
1827 { &vop_mmap_desc
, unionfs_mmap
}, /* mmap */
1828 { &vop_fsync_desc
, unionfs_fsync
}, /* fsync */
1829 { &vop_seek_desc
, unionfs_seek
}, /* seek */
1830 { &vop_remove_desc
, unionfs_remove
}, /* remove */
1831 { &vop_link_desc
, unionfs_link
}, /* link */
1832 { &vop_rename_desc
, unionfs_rename
}, /* rename */
1833 { &vop_mkdir_desc
, unionfs_mkdir
}, /* mkdir */
1834 { &vop_rmdir_desc
, unionfs_rmdir
}, /* rmdir */
1835 { &vop_symlink_desc
, unionfs_symlink
}, /* symlink */
1836 { &vop_readdir_desc
, unionfs_readdir
}, /* readdir */
1837 { &vop_readlink_desc
, unionfs_readlink
}, /* readlink */
1838 { &vop_abortop_desc
, unionfs_abortop
}, /* abortop */
1839 { &vop_inactive_desc
, unionfs_inactive
}, /* inactive */
1840 { &vop_reclaim_desc
, unionfs_reclaim
}, /* reclaim */
1841 { &vop_lock_desc
, unionfs_lock
}, /* lock */
1842 { &vop_unlock_desc
, unionfs_unlock
}, /* unlock */
1843 { &vop_bmap_desc
, unionfs_bmap
}, /* bmap */
1844 { &vop_strategy_desc
, unionfs_strategy
}, /* strategy */
1845 { &vop_print_desc
, unionfs_print
}, /* print */
1846 { &vop_islocked_desc
, unionfs_islocked
}, /* islocked */
1847 { &vop_pathconf_desc
, unionfs_pathconf
}, /* pathconf */
1848 { &vop_advlock_desc
, unionfs_advlock
}, /* advlock */
1849 { &vop_getpages_desc
, unionfs_getpages
}, /* getpages */
1850 { &vop_putpages_desc
, unionfs_putpages
}, /* putpages */
1851 { &vop_kqfilter_desc
, unionfs_kqfilter
}, /* kqfilter */
1853 { &vop_bwrite_desc
, unionfs_bwrite
}, /* bwrite */
1857 const struct vnodeopv_desc unionfs_vnodeop_opv_desc
=
1858 { &unionfs_vnodeop_p
, unionfs_vnodeop_entries
};