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
40 #include <sys/param.h>
41 #include <sys/systm.h>
43 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/mount.h>
47 #include <sys/mutex.h>
48 #include <sys/namei.h>
49 #include <sys/sysctl.h>
50 #include <sys/vnode.h>
52 #include <sys/fcntl.h>
54 #include <sys/dirent.h>
59 #include <fs/unionfs/union.h>
61 #include <machine/atomic.h>
64 #include <vm/vm_extern.h>
65 #include <vm/vm_object.h>
66 #include <vm/vnode_pager.h>
69 #define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args)
70 #define UNIONFS_IDBG_RENAME
72 #define UNIONFS_INTERNAL_DEBUG(msg, args...)
75 #define KASSERT_UNIONFS_VNODE(vp) \
76 VNASSERT(((vp)->v_op == &unionfs_vnodeops), vp, \
77 ("%s: non-unionfs vnode", __func__))
80 unionfs_lookup(struct vop_cachedlookup_args *ap)
82 struct unionfs_node *dunp;
83 struct vnode *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp;
85 struct componentname *cnp;
88 u_long cnflags, cnflagsbk;
91 int error , uerror, lerror;
95 error = uerror = lerror = ENOENT;
97 nameiop = cnp->cn_nameiop;
98 cnflags = cnp->cn_flags;
100 dunp = VTOUNIONFS(dvp);
101 udvp = dunp->un_uppervp;
102 ldvp = dunp->un_lowervp;
103 vp = uvp = lvp = NULLVP;
105 *(ap->a_vpp) = NULLVP;
107 UNIONFS_INTERNAL_DEBUG(
108 "unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n",
109 nameiop, cnflags, cnp->cn_nameptr);
111 if (dvp->v_type != VDIR)
115 * If read-only and op is not LOOKUP, will return EROFS.
117 if ((cnflags & ISLASTCN) &&
118 (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
125 if (cnflags & ISDOTDOT) {
126 if (LOOKUP != nameiop && udvp == NULLVP)
129 if (udvp != NULLVP) {
137 error = VOP_LOOKUP(dtmpvp, &vp, cnp);
139 if (dtmpvp == udvp && ldvp != NULLVP) {
141 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
146 * Exchange lock and reference from vp to
147 * dunp->un_dvp. vp is upper/lower vnode, but it
148 * will need to return the unionfs vnode.
150 if (nameiop == DELETE || nameiop == RENAME ||
151 (cnp->cn_lkflags & LK_TYPE_MASK))
156 *(ap->a_vpp) = dunp->un_dvp;
159 if (nameiop == DELETE || nameiop == RENAME)
160 vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY);
161 else if (cnp->cn_lkflags & LK_TYPE_MASK)
162 vn_lock(dunp->un_dvp, cnp->cn_lkflags |
165 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
166 } else if (error == ENOENT && (cnflags & MAKEENTRY) != 0)
167 cache_enter(dvp, NULLVP, cnp);
169 goto unionfs_lookup_return;
175 if (udvp != NULLVP) {
176 uerror = VOP_LOOKUP(udvp, &uvp, cnp);
179 if (udvp == uvp) { /* is dot */
185 goto unionfs_lookup_return;
187 if (nameiop == DELETE || nameiop == RENAME ||
188 (cnp->cn_lkflags & LK_TYPE_MASK))
193 if (uerror == ENOENT || uerror == EJUSTRETURN)
194 if (cnp->cn_flags & ISWHITEOUT)
195 iswhiteout = 1; /* don't lookup lower */
196 if (iswhiteout == 0 && ldvp != NULLVP)
197 if (!VOP_GETATTR(udvp, &va, cnp->cn_cred) &&
198 (va.va_flags & OPAQUE))
199 iswhiteout = 1; /* don't lookup lower */
201 UNIONFS_INTERNAL_DEBUG(
202 "unionfs_lookup: debug: whiteout=%d, path=%s\n",
203 iswhiteout, cnp->cn_nameptr);
210 if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) {
211 /* always op is LOOKUP */
212 cnp->cn_nameiop = LOOKUP;
213 cnflagsbk = cnp->cn_flags;
214 cnp->cn_flags = cnflags;
216 lerror = VOP_LOOKUP(ldvp, &lvp, cnp);
218 cnp->cn_nameiop = nameiop;
219 if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN))
220 cnp->cn_flags = cnflagsbk;
223 if (ldvp == lvp) { /* is dot */
225 vrele(uvp); /* no need? */
230 UNIONFS_INTERNAL_DEBUG(
231 "unionfs_lookup: leave (%d)\n", lerror);
235 if (cnp->cn_lkflags & LK_TYPE_MASK)
241 * check lookup result
243 if (uvp == NULLVP && lvp == NULLVP) {
244 error = (udvp != NULLVP ? uerror : lerror);
245 goto unionfs_lookup_return;
251 if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) {
259 if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP &&
260 lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR &&
261 !(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
262 (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) {
263 /* get unionfs vnode in order to create a new shadow dir. */
264 error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp,
267 goto unionfs_lookup_cleanup;
269 if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK))
271 if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) {
272 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
275 error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
276 udvp, VTOUNIONFS(vp), cnp, td);
281 "unionfs_lookup: Unable to create shadow dir.");
282 if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE)
286 goto unionfs_lookup_cleanup;
288 if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED)
289 vn_lock(vp, LK_SHARED | LK_RETRY);
300 goto unionfs_lookup_cleanup;
304 if (uvp != NULLVP && uvp->v_type == VSOCK) {
307 if (cnp->cn_lkflags & LK_TYPE_MASK)
308 vn_lock(vp, cnp->cn_lkflags | LK_RETRY);
310 else if (lvp != NULLVP && lvp->v_type == VSOCK) {
313 if (cnp->cn_lkflags & LK_TYPE_MASK)
314 vn_lock(vp, cnp->cn_lkflags | LK_RETRY);
320 error = unionfs_nodeget(dvp->v_mount, uvp, lvp,
324 "unionfs_lookup: Unable to create unionfs vnode.");
325 goto unionfs_lookup_cleanup;
327 if ((nameiop == DELETE || nameiop == RENAME) &&
328 (cnp->cn_lkflags & LK_TYPE_MASK) == 0)
329 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
334 if ((cnflags & MAKEENTRY) && vp->v_type != VSOCK)
335 cache_enter(dvp, vp, cnp);
337 unionfs_lookup_cleanup:
343 if (error == ENOENT && (cnflags & MAKEENTRY) != 0)
344 cache_enter(dvp, NULLVP, cnp);
346 unionfs_lookup_return:
348 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
354 unionfs_create(struct vop_create_args *ap)
356 struct unionfs_node *dunp;
357 struct componentname *cnp;
362 UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");
364 KASSERT_UNIONFS_VNODE(ap->a_dvp);
366 dunp = VTOUNIONFS(ap->a_dvp);
368 udvp = dunp->un_uppervp;
371 if (udvp != NULLVP) {
372 error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap);
374 goto unionfs_create_abort;
376 if (vp->v_type == VSOCK)
380 error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
381 ap->a_dvp, ap->a_vpp, cnp);
386 unionfs_create_abort:
387 UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error);
393 unionfs_whiteout(struct vop_whiteout_args *ap)
395 struct unionfs_node *dunp;
396 struct componentname *cnp;
400 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n");
402 KASSERT_UNIONFS_VNODE(ap->a_dvp);
404 dunp = VTOUNIONFS(ap->a_dvp);
406 udvp = dunp->un_uppervp;
409 if (udvp != NULLVP) {
410 switch (ap->a_flags) {
414 error = VOP_WHITEOUT(udvp, cnp, ap->a_flags);
422 UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error);
428 unionfs_mknod(struct vop_mknod_args *ap)
430 struct unionfs_node *dunp;
431 struct componentname *cnp;
436 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n");
438 KASSERT_UNIONFS_VNODE(ap->a_dvp);
440 dunp = VTOUNIONFS(ap->a_dvp);
442 udvp = dunp->un_uppervp;
445 if (udvp != NULLVP) {
446 error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap);
448 goto unionfs_mknod_abort;
450 if (vp->v_type == VSOCK)
454 error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
455 ap->a_dvp, ap->a_vpp, cnp);
461 UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error);
466 enum unionfs_lkupgrade {
467 UNIONFS_LKUPGRADE_SUCCESS, /* lock successfully upgraded */
468 UNIONFS_LKUPGRADE_ALREADY, /* lock already held exclusive */
469 UNIONFS_LKUPGRADE_DOOMED /* lock was upgraded, but vnode reclaimed */
472 static inline enum unionfs_lkupgrade
473 unionfs_upgrade_lock(struct vnode *vp)
475 ASSERT_VOP_LOCKED(vp, __func__);
477 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
478 return (UNIONFS_LKUPGRADE_ALREADY);
480 if (vn_lock(vp, LK_UPGRADE) != 0) {
481 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
482 if (VN_IS_DOOMED(vp))
483 return (UNIONFS_LKUPGRADE_DOOMED);
485 return (UNIONFS_LKUPGRADE_SUCCESS);
489 unionfs_downgrade_lock(struct vnode *vp, enum unionfs_lkupgrade status)
491 if (status != UNIONFS_LKUPGRADE_ALREADY)
492 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
496 unionfs_open(struct vop_open_args *ap)
498 struct unionfs_node *unp;
499 struct unionfs_node_status *unsp;
503 struct vnode *targetvp;
507 enum unionfs_lkupgrade lkstatus;
509 UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n");
511 KASSERT_UNIONFS_VNODE(ap->a_vp);
520 * The executable loader path may call this function with vp locked
521 * shared. If the vnode is reclaimed while upgrading, we can't safely
522 * use unp or do anything else unionfs- specific.
524 lkstatus = unionfs_upgrade_lock(vp);
525 if (lkstatus == UNIONFS_LKUPGRADE_DOOMED) {
527 goto unionfs_open_cleanup;
530 unp = VTOUNIONFS(vp);
531 uvp = unp->un_uppervp;
532 lvp = unp->un_lowervp;
533 unionfs_get_node_status(unp, td, &unsp);
535 if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) {
536 /* vnode is already opend. */
537 if (unsp->uns_upper_opencnt > 0)
542 if (targetvp == lvp &&
543 (ap->a_mode & FWRITE) && lvp->v_type == VREG)
546 if (targetvp == NULLVP) {
548 if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) {
549 error = unionfs_copyfile(unp,
550 !(ap->a_mode & O_TRUNC), cred, td);
552 goto unionfs_open_abort;
553 targetvp = uvp = unp->un_uppervp;
560 error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp);
562 if (targetvp == uvp) {
563 if (uvp->v_type == VDIR && lvp != NULLVP &&
564 unsp->uns_lower_opencnt <= 0) {
565 /* open lower for readdir */
566 error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
568 VOP_CLOSE(uvp, ap->a_mode, cred, td);
569 goto unionfs_open_abort;
571 unsp->uns_node_flag |= UNS_OPENL_4_READDIR;
572 unsp->uns_lower_opencnt++;
574 unsp->uns_upper_opencnt++;
576 unsp->uns_lower_opencnt++;
577 unsp->uns_lower_openmode = ap->a_mode;
579 vp->v_object = targetvp->v_object;
584 unionfs_tryrem_node_status(unp, unsp);
586 unionfs_open_cleanup:
587 unionfs_downgrade_lock(vp, lkstatus);
589 UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error);
595 unionfs_close(struct vop_close_args *ap)
597 struct unionfs_node *unp;
598 struct unionfs_node_status *unsp;
604 enum unionfs_lkupgrade lkstatus;;
606 UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");
608 KASSERT_UNIONFS_VNODE(ap->a_vp);
616 * If the vnode is reclaimed while upgrading, we can't safely use unp
617 * or do anything else unionfs- specific.
619 lkstatus = unionfs_upgrade_lock(vp);
620 if (lkstatus == UNIONFS_LKUPGRADE_DOOMED)
621 goto unionfs_close_cleanup;
623 unp = VTOUNIONFS(vp);
624 unionfs_get_node_status(unp, td, &unsp);
626 if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) {
628 printf("unionfs_close: warning: open count is 0\n");
630 if (unp->un_uppervp != NULLVP)
631 ovp = unp->un_uppervp;
633 ovp = unp->un_lowervp;
634 } else if (unsp->uns_upper_opencnt > 0)
635 ovp = unp->un_uppervp;
637 ovp = unp->un_lowervp;
639 error = VOP_CLOSE(ovp, ap->a_fflag, cred, td);
642 goto unionfs_close_abort;
644 vp->v_object = ovp->v_object;
646 if (ovp == unp->un_uppervp) {
647 unsp->uns_upper_opencnt--;
648 if (unsp->uns_upper_opencnt == 0) {
649 if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) {
650 VOP_CLOSE(unp->un_lowervp, FREAD, cred, td);
651 unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR;
652 unsp->uns_lower_opencnt--;
654 if (unsp->uns_lower_opencnt > 0)
655 vp->v_object = unp->un_lowervp->v_object;
658 unsp->uns_lower_opencnt--;
661 unionfs_tryrem_node_status(unp, unsp);
663 unionfs_close_cleanup:
664 unionfs_downgrade_lock(vp, lkstatus);
666 UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error);
672 * Check the access mode toward shadow file/dir.
675 unionfs_check_corrected_access(accmode_t accmode, struct vattr *va,
678 uid_t uid; /* upper side vnode's uid */
679 gid_t gid; /* upper side vnode's gid */
680 u_short vmode; /* upper side vnode's mode */
689 if (cred->cr_uid == uid) {
694 if (accmode & VWRITE)
696 return ((vmode & mask) == mask ? 0 : EACCES);
700 if (groupmember(gid, cred)) {
705 if (accmode & VWRITE)
707 return ((vmode & mask) == mask ? 0 : EACCES);
715 if (accmode & VWRITE)
718 return ((vmode & mask) == mask ? 0 : EACCES);
722 unionfs_access(struct vop_access_args *ap)
724 struct unionfs_mount *ump;
725 struct unionfs_node *unp;
733 UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n");
735 KASSERT_UNIONFS_VNODE(ap->a_vp);
737 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
738 unp = VTOUNIONFS(ap->a_vp);
739 uvp = unp->un_uppervp;
740 lvp = unp->un_lowervp;
742 accmode = ap->a_accmode;
745 if ((accmode & VWRITE) &&
746 (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
747 switch (ap->a_vp->v_type) {
758 error = VOP_ACCESS(uvp, accmode, ap->a_cred, td);
760 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
766 if (accmode & VWRITE) {
767 if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) {
768 switch (ap->a_vp->v_type) {
776 } else if (ap->a_vp->v_type == VREG ||
777 ap->a_vp->v_type == VDIR) {
778 /* check shadow file/dir */
779 if (ump->um_copymode != UNIONFS_TRANSPARENT) {
780 error = unionfs_create_uppervattr(ump,
781 lvp, &va, ap->a_cred, td);
785 error = unionfs_check_corrected_access(
786 accmode, &va, ap->a_cred);
791 accmode &= ~(VWRITE | VAPPEND);
792 accmode |= VREAD; /* will copy to upper */
794 error = VOP_ACCESS(lvp, accmode, ap->a_cred, td);
797 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
803 unionfs_getattr(struct vop_getattr_args *ap)
805 struct unionfs_node *unp;
806 struct unionfs_mount *ump;
813 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
815 KASSERT_UNIONFS_VNODE(ap->a_vp);
817 unp = VTOUNIONFS(ap->a_vp);
818 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
819 uvp = unp->un_uppervp;
820 lvp = unp->un_lowervp;
824 if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0)
826 ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
828 UNIONFS_INTERNAL_DEBUG(
829 "unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
830 ap->a_vap->va_mode, ap->a_vap->va_uid,
831 ap->a_vap->va_gid, error);
836 error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred);
838 if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) {
839 /* correct the attr toward shadow file/dir. */
840 if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
841 unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td);
842 ap->a_vap->va_mode = va.va_mode;
843 ap->a_vap->va_uid = va.va_uid;
844 ap->a_vap->va_gid = va.va_gid;
849 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
851 UNIONFS_INTERNAL_DEBUG(
852 "unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
853 ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error);
859 unionfs_setattr(struct vop_setattr_args *ap)
861 struct unionfs_node *unp;
868 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n");
870 KASSERT_UNIONFS_VNODE(ap->a_vp);
873 unp = VTOUNIONFS(ap->a_vp);
874 uvp = unp->un_uppervp;
875 lvp = unp->un_lowervp;
879 if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
880 (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
881 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
882 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL))
885 if (uvp == NULLVP && lvp->v_type == VREG) {
886 error = unionfs_copyfile(unp, (vap->va_size != 0),
890 uvp = unp->un_uppervp;
894 error = VOP_SETATTR(uvp, vap, ap->a_cred);
896 UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error);
902 unionfs_read(struct vop_read_args *ap)
904 struct unionfs_node *unp;
908 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */
910 KASSERT_UNIONFS_VNODE(ap->a_vp);
912 unp = VTOUNIONFS(ap->a_vp);
913 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
915 error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
917 /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */
923 unionfs_write(struct vop_write_args *ap)
925 struct unionfs_node *unp;
929 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */
931 KASSERT_UNIONFS_VNODE(ap->a_vp);
933 unp = VTOUNIONFS(ap->a_vp);
934 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
936 error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
938 /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */
944 unionfs_ioctl(struct vop_ioctl_args *ap)
946 struct unionfs_node *unp;
947 struct unionfs_node_status *unsp;
951 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n");
953 KASSERT_UNIONFS_VNODE(ap->a_vp);
955 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
956 unp = VTOUNIONFS(ap->a_vp);
957 unionfs_get_node_status(unp, ap->a_td, &unsp);
958 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
959 unionfs_tryrem_node_status(unp, unsp);
960 VOP_UNLOCK(ap->a_vp);
965 error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag,
966 ap->a_cred, ap->a_td);
968 UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error);
974 unionfs_poll(struct vop_poll_args *ap)
976 struct unionfs_node *unp;
977 struct unionfs_node_status *unsp;
980 KASSERT_UNIONFS_VNODE(ap->a_vp);
982 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
983 unp = VTOUNIONFS(ap->a_vp);
984 unionfs_get_node_status(unp, ap->a_td, &unsp);
985 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
986 unionfs_tryrem_node_status(unp, unsp);
987 VOP_UNLOCK(ap->a_vp);
992 return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td));
996 unionfs_fsync(struct vop_fsync_args *ap)
998 struct unionfs_node *unp;
999 struct unionfs_node_status *unsp;
1002 KASSERT_UNIONFS_VNODE(ap->a_vp);
1004 unp = VTOUNIONFS(ap->a_vp);
1005 unionfs_get_node_status(unp, ap->a_td, &unsp);
1006 ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
1007 unionfs_tryrem_node_status(unp, unsp);
1012 return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td));
1016 unionfs_remove(struct vop_remove_args *ap)
1019 struct unionfs_node *dunp;
1020 struct unionfs_node *unp;
1021 struct unionfs_mount *ump;
1026 struct componentname *cnp;
1027 struct componentname cn;
1032 UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n");
1034 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1037 dunp = VTOUNIONFS(ap->a_dvp);
1038 udvp = dunp->un_uppervp;
1042 if (ap->a_vp->v_op != &unionfs_vnodeops) {
1043 if (ap->a_vp->v_type != VSOCK)
1046 vp = uvp = lvp = NULLVP;
1048 VOP_UNLOCK(ap->a_vp);
1049 error = unionfs_relookup(udvp, &vp, cnp, &cn, td,
1050 cnp->cn_nameptr, cnp->cn_namelen, DELETE);
1051 if (error != 0 && error != ENOENT) {
1052 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1056 if (error == 0 && vp == ap->a_vp) {
1057 /* target vnode in upper */
1061 /* target vnode in lower */
1068 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1071 path = cnp->cn_nameptr;
1072 pathlen = cnp->cn_namelen;
1074 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1075 unp = VTOUNIONFS(ap->a_vp);
1076 uvp = unp->un_uppervp;
1077 lvp = unp->un_lowervp;
1078 path = unp->un_path;
1079 pathlen = unp->un_pathlen;
1085 if (uvp != NULLVP) {
1087 * XXX: if the vnode type is VSOCK, it will create whiteout
1090 if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS ||
1092 cnp->cn_flags |= DOWHITEOUT;
1093 error = VOP_REMOVE(udvp, uvp, cnp);
1094 } else if (lvp != NULLVP)
1095 error = unionfs_mkwhiteout(udvp, cnp, td, path, pathlen);
1097 UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error);
1103 unionfs_link(struct vop_link_args *ap)
1105 struct unionfs_node *dunp;
1106 struct unionfs_node *unp;
1109 struct componentname *cnp;
1114 UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");
1116 KASSERT_UNIONFS_VNODE(ap->a_tdvp);
1117 KASSERT_UNIONFS_VNODE(ap->a_vp);
1121 dunp = VTOUNIONFS(ap->a_tdvp);
1123 udvp = dunp->un_uppervp;
1131 if (ap->a_vp->v_op != &unionfs_vnodeops)
1134 unp = VTOUNIONFS(ap->a_vp);
1136 if (unp->un_uppervp == NULLVP) {
1137 if (ap->a_vp->v_type != VREG)
1138 return (EOPNOTSUPP);
1140 error = unionfs_copyfile(unp, 1, cnp->cn_cred, td);
1145 uvp = unp->un_uppervp;
1148 if (needrelookup != 0)
1149 error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td);
1152 error = VOP_LINK(udvp, uvp, cnp);
1154 UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error);
1160 unionfs_rename(struct vop_rename_args *ap)
1164 struct componentname *fcnp;
1167 struct componentname *tcnp;
1168 struct vnode *ltdvp;
1172 /* rename target vnodes */
1173 struct vnode *rfdvp;
1175 struct vnode *rtdvp;
1178 struct unionfs_mount *ump;
1179 struct unionfs_node *unp;
1183 UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n");
1201 /* check for cross device rename */
1202 if (fvp->v_mount != tdvp->v_mount ||
1203 (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) {
1204 if (fvp->v_op != &unionfs_vnodeops)
1208 goto unionfs_rename_abort;
1211 /* Renaming a file to itself has no effect. */
1213 goto unionfs_rename_abort;
1216 * from/to vnode is unionfs node.
1219 KASSERT_UNIONFS_VNODE(fdvp);
1220 KASSERT_UNIONFS_VNODE(fvp);
1221 KASSERT_UNIONFS_VNODE(tdvp);
1223 KASSERT_UNIONFS_VNODE(tvp);
1225 unp = VTOUNIONFS(fdvp);
1226 #ifdef UNIONFS_IDBG_RENAME
1227 UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n",
1228 fdvp, unp->un_uppervp, unp->un_lowervp);
1230 if (unp->un_uppervp == NULLVP) {
1232 goto unionfs_rename_abort;
1234 rfdvp = unp->un_uppervp;
1237 unp = VTOUNIONFS(fvp);
1238 #ifdef UNIONFS_IDBG_RENAME
1239 UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n",
1240 fvp, unp->un_uppervp, unp->un_lowervp);
1242 ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount);
1243 if (unp->un_uppervp == NULLVP) {
1244 switch (fvp->v_type) {
1246 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1247 goto unionfs_rename_abort;
1248 error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td);
1251 goto unionfs_rename_abort;
1254 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1255 goto unionfs_rename_abort;
1256 error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td);
1259 goto unionfs_rename_abort;
1263 goto unionfs_rename_abort;
1269 if (unp->un_lowervp != NULLVP)
1270 fcnp->cn_flags |= DOWHITEOUT;
1271 rfvp = unp->un_uppervp;
1274 unp = VTOUNIONFS(tdvp);
1275 #ifdef UNIONFS_IDBG_RENAME
1276 UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n",
1277 tdvp, unp->un_uppervp, unp->un_lowervp);
1279 if (unp->un_uppervp == NULLVP) {
1281 goto unionfs_rename_abort;
1283 rtdvp = unp->un_uppervp;
1284 ltdvp = unp->un_lowervp;
1290 } else if (tvp != NULLVP) {
1291 unp = VTOUNIONFS(tvp);
1292 #ifdef UNIONFS_IDBG_RENAME
1293 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n",
1294 tvp, unp->un_uppervp, unp->un_lowervp);
1296 if (unp->un_uppervp == NULLVP)
1299 if (tvp->v_type == VDIR) {
1301 goto unionfs_rename_abort;
1303 rtvp = unp->un_uppervp;
1304 ltvp = unp->un_lowervp;
1310 goto unionfs_rename_abort;
1312 if (needrelookup != 0) {
1313 if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0)
1314 goto unionfs_rename_abort;
1315 error = unionfs_relookup_for_delete(fdvp, fcnp, td);
1318 goto unionfs_rename_abort;
1320 /* Lock of tvp is canceled in order to avoid recursive lock. */
1321 if (tvp != NULLVP && tvp != tdvp)
1323 error = unionfs_relookup_for_rename(tdvp, tcnp, td);
1324 if (tvp != NULLVP && tvp != tdvp)
1325 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
1327 goto unionfs_rename_abort;
1330 error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
1333 if (rtvp != NULLVP && rtvp->v_type == VDIR)
1335 if (fvp->v_type == VDIR && fdvp != tdvp)
1339 if (ltdvp != NULLVP)
1345 if (tvp != rtvp && tvp != NULLVP) {
1356 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1360 unionfs_rename_abort:
1364 if (tvp != NULLVP) {
1370 if (tvp != rtvp && rtvp != NULLVP)
1379 UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1385 unionfs_mkdir(struct vop_mkdir_args *ap)
1387 struct unionfs_node *dunp;
1388 struct componentname *cnp;
1396 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1398 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1402 dunp = VTOUNIONFS(dvp);
1404 lkflags = cnp->cn_lkflags;
1405 udvp = dunp->un_uppervp;
1407 if (udvp != NULLVP) {
1410 if (!(cnp->cn_flags & ISWHITEOUT)) {
1411 error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
1413 goto unionfs_mkdir_cleanup;
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;
1422 * The underlying VOP_MKDIR() implementation may have
1423 * temporarily dropped the parent directory vnode lock.
1424 * Because the unionfs vnode ordinarily shares that
1425 * lock, this may allow the unionfs vnode to be reclaimed
1426 * and its lock field reset. In that case, the unionfs
1427 * vnode is effectively no longer locked, and we must
1428 * explicitly lock it before returning in order to meet
1429 * the locking requirements of VOP_MKDIR().
1431 if (__predict_false(VTOUNIONFS(dvp) == NULL)) {
1433 goto unionfs_mkdir_cleanup;
1435 error = unionfs_nodeget(dvp->v_mount, uvp, NULLVP,
1436 dvp, ap->a_vpp, cnp);
1437 cnp->cn_lkflags = lkflags;
1442 unionfs_mkdir_cleanup:
1444 if (__predict_false(VTOUNIONFS(dvp) == NULL)) {
1446 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1447 } else if (udvp != NULLVP)
1450 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
1456 unionfs_rmdir(struct vop_rmdir_args *ap)
1458 struct unionfs_node *dunp;
1459 struct unionfs_node *unp;
1460 struct unionfs_mount *ump;
1461 struct componentname *cnp;
1468 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1470 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1471 KASSERT_UNIONFS_VNODE(ap->a_vp);
1474 dunp = VTOUNIONFS(ap->a_dvp);
1475 unp = VTOUNIONFS(ap->a_vp);
1478 udvp = dunp->un_uppervp;
1479 uvp = unp->un_uppervp;
1480 lvp = unp->un_lowervp;
1486 return (EOPNOTSUPP);
1488 if (uvp != NULLVP) {
1489 if (lvp != NULLVP) {
1490 error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
1494 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1495 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP)
1496 cnp->cn_flags |= DOWHITEOUT;
1498 * The relookup path will need to relock the parent dvp and
1499 * possibly the vp as well. Locking is expected to be done
1500 * in parent->child order; drop the lock on vp to avoid LOR
1501 * and potential recursion on vp's lock.
1502 * vp is expected to remain referenced during VOP_RMDIR(),
1503 * so vref/vrele should not be necessary here.
1505 VOP_UNLOCK(ap->a_vp);
1506 VNPASS(vrefcnt(ap->a_vp) > 0, ap->a_vp);
1507 error = unionfs_relookup_for_delete(ap->a_dvp, cnp, td);
1508 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1510 * VOP_RMDIR is dispatched against udvp, so if uvp became
1511 * doomed while the lock was dropped above the target
1512 * filesystem may not be able to cope.
1514 if (error == 0 && VN_IS_DOOMED(uvp))
1517 error = VOP_RMDIR(udvp, uvp, cnp);
1518 } else if (lvp != NULLVP)
1519 error = unionfs_mkwhiteout(udvp, cnp, td,
1520 unp->un_path, unp->un_pathlen);
1523 cache_purge(ap->a_dvp);
1524 cache_purge(ap->a_vp);
1527 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
1533 unionfs_symlink(struct vop_symlink_args *ap)
1535 struct unionfs_node *dunp;
1536 struct componentname *cnp;
1542 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1544 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1547 dunp = VTOUNIONFS(ap->a_dvp);
1549 lkflags = cnp->cn_lkflags;
1550 udvp = dunp->un_uppervp;
1552 if (udvp != NULLVP) {
1553 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
1556 cnp->cn_lkflags = LK_EXCLUSIVE;
1557 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1558 ap->a_dvp, ap->a_vpp, cnp);
1559 cnp->cn_lkflags = lkflags;
1564 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
1570 unionfs_readdir(struct vop_readdir_args *ap)
1572 struct unionfs_node *unp;
1573 struct unionfs_node_status *unsp;
1581 uint64_t *cookies_bk;
1586 enum unionfs_lkupgrade lkstatus;
1588 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1590 KASSERT_UNIONFS_VNODE(ap->a_vp);
1603 if (vp->v_type != VDIR)
1607 * If the vnode is reclaimed while upgrading, we can't safely use unp
1608 * or do anything else unionfs- specific.
1610 lkstatus = unionfs_upgrade_lock(vp);
1611 if (lkstatus == UNIONFS_LKUPGRADE_DOOMED)
1614 unp = VTOUNIONFS(vp);
1615 uvp = unp->un_uppervp;
1616 lvp = unp->un_lowervp;
1617 /* check the open count. unionfs needs open before readdir. */
1618 unionfs_get_node_status(unp, td, &unsp);
1619 if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) ||
1620 (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) {
1621 unionfs_tryrem_node_status(unp, unsp);
1625 unionfs_downgrade_lock(vp, lkstatus);
1627 goto unionfs_readdir_exit;
1630 if (uvp != NULLVP && lvp != NULLVP) {
1631 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0)
1632 goto unionfs_readdir_exit;
1633 if (va.va_flags & OPAQUE)
1638 if (uvp != NULLVP && lvp == NULLVP) {
1639 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
1640 ap->a_ncookies, ap->a_cookies);
1641 unsp->uns_readdir_status = 0;
1643 goto unionfs_readdir_exit;
1647 if (uvp == NULLVP && lvp != NULLVP) {
1648 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1649 ap->a_ncookies, ap->a_cookies);
1650 unsp->uns_readdir_status = 2;
1652 goto unionfs_readdir_exit;
1656 * readdir upper and lower
1658 KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp"));
1659 KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp"));
1660 if (uio->uio_offset == 0)
1661 unsp->uns_readdir_status = 0;
1663 if (unsp->uns_readdir_status == 0) {
1665 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
1666 ap->a_ncookies, ap->a_cookies);
1668 if (error != 0 || eofflag == 0)
1669 goto unionfs_readdir_exit;
1670 unsp->uns_readdir_status = 1;
1673 * UFS(and other FS) needs size of uio_resid larger than
1675 * size of DIRBLKSIZ equals DEV_BSIZE.
1676 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1678 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
1679 goto unionfs_readdir_exit;
1683 * It prepares to readdir in lower.
1685 if (ap->a_ncookies != NULL) {
1686 ncookies_bk = *(ap->a_ncookies);
1687 *(ap->a_ncookies) = 0;
1689 if (ap->a_cookies != NULL) {
1690 cookies_bk = *(ap->a_cookies);
1691 *(ap->a_cookies) = NULL;
1695 /* initialize for readdir in lower */
1696 if (unsp->uns_readdir_status == 1) {
1697 unsp->uns_readdir_status = 2;
1699 * Backup uio_offset. See the comment after the
1700 * VOP_READDIR call on the lower layer.
1702 uio_offset_bk = uio->uio_offset;
1703 uio->uio_offset = 0;
1706 if (lvp == NULLVP) {
1708 goto unionfs_readdir_exit;
1711 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1712 ap->a_ncookies, ap->a_cookies);
1715 * We can't return an uio_offset of 0: this would trigger an
1716 * infinite loop, because the next call to unionfs_readdir would
1717 * always restart with the upper layer (uio_offset == 0) and
1718 * always return some data.
1720 * This happens when the lower layer root directory is removed.
1721 * (A root directory deleting of unionfs should not be permitted.
1722 * But current VFS can not do it.)
1724 if (uio->uio_offset == 0)
1725 uio->uio_offset = uio_offset_bk;
1727 if (cookies_bk != NULL) {
1730 uint64_t *newcookies, *pos;
1732 size = *(ap->a_ncookies) + ncookies_bk;
1733 newcookies = (uint64_t *) malloc(size * sizeof(*newcookies),
1737 memcpy(pos, cookies_bk, ncookies_bk * sizeof(*newcookies));
1739 memcpy(pos, *(ap->a_cookies),
1740 *(ap->a_ncookies) * sizeof(*newcookies));
1741 free(cookies_bk, M_TEMP);
1742 free(*(ap->a_cookies), M_TEMP);
1743 *(ap->a_ncookies) = size;
1744 *(ap->a_cookies) = newcookies;
1747 unionfs_readdir_exit:
1748 if (error != 0 && ap->a_eofflag != NULL)
1749 *(ap->a_eofflag) = 1;
1751 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
1757 unionfs_readlink(struct vop_readlink_args *ap)
1759 struct unionfs_node *unp;
1763 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
1765 KASSERT_UNIONFS_VNODE(ap->a_vp);
1767 unp = VTOUNIONFS(ap->a_vp);
1768 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1770 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
1772 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
1778 unionfs_getwritemount(struct vop_getwritemount_args *ap)
1780 struct unionfs_node *unp;
1782 struct vnode *vp, *ovp;
1785 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
1792 unp = VTOUNIONFS(vp);
1794 uvp = unp->un_uppervp;
1797 * If our node has no upper vnode, check the parent directory.
1798 * We may be initiating a write operation that will produce a
1799 * new upper vnode through CoW.
1801 if (uvp == NULLVP && unp != NULL) {
1805 * Only the root vnode should have an empty parent, but it
1806 * should not have an empty uppervp, so we shouldn't get here.
1808 VNASSERT(vp != NULL, ovp, ("%s: NULL parent vnode", __func__));
1811 unp = VTOUNIONFS(vp);
1813 uvp = unp->un_uppervp;
1818 if (uvp != NULLVP) {
1821 error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
1825 *(ap->a_mpp) = NULL;
1828 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);
1834 unionfs_inactive(struct vop_inactive_args *ap)
1836 ap->a_vp->v_object = NULL;
1842 unionfs_reclaim(struct vop_reclaim_args *ap)
1844 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
1846 unionfs_noderem(ap->a_vp);
1848 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
1854 unionfs_print(struct vop_print_args *ap)
1856 struct unionfs_node *unp;
1857 /* struct unionfs_node_status *unsp; */
1859 unp = VTOUNIONFS(ap->a_vp);
1860 /* unionfs_get_node_status(unp, curthread, &unsp); */
1862 printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
1863 ap->a_vp, unp->un_uppervp, unp->un_lowervp);
1865 printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
1866 unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
1869 if (unp->un_uppervp != NULLVP)
1870 vn_printf(unp->un_uppervp, "unionfs: upper ");
1871 if (unp->un_lowervp != NULLVP)
1872 vn_printf(unp->un_lowervp, "unionfs: lower ");
1878 unionfs_get_llt_revlock(struct vnode *vp, int flags)
1884 switch (flags & LK_TYPE_MASK) {
1886 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
1887 revlock = LK_UPGRADE;
1889 revlock = LK_RELEASE;
1893 revlock = LK_RELEASE;
1896 revlock = LK_UPGRADE;
1906 * The state of an acquired lock is adjusted similarly to
1907 * the time of error generating.
1908 * flags: LK_RELEASE or LK_UPGRADE
1911 unionfs_revlock(struct vnode *vp, int flags)
1913 if (flags & LK_RELEASE)
1914 VOP_UNLOCK_FLAGS(vp, flags);
1917 if (vn_lock(vp, flags) != 0)
1918 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1923 unionfs_lock(struct vop_lock1_args *ap)
1925 struct unionfs_node *unp;
1936 * TODO: rework the unionfs locking scheme.
1937 * It's not guaranteed to be safe to blindly lock two vnodes on
1938 * different mounts as is done here. Further, the entanglement
1939 * of locking both vnodes with the various options that can be
1940 * passed to VOP_LOCK() makes this code hard to reason about.
1941 * Instead, consider locking only the upper vnode, or the lower
1942 * vnode is the upper is not present, and taking separate measures
1943 * to lock both vnodes in the few cases when that is needed.
1948 flags = ap->a_flags;
1951 if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
1952 return (VOP_UNLOCK_FLAGS(vp, flags | LK_RELEASE));
1954 if ((flags & LK_INTERLOCK) == 0)
1957 unp = VTOUNIONFS(vp);
1959 goto unionfs_lock_null_vnode;
1961 KASSERT_UNIONFS_VNODE(ap->a_vp);
1963 lvp = unp->un_lowervp;
1964 uvp = unp->un_uppervp;
1966 if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0)
1967 panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK);
1970 * During unmount, the root vnode lock may be taken recursively,
1971 * because it may share the same v_vnlock field as the vnode covered by
1972 * the unionfs mount. The covered vnode is locked across VFS_UNMOUNT(),
1973 * and the same lock may be taken recursively here during vflush()
1974 * issued by unionfs_unmount().
1976 if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE &&
1977 (vp->v_vflag & VV_ROOT) != 0)
1978 flags |= LK_CANRECURSE;
1980 if (lvp != NULLVP) {
1981 if (uvp != NULLVP && flags & LK_UPGRADE) {
1983 * Share Lock is once released and a deadlock is
1990 VI_LOCK_FLAGS(lvp, MTX_DUPOK);
1991 flags |= LK_INTERLOCK;
1995 ap->a_flags &= ~LK_INTERLOCK;
1997 error = VOP_LOCK(lvp, flags);
2000 unp = VTOUNIONFS(vp);
2002 /* vnode is released. */
2009 goto unionfs_lock_fallback;
2013 if (error == 0 && uvp != NULLVP) {
2014 if (uhold && flags & LK_UPGRADE) {
2015 flags &= ~LK_TYPE_MASK;
2016 flags |= LK_EXCLUSIVE;
2018 VI_LOCK_FLAGS(uvp, MTX_DUPOK);
2019 flags |= LK_INTERLOCK;
2026 ap->a_flags &= ~LK_INTERLOCK;
2028 error = VOP_LOCK(uvp, flags);
2031 unp = VTOUNIONFS(vp);
2033 /* vnode is released. */
2038 if (lvp != NULLVP) {
2042 goto unionfs_lock_fallback;
2044 if (error != 0 && lvp != NULLVP) {
2047 unionfs_revlock(lvp, revlock);
2061 unionfs_lock_null_vnode:
2062 ap->a_flags |= LK_INTERLOCK;
2063 return (vop_stdlock(ap));
2065 unionfs_lock_fallback:
2067 * If we reach this point, we've discovered the unionfs vnode
2068 * has been reclaimed while the upper/lower vnode locks were
2069 * temporarily dropped. Such temporary droppage may happen
2070 * during the course of an LK_UPGRADE operation itself, and in
2071 * that case LK_UPGRADE must be cleared as the unionfs vnode's
2072 * lock has been reset to point to the standard v_lock field,
2073 * which has not previously been held.
2075 if (flags & LK_UPGRADE) {
2076 ap->a_flags &= ~LK_TYPE_MASK;
2077 ap->a_flags |= LK_EXCLUSIVE;
2079 return (vop_stdlock(ap));
2083 unionfs_unlock(struct vop_unlock_args *ap)
2088 struct unionfs_node *unp;
2092 KASSERT_UNIONFS_VNODE(ap->a_vp);
2098 unp = VTOUNIONFS(vp);
2100 goto unionfs_unlock_null_vnode;
2101 lvp = unp->un_lowervp;
2102 uvp = unp->un_uppervp;
2104 if (lvp != NULLVP) {
2106 error = VOP_UNLOCK(lvp);
2109 if (error == 0 && uvp != NULLVP) {
2112 error = VOP_UNLOCK(uvp);
2122 unionfs_unlock_null_vnode:
2123 return (vop_stdunlock(ap));
2127 unionfs_pathconf(struct vop_pathconf_args *ap)
2129 struct unionfs_node *unp;
2132 KASSERT_UNIONFS_VNODE(ap->a_vp);
2134 unp = VTOUNIONFS(ap->a_vp);
2135 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2137 return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
2141 unionfs_advlock(struct vop_advlock_args *ap)
2143 struct unionfs_node *unp;
2144 struct unionfs_node_status *unsp;
2150 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
2152 KASSERT_UNIONFS_VNODE(ap->a_vp);
2157 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2159 unp = VTOUNIONFS(ap->a_vp);
2160 uvp = unp->un_uppervp;
2162 if (uvp == NULLVP) {
2163 error = unionfs_copyfile(unp, 1, td->td_ucred, td);
2165 goto unionfs_advlock_abort;
2166 uvp = unp->un_uppervp;
2168 unionfs_get_node_status(unp, td, &unsp);
2169 if (unsp->uns_lower_opencnt > 0) {
2170 /* try reopen the vnode */
2171 error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
2172 td->td_ucred, td, NULL);
2174 goto unionfs_advlock_abort;
2175 unsp->uns_upper_opencnt++;
2176 VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode,
2178 unsp->uns_lower_opencnt--;
2180 unionfs_tryrem_node_status(unp, unsp);
2185 error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
2187 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2191 unionfs_advlock_abort:
2194 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2200 unionfs_strategy(struct vop_strategy_args *ap)
2202 struct unionfs_node *unp;
2205 KASSERT_UNIONFS_VNODE(ap->a_vp);
2207 unp = VTOUNIONFS(ap->a_vp);
2208 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2212 panic("unionfs_strategy: nullvp");
2214 if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
2215 panic("unionfs_strategy: writing to lowervp");
2218 return (VOP_STRATEGY(vp, ap->a_bp));
2222 unionfs_getacl(struct vop_getacl_args *ap)
2224 struct unionfs_node *unp;
2228 KASSERT_UNIONFS_VNODE(ap->a_vp);
2230 unp = VTOUNIONFS(ap->a_vp);
2231 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2233 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
2235 error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2237 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
2243 unionfs_setacl(struct vop_setacl_args *ap)
2245 struct unionfs_node *unp;
2251 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
2253 KASSERT_UNIONFS_VNODE(ap->a_vp);
2256 unp = VTOUNIONFS(ap->a_vp);
2257 uvp = unp->un_uppervp;
2258 lvp = unp->un_lowervp;
2261 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2264 if (uvp == NULLVP && lvp->v_type == VREG) {
2265 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2267 uvp = unp->un_uppervp;
2271 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
2273 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
2279 unionfs_aclcheck(struct vop_aclcheck_args *ap)
2281 struct unionfs_node *unp;
2285 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
2287 KASSERT_UNIONFS_VNODE(ap->a_vp);
2289 unp = VTOUNIONFS(ap->a_vp);
2290 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2292 error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2294 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
2300 unionfs_openextattr(struct vop_openextattr_args *ap)
2302 struct unionfs_node *unp;
2307 KASSERT_UNIONFS_VNODE(ap->a_vp);
2310 unp = VTOUNIONFS(vp);
2311 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2313 if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
2314 (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
2317 error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
2320 if (vn_lock(vp, LK_UPGRADE) != 0)
2321 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2322 if (!VN_IS_DOOMED(vp)) {
2323 if (tvp == unp->un_uppervp)
2324 unp->un_flag |= UNIONFS_OPENEXTU;
2326 unp->un_flag |= UNIONFS_OPENEXTL;
2328 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2335 unionfs_closeextattr(struct vop_closeextattr_args *ap)
2337 struct unionfs_node *unp;
2342 KASSERT_UNIONFS_VNODE(ap->a_vp);
2345 unp = VTOUNIONFS(vp);
2348 if (unp->un_flag & UNIONFS_OPENEXTU)
2349 tvp = unp->un_uppervp;
2350 else if (unp->un_flag & UNIONFS_OPENEXTL)
2351 tvp = unp->un_lowervp;
2354 return (EOPNOTSUPP);
2356 error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
2359 if (vn_lock(vp, LK_UPGRADE) != 0)
2360 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2361 if (!VN_IS_DOOMED(vp)) {
2362 if (tvp == unp->un_uppervp)
2363 unp->un_flag &= ~UNIONFS_OPENEXTU;
2365 unp->un_flag &= ~UNIONFS_OPENEXTL;
2367 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2374 unionfs_getextattr(struct vop_getextattr_args *ap)
2376 struct unionfs_node *unp;
2379 KASSERT_UNIONFS_VNODE(ap->a_vp);
2381 unp = VTOUNIONFS(ap->a_vp);
2384 if (unp->un_flag & UNIONFS_OPENEXTU)
2385 vp = unp->un_uppervp;
2386 else if (unp->un_flag & UNIONFS_OPENEXTL)
2387 vp = unp->un_lowervp;
2390 return (EOPNOTSUPP);
2392 return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
2393 ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
2397 unionfs_setextattr(struct vop_setextattr_args *ap)
2399 struct unionfs_node *unp;
2407 KASSERT_UNIONFS_VNODE(ap->a_vp);
2410 unp = VTOUNIONFS(ap->a_vp);
2411 uvp = unp->un_uppervp;
2412 lvp = unp->un_lowervp;
2417 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n",
2420 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2423 if (unp->un_flag & UNIONFS_OPENEXTU)
2424 ovp = unp->un_uppervp;
2425 else if (unp->un_flag & UNIONFS_OPENEXTL)
2426 ovp = unp->un_lowervp;
2429 return (EOPNOTSUPP);
2431 if (ovp == lvp && lvp->v_type == VREG) {
2432 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2433 if (uvp == NULLVP &&
2434 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2435 unionfs_setextattr_reopen:
2436 if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2437 VOP_OPENEXTATTR(lvp, cred, td)) {
2439 panic("unionfs: VOP_OPENEXTATTR failed");
2441 unp->un_flag &= ~UNIONFS_OPENEXTL;
2443 goto unionfs_setextattr_abort;
2445 uvp = unp->un_uppervp;
2446 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2447 goto unionfs_setextattr_reopen;
2448 unp->un_flag &= ~UNIONFS_OPENEXTL;
2449 unp->un_flag |= UNIONFS_OPENEXTU;
2454 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2455 ap->a_uio, cred, td);
2457 unionfs_setextattr_abort:
2458 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
2464 unionfs_listextattr(struct vop_listextattr_args *ap)
2466 struct unionfs_node *unp;
2469 KASSERT_UNIONFS_VNODE(ap->a_vp);
2471 unp = VTOUNIONFS(ap->a_vp);
2474 if (unp->un_flag & UNIONFS_OPENEXTU)
2475 vp = unp->un_uppervp;
2476 else if (unp->un_flag & UNIONFS_OPENEXTL)
2477 vp = unp->un_lowervp;
2480 return (EOPNOTSUPP);
2482 return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
2483 ap->a_size, ap->a_cred, ap->a_td));
2487 unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
2489 struct unionfs_node *unp;
2497 KASSERT_UNIONFS_VNODE(ap->a_vp);
2500 unp = VTOUNIONFS(ap->a_vp);
2501 uvp = unp->un_uppervp;
2502 lvp = unp->un_lowervp;
2507 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n",
2510 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2513 if (unp->un_flag & UNIONFS_OPENEXTU)
2514 ovp = unp->un_uppervp;
2515 else if (unp->un_flag & UNIONFS_OPENEXTL)
2516 ovp = unp->un_lowervp;
2519 return (EOPNOTSUPP);
2521 if (ovp == lvp && lvp->v_type == VREG) {
2522 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2523 if (uvp == NULLVP &&
2524 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2525 unionfs_deleteextattr_reopen:
2526 if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2527 VOP_OPENEXTATTR(lvp, cred, td)) {
2529 panic("unionfs: VOP_OPENEXTATTR failed");
2531 unp->un_flag &= ~UNIONFS_OPENEXTL;
2533 goto unionfs_deleteextattr_abort;
2535 uvp = unp->un_uppervp;
2536 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2537 goto unionfs_deleteextattr_reopen;
2538 unp->un_flag &= ~UNIONFS_OPENEXTL;
2539 unp->un_flag |= UNIONFS_OPENEXTU;
2544 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2545 ap->a_cred, ap->a_td);
2547 unionfs_deleteextattr_abort:
2548 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
2554 unionfs_setlabel(struct vop_setlabel_args *ap)
2556 struct unionfs_node *unp;
2562 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
2564 KASSERT_UNIONFS_VNODE(ap->a_vp);
2567 unp = VTOUNIONFS(ap->a_vp);
2568 uvp = unp->un_uppervp;
2569 lvp = unp->un_lowervp;
2572 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2575 if (uvp == NULLVP && lvp->v_type == VREG) {
2576 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2578 uvp = unp->un_uppervp;
2582 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
2584 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
2590 unionfs_vptofh(struct vop_vptofh_args *ap)
2592 return (EOPNOTSUPP);
2596 unionfs_add_writecount(struct vop_add_writecount_args *ap)
2598 struct vnode *tvp, *vp;
2599 struct unionfs_node *unp;
2600 int error, writerefs __diagused;
2603 unp = VTOUNIONFS(vp);
2604 tvp = unp->un_uppervp;
2605 KASSERT(tvp != NULL,
2606 ("%s: adding write ref without upper vnode", __func__));
2607 error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc);
2611 * We need to track the write refs we've passed to the underlying
2612 * vnodes so that we can undo them in case we are forcibly unmounted.
2614 writerefs = atomic_fetchadd_int(&vp->v_writecount, ap->a_inc);
2615 /* text refs are bypassed to lowervp */
2616 VNASSERT(writerefs >= 0, vp,
2617 ("%s: invalid write count %d", __func__, writerefs));
2618 VNASSERT(writerefs + ap->a_inc >= 0, vp,
2619 ("%s: invalid write count inc %d + %d", __func__,
2620 writerefs, ap->a_inc));
2625 unionfs_vput_pair(struct vop_vput_pair_args *ap)
2628 struct vnode *dvp, *vp, **vpp, *lvp, *ldvp, *uvp, *udvp, *tempvp;
2629 struct unionfs_node *dunp, *unp;
2639 dunp = VTOUNIONFS(dvp);
2640 udvp = dunp->un_uppervp;
2641 ldvp = dunp->un_lowervp;
2644 * Underlying vnodes should be locked because the encompassing unionfs
2645 * node is locked, but will not be referenced, as the reference will
2646 * only be on the unionfs node. Reference them now so that the vput()s
2647 * performed by VOP_VPUT_PAIR() will have a reference to drop.
2658 unp = VTOUNIONFS(vp);
2659 uvp = unp->un_uppervp;
2660 lvp = unp->un_lowervp;
2667 * If we're being asked to return a locked child vnode, then
2668 * we may need to create a replacement vnode in case the
2669 * original is reclaimed while the lock is dropped. In that
2670 * case we'll need to ensure the mount and the underlying
2671 * vnodes aren't also recycled during that window.
2673 if (!ap->a_unlock_vp) {
2685 * TODO: Because unionfs_lock() locks both the lower and upper vnodes
2686 * (if available), we must also call VOP_VPUT_PAIR() on both the lower
2687 * and upper parent/child pairs. If unionfs_lock() is reworked to lock
2688 * only a single vnode, this code will need to change to also only
2689 * operate on one vnode pair.
2691 ASSERT_VOP_LOCKED(ldvp, __func__);
2692 ASSERT_VOP_LOCKED(udvp, __func__);
2693 ASSERT_VOP_LOCKED(lvp, __func__);
2694 ASSERT_VOP_LOCKED(uvp, __func__);
2696 KASSERT(lvp == NULLVP || ldvp != NULLVP,
2697 ("%s: NULL ldvp with non-NULL lvp", __func__));
2699 res = VOP_VPUT_PAIR(ldvp, lvp != NULLVP ? &lvp : NULL, true);
2700 KASSERT(uvp == NULLVP || udvp != NULLVP,
2701 ("%s: NULL udvp with non-NULL uvp", __func__));
2703 res = VOP_VPUT_PAIR(udvp, uvp != NULLVP ? &uvp : NULL, true);
2705 ASSERT_VOP_UNLOCKED(ldvp, __func__);
2706 ASSERT_VOP_UNLOCKED(udvp, __func__);
2707 ASSERT_VOP_UNLOCKED(lvp, __func__);
2708 ASSERT_VOP_UNLOCKED(uvp, __func__);
2711 * VOP_VPUT_PAIR() dropped the references we added to the underlying
2712 * vnodes, now drop the caller's reference to the unionfs vnodes.
2714 if (vp != NULLVP && ap->a_unlock_vp)
2718 if (vp == NULLVP || ap->a_unlock_vp)
2722 * We're being asked to return a locked vnode. At this point, the
2723 * underlying vnodes have been unlocked, so vp may have been reclaimed.
2725 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2726 if (vp->v_data == NULL && vfs_busy(mp, MBF_NOWAIT) == 0) {
2728 error = unionfs_nodeget(mp, uvp, lvp, dvp, &tempvp, NULL);
2730 vn_lock(tempvp, LK_EXCLUSIVE | LK_RETRY);
2733 vget(vp, LK_EXCLUSIVE | LK_RETRY);
2747 unionfs_set_text(struct vop_set_text_args *ap)
2750 struct unionfs_node *unp;
2754 * We assume text refs are managed against lvp/uvp through the
2755 * executable mapping backed by its VM object. We therefore don't
2756 * need to track leased text refs in the case of a forcible unmount.
2758 unp = VTOUNIONFS(ap->a_vp);
2759 ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2760 tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2761 error = VOP_SET_TEXT(tvp);
2766 unionfs_unset_text(struct vop_unset_text_args *ap)
2769 struct unionfs_node *unp;
2771 ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2772 unp = VTOUNIONFS(ap->a_vp);
2773 tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2774 VOP_UNSET_TEXT_CHECKED(tvp);
2778 struct vop_vector unionfs_vnodeops = {
2779 .vop_default = &default_vnodeops,
2781 .vop_access = unionfs_access,
2782 .vop_aclcheck = unionfs_aclcheck,
2783 .vop_advlock = unionfs_advlock,
2784 .vop_bmap = VOP_EOPNOTSUPP,
2785 .vop_cachedlookup = unionfs_lookup,
2786 .vop_close = unionfs_close,
2787 .vop_closeextattr = unionfs_closeextattr,
2788 .vop_create = unionfs_create,
2789 .vop_deleteextattr = unionfs_deleteextattr,
2790 .vop_fsync = unionfs_fsync,
2791 .vop_getacl = unionfs_getacl,
2792 .vop_getattr = unionfs_getattr,
2793 .vop_getextattr = unionfs_getextattr,
2794 .vop_getwritemount = unionfs_getwritemount,
2795 .vop_inactive = unionfs_inactive,
2796 .vop_need_inactive = vop_stdneed_inactive,
2797 .vop_islocked = vop_stdislocked,
2798 .vop_ioctl = unionfs_ioctl,
2799 .vop_link = unionfs_link,
2800 .vop_listextattr = unionfs_listextattr,
2801 .vop_lock1 = unionfs_lock,
2802 .vop_lookup = vfs_cache_lookup,
2803 .vop_mkdir = unionfs_mkdir,
2804 .vop_mknod = unionfs_mknod,
2805 .vop_open = unionfs_open,
2806 .vop_openextattr = unionfs_openextattr,
2807 .vop_pathconf = unionfs_pathconf,
2808 .vop_poll = unionfs_poll,
2809 .vop_print = unionfs_print,
2810 .vop_read = unionfs_read,
2811 .vop_readdir = unionfs_readdir,
2812 .vop_readlink = unionfs_readlink,
2813 .vop_reclaim = unionfs_reclaim,
2814 .vop_remove = unionfs_remove,
2815 .vop_rename = unionfs_rename,
2816 .vop_rmdir = unionfs_rmdir,
2817 .vop_setacl = unionfs_setacl,
2818 .vop_setattr = unionfs_setattr,
2819 .vop_setextattr = unionfs_setextattr,
2820 .vop_setlabel = unionfs_setlabel,
2821 .vop_strategy = unionfs_strategy,
2822 .vop_symlink = unionfs_symlink,
2823 .vop_unlock = unionfs_unlock,
2824 .vop_whiteout = unionfs_whiteout,
2825 .vop_write = unionfs_write,
2826 .vop_vptofh = unionfs_vptofh,
2827 .vop_add_writecount = unionfs_add_writecount,
2828 .vop_vput_pair = unionfs_vput_pair,
2829 .vop_set_text = unionfs_set_text,
2830 .vop_unset_text = unionfs_unset_text,
2832 VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);