2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
5 * Copyright (c) 1992, 1993, 1994, 1995
6 * The Regents of the University of California.
7 * Copyright (c) 2005, 2006, 2012 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
8 * Copyright (c) 2006, 2012 Daichi Goto <daichi@freebsd.org>
11 * This code is derived from software contributed to Berkeley by
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95
43 #include <sys/param.h>
44 #include <sys/systm.h>
46 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #include <sys/mount.h>
50 #include <sys/mutex.h>
51 #include <sys/namei.h>
52 #include <sys/sysctl.h>
53 #include <sys/vnode.h>
55 #include <sys/fcntl.h>
57 #include <sys/dirent.h>
62 #include <fs/unionfs/union.h>
64 #include <machine/atomic.h>
67 #include <vm/vm_extern.h>
68 #include <vm/vm_object.h>
69 #include <vm/vnode_pager.h>
72 #define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args)
73 #define UNIONFS_IDBG_RENAME
75 #define UNIONFS_INTERNAL_DEBUG(msg, args...)
78 #define KASSERT_UNIONFS_VNODE(vp) \
79 VNASSERT(((vp)->v_op == &unionfs_vnodeops), vp, \
80 ("%s: non-unionfs vnode", __func__))
83 unionfs_lookup(struct vop_cachedlookup_args *ap)
85 struct unionfs_node *dunp;
86 struct vnode *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp;
88 struct componentname *cnp;
91 u_long cnflags, cnflagsbk;
94 int error , uerror, lerror;
98 error = uerror = lerror = ENOENT;
100 nameiop = cnp->cn_nameiop;
101 cnflags = cnp->cn_flags;
103 dunp = VTOUNIONFS(dvp);
104 udvp = dunp->un_uppervp;
105 ldvp = dunp->un_lowervp;
106 vp = uvp = lvp = NULLVP;
108 *(ap->a_vpp) = NULLVP;
110 UNIONFS_INTERNAL_DEBUG(
111 "unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n",
112 nameiop, cnflags, cnp->cn_nameptr);
114 if (dvp->v_type != VDIR)
118 * If read-only and op is not LOOKUP, will return EROFS.
120 if ((cnflags & ISLASTCN) &&
121 (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
128 if (cnflags & ISDOTDOT) {
129 if (LOOKUP != nameiop && udvp == NULLVP)
132 if (udvp != NULLVP) {
140 error = VOP_LOOKUP(dtmpvp, &vp, cnp);
142 if (dtmpvp == udvp && ldvp != NULLVP) {
144 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
149 * Exchange lock and reference from vp to
150 * dunp->un_dvp. vp is upper/lower vnode, but it
151 * will need to return the unionfs vnode.
153 if (nameiop == DELETE || nameiop == RENAME ||
154 (cnp->cn_lkflags & LK_TYPE_MASK))
159 *(ap->a_vpp) = dunp->un_dvp;
162 if (nameiop == DELETE || nameiop == RENAME)
163 vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY);
164 else if (cnp->cn_lkflags & LK_TYPE_MASK)
165 vn_lock(dunp->un_dvp, cnp->cn_lkflags |
168 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
169 } else if (error == ENOENT && (cnflags & MAKEENTRY) != 0)
170 cache_enter(dvp, NULLVP, cnp);
172 goto unionfs_lookup_return;
178 if (udvp != NULLVP) {
179 uerror = VOP_LOOKUP(udvp, &uvp, cnp);
182 if (udvp == uvp) { /* is dot */
188 goto unionfs_lookup_return;
190 if (nameiop == DELETE || nameiop == RENAME ||
191 (cnp->cn_lkflags & LK_TYPE_MASK))
196 if (uerror == ENOENT || uerror == EJUSTRETURN)
197 if (cnp->cn_flags & ISWHITEOUT)
198 iswhiteout = 1; /* don't lookup lower */
199 if (iswhiteout == 0 && ldvp != NULLVP)
200 if (!VOP_GETATTR(udvp, &va, cnp->cn_cred) &&
201 (va.va_flags & OPAQUE))
202 iswhiteout = 1; /* don't lookup lower */
204 UNIONFS_INTERNAL_DEBUG(
205 "unionfs_lookup: debug: whiteout=%d, path=%s\n",
206 iswhiteout, cnp->cn_nameptr);
213 if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) {
214 /* always op is LOOKUP */
215 cnp->cn_nameiop = LOOKUP;
216 cnflagsbk = cnp->cn_flags;
217 cnp->cn_flags = cnflags;
219 lerror = VOP_LOOKUP(ldvp, &lvp, cnp);
221 cnp->cn_nameiop = nameiop;
222 if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN))
223 cnp->cn_flags = cnflagsbk;
226 if (ldvp == lvp) { /* is dot */
228 vrele(uvp); /* no need? */
233 UNIONFS_INTERNAL_DEBUG(
234 "unionfs_lookup: leave (%d)\n", lerror);
238 if (cnp->cn_lkflags & LK_TYPE_MASK)
244 * check lookup result
246 if (uvp == NULLVP && lvp == NULLVP) {
247 error = (udvp != NULLVP ? uerror : lerror);
248 goto unionfs_lookup_return;
254 if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) {
262 if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP &&
263 lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR &&
264 !(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
265 (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) {
266 /* get unionfs vnode in order to create a new shadow dir. */
267 error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp,
270 goto unionfs_lookup_cleanup;
272 if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK))
274 if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) {
275 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
278 error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
279 udvp, VTOUNIONFS(vp), cnp, td);
284 "unionfs_lookup: Unable to create shadow dir.");
285 if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE)
289 goto unionfs_lookup_cleanup;
291 if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED)
292 vn_lock(vp, LK_SHARED | LK_RETRY);
303 goto unionfs_lookup_cleanup;
307 if (uvp != NULLVP && uvp->v_type == VSOCK) {
310 if (cnp->cn_lkflags & LK_TYPE_MASK)
311 vn_lock(vp, cnp->cn_lkflags | LK_RETRY);
313 else if (lvp != NULLVP && lvp->v_type == VSOCK) {
316 if (cnp->cn_lkflags & LK_TYPE_MASK)
317 vn_lock(vp, cnp->cn_lkflags | LK_RETRY);
323 error = unionfs_nodeget(dvp->v_mount, uvp, lvp,
327 "unionfs_lookup: Unable to create unionfs vnode.");
328 goto unionfs_lookup_cleanup;
330 if ((nameiop == DELETE || nameiop == RENAME) &&
331 (cnp->cn_lkflags & LK_TYPE_MASK) == 0)
332 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
337 if ((cnflags & MAKEENTRY) && vp->v_type != VSOCK)
338 cache_enter(dvp, vp, cnp);
340 unionfs_lookup_cleanup:
346 if (error == ENOENT && (cnflags & MAKEENTRY) != 0)
347 cache_enter(dvp, NULLVP, cnp);
349 unionfs_lookup_return:
351 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
357 unionfs_create(struct vop_create_args *ap)
359 struct unionfs_node *dunp;
360 struct componentname *cnp;
365 UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");
367 KASSERT_UNIONFS_VNODE(ap->a_dvp);
369 dunp = VTOUNIONFS(ap->a_dvp);
371 udvp = dunp->un_uppervp;
374 if (udvp != NULLVP) {
375 error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap);
377 goto unionfs_create_abort;
379 if (vp->v_type == VSOCK)
383 error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
384 ap->a_dvp, ap->a_vpp, cnp);
389 unionfs_create_abort:
390 UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error);
396 unionfs_whiteout(struct vop_whiteout_args *ap)
398 struct unionfs_node *dunp;
399 struct componentname *cnp;
403 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n");
405 KASSERT_UNIONFS_VNODE(ap->a_dvp);
407 dunp = VTOUNIONFS(ap->a_dvp);
409 udvp = dunp->un_uppervp;
412 if (udvp != NULLVP) {
413 switch (ap->a_flags) {
417 error = VOP_WHITEOUT(udvp, cnp, ap->a_flags);
425 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error);
431 unionfs_mknod(struct vop_mknod_args *ap)
433 struct unionfs_node *dunp;
434 struct componentname *cnp;
439 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n");
441 KASSERT_UNIONFS_VNODE(ap->a_dvp);
443 dunp = VTOUNIONFS(ap->a_dvp);
445 udvp = dunp->un_uppervp;
448 if (udvp != NULLVP) {
449 error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap);
451 goto unionfs_mknod_abort;
453 if (vp->v_type == VSOCK)
457 error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
458 ap->a_dvp, ap->a_vpp, cnp);
464 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error);
469 enum unionfs_lkupgrade {
470 UNIONFS_LKUPGRADE_SUCCESS, /* lock successfully upgraded */
471 UNIONFS_LKUPGRADE_ALREADY, /* lock already held exclusive */
472 UNIONFS_LKUPGRADE_DOOMED /* lock was upgraded, but vnode reclaimed */
475 static inline enum unionfs_lkupgrade
476 unionfs_upgrade_lock(struct vnode *vp)
478 ASSERT_VOP_LOCKED(vp, __func__);
480 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
481 return (UNIONFS_LKUPGRADE_ALREADY);
483 if (vn_lock(vp, LK_UPGRADE) != 0) {
484 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
485 if (VN_IS_DOOMED(vp))
486 return (UNIONFS_LKUPGRADE_DOOMED);
488 return (UNIONFS_LKUPGRADE_SUCCESS);
492 unionfs_downgrade_lock(struct vnode *vp, enum unionfs_lkupgrade status)
494 if (status != UNIONFS_LKUPGRADE_ALREADY)
495 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
499 unionfs_open(struct vop_open_args *ap)
501 struct unionfs_node *unp;
502 struct unionfs_node_status *unsp;
506 struct vnode *targetvp;
510 enum unionfs_lkupgrade lkstatus;
512 UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n");
514 KASSERT_UNIONFS_VNODE(ap->a_vp);
523 * The executable loader path may call this function with vp locked
524 * shared. If the vnode is reclaimed while upgrading, we can't safely
525 * use unp or do anything else unionfs- specific.
527 lkstatus = unionfs_upgrade_lock(vp);
528 if (lkstatus == UNIONFS_LKUPGRADE_DOOMED) {
530 goto unionfs_open_cleanup;
533 unp = VTOUNIONFS(vp);
534 uvp = unp->un_uppervp;
535 lvp = unp->un_lowervp;
536 unionfs_get_node_status(unp, td, &unsp);
538 if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) {
539 /* vnode is already opend. */
540 if (unsp->uns_upper_opencnt > 0)
545 if (targetvp == lvp &&
546 (ap->a_mode & FWRITE) && lvp->v_type == VREG)
549 if (targetvp == NULLVP) {
551 if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) {
552 error = unionfs_copyfile(unp,
553 !(ap->a_mode & O_TRUNC), cred, td);
555 goto unionfs_open_abort;
556 targetvp = uvp = unp->un_uppervp;
563 error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp);
565 if (targetvp == uvp) {
566 if (uvp->v_type == VDIR && lvp != NULLVP &&
567 unsp->uns_lower_opencnt <= 0) {
568 /* open lower for readdir */
569 error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
571 VOP_CLOSE(uvp, ap->a_mode, cred, td);
572 goto unionfs_open_abort;
574 unsp->uns_node_flag |= UNS_OPENL_4_READDIR;
575 unsp->uns_lower_opencnt++;
577 unsp->uns_upper_opencnt++;
579 unsp->uns_lower_opencnt++;
580 unsp->uns_lower_openmode = ap->a_mode;
582 vp->v_object = targetvp->v_object;
587 unionfs_tryrem_node_status(unp, unsp);
589 unionfs_open_cleanup:
590 unionfs_downgrade_lock(vp, lkstatus);
592 UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error);
598 unionfs_close(struct vop_close_args *ap)
600 struct unionfs_node *unp;
601 struct unionfs_node_status *unsp;
607 enum unionfs_lkupgrade lkstatus;;
609 UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");
611 KASSERT_UNIONFS_VNODE(ap->a_vp);
619 * If the vnode is reclaimed while upgrading, we can't safely use unp
620 * or do anything else unionfs- specific.
622 lkstatus = unionfs_upgrade_lock(vp);
623 if (lkstatus == UNIONFS_LKUPGRADE_DOOMED)
624 goto unionfs_close_cleanup;
626 unp = VTOUNIONFS(vp);
627 unionfs_get_node_status(unp, td, &unsp);
629 if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) {
631 printf("unionfs_close: warning: open count is 0\n");
633 if (unp->un_uppervp != NULLVP)
634 ovp = unp->un_uppervp;
636 ovp = unp->un_lowervp;
637 } else if (unsp->uns_upper_opencnt > 0)
638 ovp = unp->un_uppervp;
640 ovp = unp->un_lowervp;
642 error = VOP_CLOSE(ovp, ap->a_fflag, cred, td);
645 goto unionfs_close_abort;
647 vp->v_object = ovp->v_object;
649 if (ovp == unp->un_uppervp) {
650 unsp->uns_upper_opencnt--;
651 if (unsp->uns_upper_opencnt == 0) {
652 if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) {
653 VOP_CLOSE(unp->un_lowervp, FREAD, cred, td);
654 unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR;
655 unsp->uns_lower_opencnt--;
657 if (unsp->uns_lower_opencnt > 0)
658 vp->v_object = unp->un_lowervp->v_object;
661 unsp->uns_lower_opencnt--;
664 unionfs_tryrem_node_status(unp, unsp);
666 unionfs_close_cleanup:
667 unionfs_downgrade_lock(vp, lkstatus);
669 UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error);
675 * Check the access mode toward shadow file/dir.
678 unionfs_check_corrected_access(accmode_t accmode, struct vattr *va,
681 uid_t uid; /* upper side vnode's uid */
682 gid_t gid; /* upper side vnode's gid */
683 u_short vmode; /* upper side vnode's mode */
692 if (cred->cr_uid == uid) {
697 if (accmode & VWRITE)
699 return ((vmode & mask) == mask ? 0 : EACCES);
703 if (groupmember(gid, cred)) {
708 if (accmode & VWRITE)
710 return ((vmode & mask) == mask ? 0 : EACCES);
718 if (accmode & VWRITE)
721 return ((vmode & mask) == mask ? 0 : EACCES);
725 unionfs_access(struct vop_access_args *ap)
727 struct unionfs_mount *ump;
728 struct unionfs_node *unp;
736 UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n");
738 KASSERT_UNIONFS_VNODE(ap->a_vp);
740 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
741 unp = VTOUNIONFS(ap->a_vp);
742 uvp = unp->un_uppervp;
743 lvp = unp->un_lowervp;
745 accmode = ap->a_accmode;
748 if ((accmode & VWRITE) &&
749 (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
750 switch (ap->a_vp->v_type) {
761 error = VOP_ACCESS(uvp, accmode, ap->a_cred, td);
763 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
769 if (accmode & VWRITE) {
770 if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) {
771 switch (ap->a_vp->v_type) {
779 } else if (ap->a_vp->v_type == VREG ||
780 ap->a_vp->v_type == VDIR) {
781 /* check shadow file/dir */
782 if (ump->um_copymode != UNIONFS_TRANSPARENT) {
783 error = unionfs_create_uppervattr(ump,
784 lvp, &va, ap->a_cred, td);
788 error = unionfs_check_corrected_access(
789 accmode, &va, ap->a_cred);
794 accmode &= ~(VWRITE | VAPPEND);
795 accmode |= VREAD; /* will copy to upper */
797 error = VOP_ACCESS(lvp, accmode, ap->a_cred, td);
800 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
806 unionfs_getattr(struct vop_getattr_args *ap)
808 struct unionfs_node *unp;
809 struct unionfs_mount *ump;
816 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
818 KASSERT_UNIONFS_VNODE(ap->a_vp);
820 unp = VTOUNIONFS(ap->a_vp);
821 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
822 uvp = unp->un_uppervp;
823 lvp = unp->un_lowervp;
827 if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0)
829 ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
831 UNIONFS_INTERNAL_DEBUG(
832 "unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
833 ap->a_vap->va_mode, ap->a_vap->va_uid,
834 ap->a_vap->va_gid, error);
839 error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred);
841 if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) {
842 /* correct the attr toward shadow file/dir. */
843 if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
844 unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td);
845 ap->a_vap->va_mode = va.va_mode;
846 ap->a_vap->va_uid = va.va_uid;
847 ap->a_vap->va_gid = va.va_gid;
852 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
854 UNIONFS_INTERNAL_DEBUG(
855 "unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
856 ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error);
862 unionfs_setattr(struct vop_setattr_args *ap)
864 struct unionfs_node *unp;
871 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n");
873 KASSERT_UNIONFS_VNODE(ap->a_vp);
876 unp = VTOUNIONFS(ap->a_vp);
877 uvp = unp->un_uppervp;
878 lvp = unp->un_lowervp;
882 if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
883 (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
884 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
885 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL))
888 if (uvp == NULLVP && lvp->v_type == VREG) {
889 error = unionfs_copyfile(unp, (vap->va_size != 0),
893 uvp = unp->un_uppervp;
897 error = VOP_SETATTR(uvp, vap, ap->a_cred);
899 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error);
905 unionfs_read(struct vop_read_args *ap)
907 struct unionfs_node *unp;
911 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */
913 KASSERT_UNIONFS_VNODE(ap->a_vp);
915 unp = VTOUNIONFS(ap->a_vp);
916 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
918 error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
920 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */
926 unionfs_write(struct vop_write_args *ap)
928 struct unionfs_node *unp;
932 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */
934 KASSERT_UNIONFS_VNODE(ap->a_vp);
936 unp = VTOUNIONFS(ap->a_vp);
937 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
939 error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
941 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */
947 unionfs_ioctl(struct vop_ioctl_args *ap)
949 struct unionfs_node *unp;
950 struct unionfs_node_status *unsp;
954 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n");
956 KASSERT_UNIONFS_VNODE(ap->a_vp);
958 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
959 unp = VTOUNIONFS(ap->a_vp);
960 unionfs_get_node_status(unp, ap->a_td, &unsp);
961 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
962 unionfs_tryrem_node_status(unp, unsp);
963 VOP_UNLOCK(ap->a_vp);
968 error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag,
969 ap->a_cred, ap->a_td);
971 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error);
977 unionfs_poll(struct vop_poll_args *ap)
979 struct unionfs_node *unp;
980 struct unionfs_node_status *unsp;
983 KASSERT_UNIONFS_VNODE(ap->a_vp);
985 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
986 unp = VTOUNIONFS(ap->a_vp);
987 unionfs_get_node_status(unp, ap->a_td, &unsp);
988 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
989 unionfs_tryrem_node_status(unp, unsp);
990 VOP_UNLOCK(ap->a_vp);
995 return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td));
999 unionfs_fsync(struct vop_fsync_args *ap)
1001 struct unionfs_node *unp;
1002 struct unionfs_node_status *unsp;
1005 KASSERT_UNIONFS_VNODE(ap->a_vp);
1007 unp = VTOUNIONFS(ap->a_vp);
1008 unionfs_get_node_status(unp, ap->a_td, &unsp);
1009 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
1010 unionfs_tryrem_node_status(unp, unsp);
1015 return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td));
1019 unionfs_remove(struct vop_remove_args *ap)
1022 struct unionfs_node *dunp;
1023 struct unionfs_node *unp;
1024 struct unionfs_mount *ump;
1029 struct componentname *cnp;
1030 struct componentname cn;
1035 UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n");
1037 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1040 dunp = VTOUNIONFS(ap->a_dvp);
1041 udvp = dunp->un_uppervp;
1045 if (ap->a_vp->v_op != &unionfs_vnodeops) {
1046 if (ap->a_vp->v_type != VSOCK)
1049 vp = uvp = lvp = NULLVP;
1051 VOP_UNLOCK(ap->a_vp);
1052 error = unionfs_relookup(udvp, &vp, cnp, &cn, td,
1053 cnp->cn_nameptr, cnp->cn_namelen, DELETE);
1054 if (error != 0 && error != ENOENT) {
1055 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1059 if (error == 0 && vp == ap->a_vp) {
1060 /* target vnode in upper */
1064 /* target vnode in lower */
1071 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1074 path = cnp->cn_nameptr;
1075 pathlen = cnp->cn_namelen;
1077 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1078 unp = VTOUNIONFS(ap->a_vp);
1079 uvp = unp->un_uppervp;
1080 lvp = unp->un_lowervp;
1081 path = unp->un_path;
1082 pathlen = unp->un_pathlen;
1088 if (uvp != NULLVP) {
1090 * XXX: if the vnode type is VSOCK, it will create whiteout
1093 if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS ||
1095 cnp->cn_flags |= DOWHITEOUT;
1096 error = VOP_REMOVE(udvp, uvp, cnp);
1097 } else if (lvp != NULLVP)
1098 error = unionfs_mkwhiteout(udvp, cnp, td, path, pathlen);
1100 UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error);
1106 unionfs_link(struct vop_link_args *ap)
1108 struct unionfs_node *dunp;
1109 struct unionfs_node *unp;
1112 struct componentname *cnp;
1117 UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");
1119 KASSERT_UNIONFS_VNODE(ap->a_tdvp);
1120 KASSERT_UNIONFS_VNODE(ap->a_vp);
1124 dunp = VTOUNIONFS(ap->a_tdvp);
1126 udvp = dunp->un_uppervp;
1134 if (ap->a_vp->v_op != &unionfs_vnodeops)
1137 unp = VTOUNIONFS(ap->a_vp);
1139 if (unp->un_uppervp == NULLVP) {
1140 if (ap->a_vp->v_type != VREG)
1141 return (EOPNOTSUPP);
1143 error = unionfs_copyfile(unp, 1, cnp->cn_cred, td);
1148 uvp = unp->un_uppervp;
1151 if (needrelookup != 0)
1152 error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td);
1155 error = VOP_LINK(udvp, uvp, cnp);
1157 UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error);
1163 unionfs_rename(struct vop_rename_args *ap)
1167 struct componentname *fcnp;
1170 struct componentname *tcnp;
1171 struct vnode *ltdvp;
1175 /* rename target vnodes */
1176 struct vnode *rfdvp;
1178 struct vnode *rtdvp;
1181 struct unionfs_mount *ump;
1182 struct unionfs_node *unp;
1186 UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n");
1204 /* check for cross device rename */
1205 if (fvp->v_mount != tdvp->v_mount ||
1206 (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) {
1207 if (fvp->v_op != &unionfs_vnodeops)
1211 goto unionfs_rename_abort;
1214 /* Renaming a file to itself has no effect. */
1216 goto unionfs_rename_abort;
1219 * from/to vnode is unionfs node.
1222 KASSERT_UNIONFS_VNODE(fdvp);
1223 KASSERT_UNIONFS_VNODE(fvp);
1224 KASSERT_UNIONFS_VNODE(tdvp);
1226 KASSERT_UNIONFS_VNODE(tvp);
1228 unp = VTOUNIONFS(fdvp);
1229 #ifdef UNIONFS_IDBG_RENAME
1230 UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n",
1231 fdvp, unp->un_uppervp, unp->un_lowervp);
1233 if (unp->un_uppervp == NULLVP) {
1235 goto unionfs_rename_abort;
1237 rfdvp = unp->un_uppervp;
1240 unp = VTOUNIONFS(fvp);
1241 #ifdef UNIONFS_IDBG_RENAME
1242 UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n",
1243 fvp, unp->un_uppervp, unp->un_lowervp);
1245 ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount);
1246 if (unp->un_uppervp == NULLVP) {
1247 switch (fvp->v_type) {
1249 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1250 goto unionfs_rename_abort;
1251 error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td);
1254 goto unionfs_rename_abort;
1257 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1258 goto unionfs_rename_abort;
1259 error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td);
1262 goto unionfs_rename_abort;
1266 goto unionfs_rename_abort;
1272 if (unp->un_lowervp != NULLVP)
1273 fcnp->cn_flags |= DOWHITEOUT;
1274 rfvp = unp->un_uppervp;
1277 unp = VTOUNIONFS(tdvp);
1278 #ifdef UNIONFS_IDBG_RENAME
1279 UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n",
1280 tdvp, unp->un_uppervp, unp->un_lowervp);
1282 if (unp->un_uppervp == NULLVP) {
1284 goto unionfs_rename_abort;
1286 rtdvp = unp->un_uppervp;
1287 ltdvp = unp->un_lowervp;
1293 } else if (tvp != NULLVP) {
1294 unp = VTOUNIONFS(tvp);
1295 #ifdef UNIONFS_IDBG_RENAME
1296 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n",
1297 tvp, unp->un_uppervp, unp->un_lowervp);
1299 if (unp->un_uppervp == NULLVP)
1302 if (tvp->v_type == VDIR) {
1304 goto unionfs_rename_abort;
1306 rtvp = unp->un_uppervp;
1307 ltvp = unp->un_lowervp;
1313 goto unionfs_rename_abort;
1315 if (needrelookup != 0) {
1316 if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0)
1317 goto unionfs_rename_abort;
1318 error = unionfs_relookup_for_delete(fdvp, fcnp, td);
1321 goto unionfs_rename_abort;
1323 /* Lock of tvp is canceled in order to avoid recursive lock. */
1324 if (tvp != NULLVP && tvp != tdvp)
1326 error = unionfs_relookup_for_rename(tdvp, tcnp, td);
1327 if (tvp != NULLVP && tvp != tdvp)
1328 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
1330 goto unionfs_rename_abort;
1333 error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
1336 if (rtvp != NULLVP && rtvp->v_type == VDIR)
1338 if (fvp->v_type == VDIR && fdvp != tdvp)
1342 if (ltdvp != NULLVP)
1348 if (tvp != rtvp && tvp != NULLVP) {
1359 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1363 unionfs_rename_abort:
1367 if (tvp != NULLVP) {
1373 if (tvp != rtvp && rtvp != NULLVP)
1382 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1388 unionfs_mkdir(struct vop_mkdir_args *ap)
1390 struct unionfs_node *dunp;
1391 struct componentname *cnp;
1398 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1400 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1403 dunp = VTOUNIONFS(ap->a_dvp);
1405 lkflags = cnp->cn_lkflags;
1406 udvp = dunp->un_uppervp;
1408 if (udvp != NULLVP) {
1410 if (!(cnp->cn_flags & ISWHITEOUT)) {
1411 error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
1414 if ((va.va_flags & OPAQUE) != 0)
1415 cnp->cn_flags |= ISWHITEOUT;
1418 if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) {
1420 cnp->cn_lkflags = LK_EXCLUSIVE;
1421 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1422 ap->a_dvp, ap->a_vpp, cnp);
1423 cnp->cn_lkflags = lkflags;
1428 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
1434 unionfs_rmdir(struct vop_rmdir_args *ap)
1436 struct unionfs_node *dunp;
1437 struct unionfs_node *unp;
1438 struct unionfs_mount *ump;
1439 struct componentname *cnp;
1446 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1448 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1449 KASSERT_UNIONFS_VNODE(ap->a_vp);
1452 dunp = VTOUNIONFS(ap->a_dvp);
1453 unp = VTOUNIONFS(ap->a_vp);
1456 udvp = dunp->un_uppervp;
1457 uvp = unp->un_uppervp;
1458 lvp = unp->un_lowervp;
1464 return (EOPNOTSUPP);
1466 if (uvp != NULLVP) {
1467 if (lvp != NULLVP) {
1468 error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
1472 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1473 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP)
1474 cnp->cn_flags |= DOWHITEOUT;
1476 * The relookup path will need to relock the parent dvp and
1477 * possibly the vp as well. Locking is expected to be done
1478 * in parent->child order; drop the lock on vp to avoid LOR
1479 * and potential recursion on vp's lock.
1480 * vp is expected to remain referenced during VOP_RMDIR(),
1481 * so vref/vrele should not be necessary here.
1483 VOP_UNLOCK(ap->a_vp);
1484 VNPASS(vrefcnt(ap->a_vp) > 0, ap->a_vp);
1485 error = unionfs_relookup_for_delete(ap->a_dvp, cnp, td);
1486 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1488 * VOP_RMDIR is dispatched against udvp, so if uvp became
1489 * doomed while the lock was dropped above the target
1490 * filesystem may not be able to cope.
1492 if (error == 0 && VN_IS_DOOMED(uvp))
1495 error = VOP_RMDIR(udvp, uvp, cnp);
1496 } else if (lvp != NULLVP)
1497 error = unionfs_mkwhiteout(udvp, cnp, td,
1498 unp->un_path, unp->un_pathlen);
1501 cache_purge(ap->a_dvp);
1502 cache_purge(ap->a_vp);
1505 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
1511 unionfs_symlink(struct vop_symlink_args *ap)
1513 struct unionfs_node *dunp;
1514 struct componentname *cnp;
1520 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1522 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1525 dunp = VTOUNIONFS(ap->a_dvp);
1527 lkflags = cnp->cn_lkflags;
1528 udvp = dunp->un_uppervp;
1530 if (udvp != NULLVP) {
1531 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
1534 cnp->cn_lkflags = LK_EXCLUSIVE;
1535 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1536 ap->a_dvp, ap->a_vpp, cnp);
1537 cnp->cn_lkflags = lkflags;
1542 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
1548 unionfs_readdir(struct vop_readdir_args *ap)
1550 struct unionfs_node *unp;
1551 struct unionfs_node_status *unsp;
1559 uint64_t *cookies_bk;
1564 enum unionfs_lkupgrade lkstatus;
1566 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1568 KASSERT_UNIONFS_VNODE(ap->a_vp);
1581 if (vp->v_type != VDIR)
1585 * If the vnode is reclaimed while upgrading, we can't safely use unp
1586 * or do anything else unionfs- specific.
1588 lkstatus = unionfs_upgrade_lock(vp);
1589 if (lkstatus == UNIONFS_LKUPGRADE_DOOMED)
1592 unp = VTOUNIONFS(vp);
1593 uvp = unp->un_uppervp;
1594 lvp = unp->un_lowervp;
1595 /* check the open count. unionfs needs open before readdir. */
1596 unionfs_get_node_status(unp, td, &unsp);
1597 if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) ||
1598 (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) {
1599 unionfs_tryrem_node_status(unp, unsp);
1603 unionfs_downgrade_lock(vp, lkstatus);
1605 goto unionfs_readdir_exit;
1608 if (uvp != NULLVP && lvp != NULLVP) {
1609 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0)
1610 goto unionfs_readdir_exit;
1611 if (va.va_flags & OPAQUE)
1616 if (uvp != NULLVP && lvp == NULLVP) {
1617 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
1618 ap->a_ncookies, ap->a_cookies);
1619 unsp->uns_readdir_status = 0;
1621 goto unionfs_readdir_exit;
1625 if (uvp == NULLVP && lvp != NULLVP) {
1626 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1627 ap->a_ncookies, ap->a_cookies);
1628 unsp->uns_readdir_status = 2;
1630 goto unionfs_readdir_exit;
1634 * readdir upper and lower
1636 KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp"));
1637 KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp"));
1638 if (uio->uio_offset == 0)
1639 unsp->uns_readdir_status = 0;
1641 if (unsp->uns_readdir_status == 0) {
1643 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
1644 ap->a_ncookies, ap->a_cookies);
1646 if (error != 0 || eofflag == 0)
1647 goto unionfs_readdir_exit;
1648 unsp->uns_readdir_status = 1;
1651 * UFS(and other FS) needs size of uio_resid larger than
1653 * size of DIRBLKSIZ equals DEV_BSIZE.
1654 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1656 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
1657 goto unionfs_readdir_exit;
1661 * It prepares to readdir in lower.
1663 if (ap->a_ncookies != NULL) {
1664 ncookies_bk = *(ap->a_ncookies);
1665 *(ap->a_ncookies) = 0;
1667 if (ap->a_cookies != NULL) {
1668 cookies_bk = *(ap->a_cookies);
1669 *(ap->a_cookies) = NULL;
1673 /* initialize for readdir in lower */
1674 if (unsp->uns_readdir_status == 1) {
1675 unsp->uns_readdir_status = 2;
1677 * Backup uio_offset. See the comment after the
1678 * VOP_READDIR call on the lower layer.
1680 uio_offset_bk = uio->uio_offset;
1681 uio->uio_offset = 0;
1684 if (lvp == NULLVP) {
1686 goto unionfs_readdir_exit;
1689 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1690 ap->a_ncookies, ap->a_cookies);
1693 * We can't return an uio_offset of 0: this would trigger an
1694 * infinite loop, because the next call to unionfs_readdir would
1695 * always restart with the upper layer (uio_offset == 0) and
1696 * always return some data.
1698 * This happens when the lower layer root directory is removed.
1699 * (A root directory deleting of unionfs should not be permitted.
1700 * But current VFS can not do it.)
1702 if (uio->uio_offset == 0)
1703 uio->uio_offset = uio_offset_bk;
1705 if (cookies_bk != NULL) {
1708 uint64_t *newcookies, *pos;
1710 size = *(ap->a_ncookies) + ncookies_bk;
1711 newcookies = (uint64_t *) malloc(size * sizeof(*newcookies),
1715 memcpy(pos, cookies_bk, ncookies_bk * sizeof(*newcookies));
1717 memcpy(pos, *(ap->a_cookies),
1718 *(ap->a_ncookies) * sizeof(*newcookies));
1719 free(cookies_bk, M_TEMP);
1720 free(*(ap->a_cookies), M_TEMP);
1721 *(ap->a_ncookies) = size;
1722 *(ap->a_cookies) = newcookies;
1725 unionfs_readdir_exit:
1726 if (error != 0 && ap->a_eofflag != NULL)
1727 *(ap->a_eofflag) = 1;
1729 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
1735 unionfs_readlink(struct vop_readlink_args *ap)
1737 struct unionfs_node *unp;
1741 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
1743 KASSERT_UNIONFS_VNODE(ap->a_vp);
1745 unp = VTOUNIONFS(ap->a_vp);
1746 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1748 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
1750 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
1756 unionfs_getwritemount(struct vop_getwritemount_args *ap)
1758 struct unionfs_node *unp;
1760 struct vnode *vp, *ovp;
1763 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
1770 unp = VTOUNIONFS(vp);
1772 uvp = unp->un_uppervp;
1775 * If our node has no upper vnode, check the parent directory.
1776 * We may be initiating a write operation that will produce a
1777 * new upper vnode through CoW.
1779 if (uvp == NULLVP && unp != NULL) {
1783 * Only the root vnode should have an empty parent, but it
1784 * should not have an empty uppervp, so we shouldn't get here.
1786 VNASSERT(vp != NULL, ovp, ("%s: NULL parent vnode", __func__));
1789 unp = VTOUNIONFS(vp);
1791 uvp = unp->un_uppervp;
1796 if (uvp != NULLVP) {
1799 error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
1803 *(ap->a_mpp) = NULL;
1806 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);
1812 unionfs_inactive(struct vop_inactive_args *ap)
1814 ap->a_vp->v_object = NULL;
1820 unionfs_reclaim(struct vop_reclaim_args *ap)
1822 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
1824 unionfs_noderem(ap->a_vp);
1826 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
1832 unionfs_print(struct vop_print_args *ap)
1834 struct unionfs_node *unp;
1835 /* struct unionfs_node_status *unsp; */
1837 unp = VTOUNIONFS(ap->a_vp);
1838 /* unionfs_get_node_status(unp, curthread, &unsp); */
1840 printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
1841 ap->a_vp, unp->un_uppervp, unp->un_lowervp);
1843 printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
1844 unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
1847 if (unp->un_uppervp != NULLVP)
1848 vn_printf(unp->un_uppervp, "unionfs: upper ");
1849 if (unp->un_lowervp != NULLVP)
1850 vn_printf(unp->un_lowervp, "unionfs: lower ");
1856 unionfs_islocked(struct vop_islocked_args *ap)
1858 struct unionfs_node *unp;
1860 KASSERT_UNIONFS_VNODE(ap->a_vp);
1862 unp = VTOUNIONFS(ap->a_vp);
1864 return (vop_stdislocked(ap));
1866 if (unp->un_uppervp != NULLVP)
1867 return (VOP_ISLOCKED(unp->un_uppervp));
1868 if (unp->un_lowervp != NULLVP)
1869 return (VOP_ISLOCKED(unp->un_lowervp));
1870 return (vop_stdislocked(ap));
1874 unionfs_get_llt_revlock(struct vnode *vp, int flags)
1880 switch (flags & LK_TYPE_MASK) {
1882 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
1883 revlock = LK_UPGRADE;
1885 revlock = LK_RELEASE;
1889 revlock = LK_RELEASE;
1892 revlock = LK_UPGRADE;
1902 * The state of an acquired lock is adjusted similarly to
1903 * the time of error generating.
1904 * flags: LK_RELEASE or LK_UPGRADE
1907 unionfs_revlock(struct vnode *vp, int flags)
1909 if (flags & LK_RELEASE)
1910 VOP_UNLOCK_FLAGS(vp, flags);
1913 if (vn_lock(vp, flags) != 0)
1914 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1919 unionfs_lock(struct vop_lock1_args *ap)
1921 struct unionfs_node *unp;
1932 * TODO: rework the unionfs locking scheme.
1933 * It's not guaranteed to be safe to blindly lock two vnodes on
1934 * different mounts as is done here. Further, the entanglement
1935 * of locking both vnodes with the various options that can be
1936 * passed to VOP_LOCK() makes this code hard to reason about.
1937 * Instead, consider locking only the upper vnode, or the lower
1938 * vnode is the upper is not present, and taking separate measures
1939 * to lock both vnodes in the few cases when that is needed.
1944 flags = ap->a_flags;
1947 if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
1948 return (VOP_UNLOCK_FLAGS(vp, flags | LK_RELEASE));
1950 if ((flags & LK_INTERLOCK) == 0)
1953 unp = VTOUNIONFS(vp);
1955 goto unionfs_lock_null_vnode;
1957 KASSERT_UNIONFS_VNODE(ap->a_vp);
1959 lvp = unp->un_lowervp;
1960 uvp = unp->un_uppervp;
1962 if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0)
1963 panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK);
1966 * During unmount, the root vnode lock may be taken recursively,
1967 * because it may share the same v_vnlock field as the vnode covered by
1968 * the unionfs mount. The covered vnode is locked across VFS_UNMOUNT(),
1969 * and the same lock may be taken recursively here during vflush()
1970 * issued by unionfs_unmount().
1972 if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE &&
1973 (vp->v_vflag & VV_ROOT) != 0)
1974 flags |= LK_CANRECURSE;
1976 if (lvp != NULLVP) {
1977 if (uvp != NULLVP && flags & LK_UPGRADE) {
1979 * Share Lock is once released and a deadlock is
1985 unp = VTOUNIONFS(vp);
1987 /* vnode is released. */
1994 VI_LOCK_FLAGS(lvp, MTX_DUPOK);
1995 flags |= LK_INTERLOCK;
1999 ap->a_flags &= ~LK_INTERLOCK;
2001 error = VOP_LOCK(lvp, flags);
2004 unp = VTOUNIONFS(vp);
2006 /* vnode is released. */
2013 return (vop_stdlock(ap));
2017 if (error == 0 && uvp != NULLVP) {
2018 if (uhold && flags & LK_UPGRADE) {
2019 flags &= ~LK_TYPE_MASK;
2020 flags |= LK_EXCLUSIVE;
2022 VI_LOCK_FLAGS(uvp, MTX_DUPOK);
2023 flags |= LK_INTERLOCK;
2030 ap->a_flags &= ~LK_INTERLOCK;
2032 error = VOP_LOCK(uvp, flags);
2035 unp = VTOUNIONFS(vp);
2037 /* vnode is released. */
2042 if (lvp != NULLVP) {
2046 return (vop_stdlock(ap));
2048 if (error != 0 && lvp != NULLVP) {
2051 unionfs_revlock(lvp, revlock);
2065 unionfs_lock_null_vnode:
2066 ap->a_flags |= LK_INTERLOCK;
2067 return (vop_stdlock(ap));
2071 unionfs_unlock(struct vop_unlock_args *ap)
2076 struct unionfs_node *unp;
2080 KASSERT_UNIONFS_VNODE(ap->a_vp);
2086 unp = VTOUNIONFS(vp);
2088 goto unionfs_unlock_null_vnode;
2089 lvp = unp->un_lowervp;
2090 uvp = unp->un_uppervp;
2092 if (lvp != NULLVP) {
2094 error = VOP_UNLOCK(lvp);
2097 if (error == 0 && uvp != NULLVP) {
2100 error = VOP_UNLOCK(uvp);
2110 unionfs_unlock_null_vnode:
2111 return (vop_stdunlock(ap));
2115 unionfs_pathconf(struct vop_pathconf_args *ap)
2117 struct unionfs_node *unp;
2120 KASSERT_UNIONFS_VNODE(ap->a_vp);
2122 unp = VTOUNIONFS(ap->a_vp);
2123 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2125 return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
2129 unionfs_advlock(struct vop_advlock_args *ap)
2131 struct unionfs_node *unp;
2132 struct unionfs_node_status *unsp;
2138 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
2140 KASSERT_UNIONFS_VNODE(ap->a_vp);
2145 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2147 unp = VTOUNIONFS(ap->a_vp);
2148 uvp = unp->un_uppervp;
2150 if (uvp == NULLVP) {
2151 error = unionfs_copyfile(unp, 1, td->td_ucred, td);
2153 goto unionfs_advlock_abort;
2154 uvp = unp->un_uppervp;
2156 unionfs_get_node_status(unp, td, &unsp);
2157 if (unsp->uns_lower_opencnt > 0) {
2158 /* try reopen the vnode */
2159 error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
2160 td->td_ucred, td, NULL);
2162 goto unionfs_advlock_abort;
2163 unsp->uns_upper_opencnt++;
2164 VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode,
2166 unsp->uns_lower_opencnt--;
2168 unionfs_tryrem_node_status(unp, unsp);
2173 error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
2175 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2179 unionfs_advlock_abort:
2182 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2188 unionfs_strategy(struct vop_strategy_args *ap)
2190 struct unionfs_node *unp;
2193 KASSERT_UNIONFS_VNODE(ap->a_vp);
2195 unp = VTOUNIONFS(ap->a_vp);
2196 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2200 panic("unionfs_strategy: nullvp");
2202 if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
2203 panic("unionfs_strategy: writing to lowervp");
2206 return (VOP_STRATEGY(vp, ap->a_bp));
2210 unionfs_getacl(struct vop_getacl_args *ap)
2212 struct unionfs_node *unp;
2216 KASSERT_UNIONFS_VNODE(ap->a_vp);
2218 unp = VTOUNIONFS(ap->a_vp);
2219 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2221 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
2223 error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2225 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
2231 unionfs_setacl(struct vop_setacl_args *ap)
2233 struct unionfs_node *unp;
2239 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
2241 KASSERT_UNIONFS_VNODE(ap->a_vp);
2244 unp = VTOUNIONFS(ap->a_vp);
2245 uvp = unp->un_uppervp;
2246 lvp = unp->un_lowervp;
2249 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2252 if (uvp == NULLVP && lvp->v_type == VREG) {
2253 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2255 uvp = unp->un_uppervp;
2259 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
2261 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
2267 unionfs_aclcheck(struct vop_aclcheck_args *ap)
2269 struct unionfs_node *unp;
2273 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
2275 KASSERT_UNIONFS_VNODE(ap->a_vp);
2277 unp = VTOUNIONFS(ap->a_vp);
2278 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2280 error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2282 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
2288 unionfs_openextattr(struct vop_openextattr_args *ap)
2290 struct unionfs_node *unp;
2295 KASSERT_UNIONFS_VNODE(ap->a_vp);
2298 unp = VTOUNIONFS(vp);
2299 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2301 if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
2302 (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
2305 error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
2308 if (vn_lock(vp, LK_UPGRADE) != 0)
2309 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2310 if (!VN_IS_DOOMED(vp)) {
2311 if (tvp == unp->un_uppervp)
2312 unp->un_flag |= UNIONFS_OPENEXTU;
2314 unp->un_flag |= UNIONFS_OPENEXTL;
2316 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2323 unionfs_closeextattr(struct vop_closeextattr_args *ap)
2325 struct unionfs_node *unp;
2330 KASSERT_UNIONFS_VNODE(ap->a_vp);
2333 unp = VTOUNIONFS(vp);
2336 if (unp->un_flag & UNIONFS_OPENEXTU)
2337 tvp = unp->un_uppervp;
2338 else if (unp->un_flag & UNIONFS_OPENEXTL)
2339 tvp = unp->un_lowervp;
2342 return (EOPNOTSUPP);
2344 error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
2347 if (vn_lock(vp, LK_UPGRADE) != 0)
2348 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2349 if (!VN_IS_DOOMED(vp)) {
2350 if (tvp == unp->un_uppervp)
2351 unp->un_flag &= ~UNIONFS_OPENEXTU;
2353 unp->un_flag &= ~UNIONFS_OPENEXTL;
2355 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2362 unionfs_getextattr(struct vop_getextattr_args *ap)
2364 struct unionfs_node *unp;
2367 KASSERT_UNIONFS_VNODE(ap->a_vp);
2369 unp = VTOUNIONFS(ap->a_vp);
2372 if (unp->un_flag & UNIONFS_OPENEXTU)
2373 vp = unp->un_uppervp;
2374 else if (unp->un_flag & UNIONFS_OPENEXTL)
2375 vp = unp->un_lowervp;
2378 return (EOPNOTSUPP);
2380 return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
2381 ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
2385 unionfs_setextattr(struct vop_setextattr_args *ap)
2387 struct unionfs_node *unp;
2395 KASSERT_UNIONFS_VNODE(ap->a_vp);
2398 unp = VTOUNIONFS(ap->a_vp);
2399 uvp = unp->un_uppervp;
2400 lvp = unp->un_lowervp;
2405 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n",
2408 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2411 if (unp->un_flag & UNIONFS_OPENEXTU)
2412 ovp = unp->un_uppervp;
2413 else if (unp->un_flag & UNIONFS_OPENEXTL)
2414 ovp = unp->un_lowervp;
2417 return (EOPNOTSUPP);
2419 if (ovp == lvp && lvp->v_type == VREG) {
2420 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2421 if (uvp == NULLVP &&
2422 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2423 unionfs_setextattr_reopen:
2424 if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2425 VOP_OPENEXTATTR(lvp, cred, td)) {
2427 panic("unionfs: VOP_OPENEXTATTR failed");
2429 unp->un_flag &= ~UNIONFS_OPENEXTL;
2431 goto unionfs_setextattr_abort;
2433 uvp = unp->un_uppervp;
2434 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2435 goto unionfs_setextattr_reopen;
2436 unp->un_flag &= ~UNIONFS_OPENEXTL;
2437 unp->un_flag |= UNIONFS_OPENEXTU;
2442 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2443 ap->a_uio, cred, td);
2445 unionfs_setextattr_abort:
2446 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
2452 unionfs_listextattr(struct vop_listextattr_args *ap)
2454 struct unionfs_node *unp;
2457 KASSERT_UNIONFS_VNODE(ap->a_vp);
2459 unp = VTOUNIONFS(ap->a_vp);
2462 if (unp->un_flag & UNIONFS_OPENEXTU)
2463 vp = unp->un_uppervp;
2464 else if (unp->un_flag & UNIONFS_OPENEXTL)
2465 vp = unp->un_lowervp;
2468 return (EOPNOTSUPP);
2470 return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
2471 ap->a_size, ap->a_cred, ap->a_td));
2475 unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
2477 struct unionfs_node *unp;
2485 KASSERT_UNIONFS_VNODE(ap->a_vp);
2488 unp = VTOUNIONFS(ap->a_vp);
2489 uvp = unp->un_uppervp;
2490 lvp = unp->un_lowervp;
2495 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n",
2498 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2501 if (unp->un_flag & UNIONFS_OPENEXTU)
2502 ovp = unp->un_uppervp;
2503 else if (unp->un_flag & UNIONFS_OPENEXTL)
2504 ovp = unp->un_lowervp;
2507 return (EOPNOTSUPP);
2509 if (ovp == lvp && lvp->v_type == VREG) {
2510 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2511 if (uvp == NULLVP &&
2512 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2513 unionfs_deleteextattr_reopen:
2514 if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2515 VOP_OPENEXTATTR(lvp, cred, td)) {
2517 panic("unionfs: VOP_OPENEXTATTR failed");
2519 unp->un_flag &= ~UNIONFS_OPENEXTL;
2521 goto unionfs_deleteextattr_abort;
2523 uvp = unp->un_uppervp;
2524 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2525 goto unionfs_deleteextattr_reopen;
2526 unp->un_flag &= ~UNIONFS_OPENEXTL;
2527 unp->un_flag |= UNIONFS_OPENEXTU;
2532 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2533 ap->a_cred, ap->a_td);
2535 unionfs_deleteextattr_abort:
2536 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
2542 unionfs_setlabel(struct vop_setlabel_args *ap)
2544 struct unionfs_node *unp;
2550 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
2552 KASSERT_UNIONFS_VNODE(ap->a_vp);
2555 unp = VTOUNIONFS(ap->a_vp);
2556 uvp = unp->un_uppervp;
2557 lvp = unp->un_lowervp;
2560 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2563 if (uvp == NULLVP && lvp->v_type == VREG) {
2564 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2566 uvp = unp->un_uppervp;
2570 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
2572 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
2578 unionfs_vptofh(struct vop_vptofh_args *ap)
2580 return (EOPNOTSUPP);
2584 unionfs_add_writecount(struct vop_add_writecount_args *ap)
2586 struct vnode *tvp, *vp;
2587 struct unionfs_node *unp;
2588 int error, writerefs __diagused;
2591 unp = VTOUNIONFS(vp);
2592 tvp = unp->un_uppervp;
2593 KASSERT(tvp != NULL,
2594 ("%s: adding write ref without upper vnode", __func__));
2595 error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc);
2599 * We need to track the write refs we've passed to the underlying
2600 * vnodes so that we can undo them in case we are forcibly unmounted.
2602 writerefs = atomic_fetchadd_int(&vp->v_writecount, ap->a_inc);
2603 /* text refs are bypassed to lowervp */
2604 VNASSERT(writerefs >= 0, vp,
2605 ("%s: invalid write count %d", __func__, writerefs));
2606 VNASSERT(writerefs + ap->a_inc >= 0, vp,
2607 ("%s: invalid write count inc %d + %d", __func__,
2608 writerefs, ap->a_inc));
2613 unionfs_vput_pair(struct vop_vput_pair_args *ap)
2616 struct vnode *dvp, *vp, **vpp, *lvp, *ldvp, *uvp, *udvp, *tempvp;
2617 struct unionfs_node *dunp, *unp;
2627 dunp = VTOUNIONFS(dvp);
2628 udvp = dunp->un_uppervp;
2629 ldvp = dunp->un_lowervp;
2632 * Underlying vnodes should be locked because the encompassing unionfs
2633 * node is locked, but will not be referenced, as the reference will
2634 * only be on the unionfs node. Reference them now so that the vput()s
2635 * performed by VOP_VPUT_PAIR() will have a reference to drop.
2646 unp = VTOUNIONFS(vp);
2647 uvp = unp->un_uppervp;
2648 lvp = unp->un_lowervp;
2655 * If we're being asked to return a locked child vnode, then
2656 * we may need to create a replacement vnode in case the
2657 * original is reclaimed while the lock is dropped. In that
2658 * case we'll need to ensure the mount and the underlying
2659 * vnodes aren't also recycled during that window.
2661 if (!ap->a_unlock_vp) {
2673 * TODO: Because unionfs_lock() locks both the lower and upper vnodes
2674 * (if available), we must also call VOP_VPUT_PAIR() on both the lower
2675 * and upper parent/child pairs. If unionfs_lock() is reworked to lock
2676 * only a single vnode, this code will need to change to also only
2677 * operate on one vnode pair.
2679 ASSERT_VOP_LOCKED(ldvp, __func__);
2680 ASSERT_VOP_LOCKED(udvp, __func__);
2681 ASSERT_VOP_LOCKED(lvp, __func__);
2682 ASSERT_VOP_LOCKED(uvp, __func__);
2684 KASSERT(lvp == NULLVP || ldvp != NULLVP,
2685 ("%s: NULL ldvp with non-NULL lvp", __func__));
2687 res = VOP_VPUT_PAIR(ldvp, lvp != NULLVP ? &lvp : NULL, true);
2688 KASSERT(uvp == NULLVP || udvp != NULLVP,
2689 ("%s: NULL udvp with non-NULL uvp", __func__));
2691 res = VOP_VPUT_PAIR(udvp, uvp != NULLVP ? &uvp : NULL, true);
2693 ASSERT_VOP_UNLOCKED(ldvp, __func__);
2694 ASSERT_VOP_UNLOCKED(udvp, __func__);
2695 ASSERT_VOP_UNLOCKED(lvp, __func__);
2696 ASSERT_VOP_UNLOCKED(uvp, __func__);
2699 * VOP_VPUT_PAIR() dropped the references we added to the underlying
2700 * vnodes, now drop the caller's reference to the unionfs vnodes.
2702 if (vp != NULLVP && ap->a_unlock_vp)
2706 if (vp == NULLVP || ap->a_unlock_vp)
2710 * We're being asked to return a locked vnode. At this point, the
2711 * underlying vnodes have been unlocked, so vp may have been reclaimed.
2713 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2714 if (vp->v_data == NULL && vfs_busy(mp, MBF_NOWAIT) == 0) {
2716 error = unionfs_nodeget(mp, uvp, lvp, dvp, &tempvp, NULL);
2718 vn_lock(tempvp, LK_EXCLUSIVE | LK_RETRY);
2721 vget(vp, LK_EXCLUSIVE | LK_RETRY);
2735 unionfs_set_text(struct vop_set_text_args *ap)
2738 struct unionfs_node *unp;
2742 * We assume text refs are managed against lvp/uvp through the
2743 * executable mapping backed by its VM object. We therefore don't
2744 * need to track leased text refs in the case of a forcible unmount.
2746 unp = VTOUNIONFS(ap->a_vp);
2747 ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2748 tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2749 error = VOP_SET_TEXT(tvp);
2754 unionfs_unset_text(struct vop_unset_text_args *ap)
2757 struct unionfs_node *unp;
2759 ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2760 unp = VTOUNIONFS(ap->a_vp);
2761 tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2762 VOP_UNSET_TEXT_CHECKED(tvp);
2766 struct vop_vector unionfs_vnodeops = {
2767 .vop_default = &default_vnodeops,
2769 .vop_access = unionfs_access,
2770 .vop_aclcheck = unionfs_aclcheck,
2771 .vop_advlock = unionfs_advlock,
2772 .vop_bmap = VOP_EOPNOTSUPP,
2773 .vop_cachedlookup = unionfs_lookup,
2774 .vop_close = unionfs_close,
2775 .vop_closeextattr = unionfs_closeextattr,
2776 .vop_create = unionfs_create,
2777 .vop_deleteextattr = unionfs_deleteextattr,
2778 .vop_fsync = unionfs_fsync,
2779 .vop_getacl = unionfs_getacl,
2780 .vop_getattr = unionfs_getattr,
2781 .vop_getextattr = unionfs_getextattr,
2782 .vop_getwritemount = unionfs_getwritemount,
2783 .vop_inactive = unionfs_inactive,
2784 .vop_need_inactive = vop_stdneed_inactive,
2785 .vop_islocked = unionfs_islocked,
2786 .vop_ioctl = unionfs_ioctl,
2787 .vop_link = unionfs_link,
2788 .vop_listextattr = unionfs_listextattr,
2789 .vop_lock1 = unionfs_lock,
2790 .vop_lookup = vfs_cache_lookup,
2791 .vop_mkdir = unionfs_mkdir,
2792 .vop_mknod = unionfs_mknod,
2793 .vop_open = unionfs_open,
2794 .vop_openextattr = unionfs_openextattr,
2795 .vop_pathconf = unionfs_pathconf,
2796 .vop_poll = unionfs_poll,
2797 .vop_print = unionfs_print,
2798 .vop_read = unionfs_read,
2799 .vop_readdir = unionfs_readdir,
2800 .vop_readlink = unionfs_readlink,
2801 .vop_reclaim = unionfs_reclaim,
2802 .vop_remove = unionfs_remove,
2803 .vop_rename = unionfs_rename,
2804 .vop_rmdir = unionfs_rmdir,
2805 .vop_setacl = unionfs_setacl,
2806 .vop_setattr = unionfs_setattr,
2807 .vop_setextattr = unionfs_setextattr,
2808 .vop_setlabel = unionfs_setlabel,
2809 .vop_strategy = unionfs_strategy,
2810 .vop_symlink = unionfs_symlink,
2811 .vop_unlock = unionfs_unlock,
2812 .vop_whiteout = unionfs_whiteout,
2813 .vop_write = unionfs_write,
2814 .vop_vptofh = unionfs_vptofh,
2815 .vop_add_writecount = unionfs_add_writecount,
2816 .vop_vput_pair = unionfs_vput_pair,
2817 .vop_set_text = unionfs_set_text,
2818 .vop_unset_text = unionfs_unset_text,
2820 VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);