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;
1399 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1401 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1405 dunp = VTOUNIONFS(dvp);
1407 lkflags = cnp->cn_lkflags;
1408 udvp = dunp->un_uppervp;
1410 if (udvp != NULLVP) {
1413 if (!(cnp->cn_flags & ISWHITEOUT)) {
1414 error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
1416 goto unionfs_mkdir_cleanup;
1417 if ((va.va_flags & OPAQUE) != 0)
1418 cnp->cn_flags |= ISWHITEOUT;
1421 if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) {
1423 cnp->cn_lkflags = LK_EXCLUSIVE;
1425 * The underlying VOP_MKDIR() implementation may have
1426 * temporarily dropped the parent directory vnode lock.
1427 * Because the unionfs vnode ordinarily shares that
1428 * lock, this may allow the unionfs vnode to be reclaimed
1429 * and its lock field reset. In that case, the unionfs
1430 * vnode is effectively no longer locked, and we must
1431 * explicitly lock it before returning in order to meet
1432 * the locking requirements of VOP_MKDIR().
1434 if (__predict_false(VTOUNIONFS(dvp) == NULL)) {
1436 goto unionfs_mkdir_cleanup;
1438 error = unionfs_nodeget(dvp->v_mount, uvp, NULLVP,
1439 dvp, ap->a_vpp, cnp);
1440 cnp->cn_lkflags = lkflags;
1445 unionfs_mkdir_cleanup:
1447 if (__predict_false(VTOUNIONFS(dvp) == NULL)) {
1449 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1450 } else if (udvp != NULLVP)
1453 UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
1459 unionfs_rmdir(struct vop_rmdir_args *ap)
1461 struct unionfs_node *dunp;
1462 struct unionfs_node *unp;
1463 struct unionfs_mount *ump;
1464 struct componentname *cnp;
1471 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1473 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1474 KASSERT_UNIONFS_VNODE(ap->a_vp);
1477 dunp = VTOUNIONFS(ap->a_dvp);
1478 unp = VTOUNIONFS(ap->a_vp);
1481 udvp = dunp->un_uppervp;
1482 uvp = unp->un_uppervp;
1483 lvp = unp->un_lowervp;
1489 return (EOPNOTSUPP);
1491 if (uvp != NULLVP) {
1492 if (lvp != NULLVP) {
1493 error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
1497 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1498 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP)
1499 cnp->cn_flags |= DOWHITEOUT;
1501 * The relookup path will need to relock the parent dvp and
1502 * possibly the vp as well. Locking is expected to be done
1503 * in parent->child order; drop the lock on vp to avoid LOR
1504 * and potential recursion on vp's lock.
1505 * vp is expected to remain referenced during VOP_RMDIR(),
1506 * so vref/vrele should not be necessary here.
1508 VOP_UNLOCK(ap->a_vp);
1509 VNPASS(vrefcnt(ap->a_vp) > 0, ap->a_vp);
1510 error = unionfs_relookup_for_delete(ap->a_dvp, cnp, td);
1511 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1513 * VOP_RMDIR is dispatched against udvp, so if uvp became
1514 * doomed while the lock was dropped above the target
1515 * filesystem may not be able to cope.
1517 if (error == 0 && VN_IS_DOOMED(uvp))
1520 error = VOP_RMDIR(udvp, uvp, cnp);
1521 } else if (lvp != NULLVP)
1522 error = unionfs_mkwhiteout(udvp, cnp, td,
1523 unp->un_path, unp->un_pathlen);
1526 cache_purge(ap->a_dvp);
1527 cache_purge(ap->a_vp);
1530 UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
1536 unionfs_symlink(struct vop_symlink_args *ap)
1538 struct unionfs_node *dunp;
1539 struct componentname *cnp;
1545 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1547 KASSERT_UNIONFS_VNODE(ap->a_dvp);
1550 dunp = VTOUNIONFS(ap->a_dvp);
1552 lkflags = cnp->cn_lkflags;
1553 udvp = dunp->un_uppervp;
1555 if (udvp != NULLVP) {
1556 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
1559 cnp->cn_lkflags = LK_EXCLUSIVE;
1560 error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1561 ap->a_dvp, ap->a_vpp, cnp);
1562 cnp->cn_lkflags = lkflags;
1567 UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
1573 unionfs_readdir(struct vop_readdir_args *ap)
1575 struct unionfs_node *unp;
1576 struct unionfs_node_status *unsp;
1584 uint64_t *cookies_bk;
1589 enum unionfs_lkupgrade lkstatus;
1591 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1593 KASSERT_UNIONFS_VNODE(ap->a_vp);
1606 if (vp->v_type != VDIR)
1610 * If the vnode is reclaimed while upgrading, we can't safely use unp
1611 * or do anything else unionfs- specific.
1613 lkstatus = unionfs_upgrade_lock(vp);
1614 if (lkstatus == UNIONFS_LKUPGRADE_DOOMED)
1617 unp = VTOUNIONFS(vp);
1618 uvp = unp->un_uppervp;
1619 lvp = unp->un_lowervp;
1620 /* check the open count. unionfs needs open before readdir. */
1621 unionfs_get_node_status(unp, td, &unsp);
1622 if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) ||
1623 (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) {
1624 unionfs_tryrem_node_status(unp, unsp);
1628 unionfs_downgrade_lock(vp, lkstatus);
1630 goto unionfs_readdir_exit;
1633 if (uvp != NULLVP && lvp != NULLVP) {
1634 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0)
1635 goto unionfs_readdir_exit;
1636 if (va.va_flags & OPAQUE)
1641 if (uvp != NULLVP && lvp == NULLVP) {
1642 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
1643 ap->a_ncookies, ap->a_cookies);
1644 unsp->uns_readdir_status = 0;
1646 goto unionfs_readdir_exit;
1650 if (uvp == NULLVP && lvp != NULLVP) {
1651 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1652 ap->a_ncookies, ap->a_cookies);
1653 unsp->uns_readdir_status = 2;
1655 goto unionfs_readdir_exit;
1659 * readdir upper and lower
1661 KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp"));
1662 KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp"));
1663 if (uio->uio_offset == 0)
1664 unsp->uns_readdir_status = 0;
1666 if (unsp->uns_readdir_status == 0) {
1668 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
1669 ap->a_ncookies, ap->a_cookies);
1671 if (error != 0 || eofflag == 0)
1672 goto unionfs_readdir_exit;
1673 unsp->uns_readdir_status = 1;
1676 * UFS(and other FS) needs size of uio_resid larger than
1678 * size of DIRBLKSIZ equals DEV_BSIZE.
1679 * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1681 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
1682 goto unionfs_readdir_exit;
1686 * It prepares to readdir in lower.
1688 if (ap->a_ncookies != NULL) {
1689 ncookies_bk = *(ap->a_ncookies);
1690 *(ap->a_ncookies) = 0;
1692 if (ap->a_cookies != NULL) {
1693 cookies_bk = *(ap->a_cookies);
1694 *(ap->a_cookies) = NULL;
1698 /* initialize for readdir in lower */
1699 if (unsp->uns_readdir_status == 1) {
1700 unsp->uns_readdir_status = 2;
1702 * Backup uio_offset. See the comment after the
1703 * VOP_READDIR call on the lower layer.
1705 uio_offset_bk = uio->uio_offset;
1706 uio->uio_offset = 0;
1709 if (lvp == NULLVP) {
1711 goto unionfs_readdir_exit;
1714 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1715 ap->a_ncookies, ap->a_cookies);
1718 * We can't return an uio_offset of 0: this would trigger an
1719 * infinite loop, because the next call to unionfs_readdir would
1720 * always restart with the upper layer (uio_offset == 0) and
1721 * always return some data.
1723 * This happens when the lower layer root directory is removed.
1724 * (A root directory deleting of unionfs should not be permitted.
1725 * But current VFS can not do it.)
1727 if (uio->uio_offset == 0)
1728 uio->uio_offset = uio_offset_bk;
1730 if (cookies_bk != NULL) {
1733 uint64_t *newcookies, *pos;
1735 size = *(ap->a_ncookies) + ncookies_bk;
1736 newcookies = (uint64_t *) malloc(size * sizeof(*newcookies),
1740 memcpy(pos, cookies_bk, ncookies_bk * sizeof(*newcookies));
1742 memcpy(pos, *(ap->a_cookies),
1743 *(ap->a_ncookies) * sizeof(*newcookies));
1744 free(cookies_bk, M_TEMP);
1745 free(*(ap->a_cookies), M_TEMP);
1746 *(ap->a_ncookies) = size;
1747 *(ap->a_cookies) = newcookies;
1750 unionfs_readdir_exit:
1751 if (error != 0 && ap->a_eofflag != NULL)
1752 *(ap->a_eofflag) = 1;
1754 UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
1760 unionfs_readlink(struct vop_readlink_args *ap)
1762 struct unionfs_node *unp;
1766 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
1768 KASSERT_UNIONFS_VNODE(ap->a_vp);
1770 unp = VTOUNIONFS(ap->a_vp);
1771 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1773 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
1775 UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
1781 unionfs_getwritemount(struct vop_getwritemount_args *ap)
1783 struct unionfs_node *unp;
1785 struct vnode *vp, *ovp;
1788 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
1795 unp = VTOUNIONFS(vp);
1797 uvp = unp->un_uppervp;
1800 * If our node has no upper vnode, check the parent directory.
1801 * We may be initiating a write operation that will produce a
1802 * new upper vnode through CoW.
1804 if (uvp == NULLVP && unp != NULL) {
1808 * Only the root vnode should have an empty parent, but it
1809 * should not have an empty uppervp, so we shouldn't get here.
1811 VNASSERT(vp != NULL, ovp, ("%s: NULL parent vnode", __func__));
1814 unp = VTOUNIONFS(vp);
1816 uvp = unp->un_uppervp;
1821 if (uvp != NULLVP) {
1824 error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
1828 *(ap->a_mpp) = NULL;
1831 UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);
1837 unionfs_inactive(struct vop_inactive_args *ap)
1839 ap->a_vp->v_object = NULL;
1845 unionfs_reclaim(struct vop_reclaim_args *ap)
1847 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
1849 unionfs_noderem(ap->a_vp);
1851 /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
1857 unionfs_print(struct vop_print_args *ap)
1859 struct unionfs_node *unp;
1860 /* struct unionfs_node_status *unsp; */
1862 unp = VTOUNIONFS(ap->a_vp);
1863 /* unionfs_get_node_status(unp, curthread, &unsp); */
1865 printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
1866 ap->a_vp, unp->un_uppervp, unp->un_lowervp);
1868 printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
1869 unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
1872 if (unp->un_uppervp != NULLVP)
1873 vn_printf(unp->un_uppervp, "unionfs: upper ");
1874 if (unp->un_lowervp != NULLVP)
1875 vn_printf(unp->un_lowervp, "unionfs: lower ");
1881 unionfs_get_llt_revlock(struct vnode *vp, int flags)
1887 switch (flags & LK_TYPE_MASK) {
1889 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
1890 revlock = LK_UPGRADE;
1892 revlock = LK_RELEASE;
1896 revlock = LK_RELEASE;
1899 revlock = LK_UPGRADE;
1909 * The state of an acquired lock is adjusted similarly to
1910 * the time of error generating.
1911 * flags: LK_RELEASE or LK_UPGRADE
1914 unionfs_revlock(struct vnode *vp, int flags)
1916 if (flags & LK_RELEASE)
1917 VOP_UNLOCK_FLAGS(vp, flags);
1920 if (vn_lock(vp, flags) != 0)
1921 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1926 unionfs_lock(struct vop_lock1_args *ap)
1928 struct unionfs_node *unp;
1939 * TODO: rework the unionfs locking scheme.
1940 * It's not guaranteed to be safe to blindly lock two vnodes on
1941 * different mounts as is done here. Further, the entanglement
1942 * of locking both vnodes with the various options that can be
1943 * passed to VOP_LOCK() makes this code hard to reason about.
1944 * Instead, consider locking only the upper vnode, or the lower
1945 * vnode is the upper is not present, and taking separate measures
1946 * to lock both vnodes in the few cases when that is needed.
1951 flags = ap->a_flags;
1954 if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
1955 return (VOP_UNLOCK_FLAGS(vp, flags | LK_RELEASE));
1957 if ((flags & LK_INTERLOCK) == 0)
1960 unp = VTOUNIONFS(vp);
1962 goto unionfs_lock_null_vnode;
1964 KASSERT_UNIONFS_VNODE(ap->a_vp);
1966 lvp = unp->un_lowervp;
1967 uvp = unp->un_uppervp;
1969 if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0)
1970 panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK);
1973 * During unmount, the root vnode lock may be taken recursively,
1974 * because it may share the same v_vnlock field as the vnode covered by
1975 * the unionfs mount. The covered vnode is locked across VFS_UNMOUNT(),
1976 * and the same lock may be taken recursively here during vflush()
1977 * issued by unionfs_unmount().
1979 if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE &&
1980 (vp->v_vflag & VV_ROOT) != 0)
1981 flags |= LK_CANRECURSE;
1983 if (lvp != NULLVP) {
1984 if (uvp != NULLVP && flags & LK_UPGRADE) {
1986 * Share Lock is once released and a deadlock is
1993 VI_LOCK_FLAGS(lvp, MTX_DUPOK);
1994 flags |= LK_INTERLOCK;
1998 ap->a_flags &= ~LK_INTERLOCK;
2000 error = VOP_LOCK(lvp, flags);
2003 unp = VTOUNIONFS(vp);
2005 /* vnode is released. */
2012 goto unionfs_lock_fallback;
2016 if (error == 0 && uvp != NULLVP) {
2017 if (uhold && flags & LK_UPGRADE) {
2018 flags &= ~LK_TYPE_MASK;
2019 flags |= LK_EXCLUSIVE;
2021 VI_LOCK_FLAGS(uvp, MTX_DUPOK);
2022 flags |= LK_INTERLOCK;
2029 ap->a_flags &= ~LK_INTERLOCK;
2031 error = VOP_LOCK(uvp, flags);
2034 unp = VTOUNIONFS(vp);
2036 /* vnode is released. */
2041 if (lvp != NULLVP) {
2045 goto unionfs_lock_fallback;
2047 if (error != 0 && lvp != NULLVP) {
2050 unionfs_revlock(lvp, revlock);
2064 unionfs_lock_null_vnode:
2065 ap->a_flags |= LK_INTERLOCK;
2066 return (vop_stdlock(ap));
2068 unionfs_lock_fallback:
2070 * If we reach this point, we've discovered the unionfs vnode
2071 * has been reclaimed while the upper/lower vnode locks were
2072 * temporarily dropped. Such temporary droppage may happen
2073 * during the course of an LK_UPGRADE operation itself, and in
2074 * that case LK_UPGRADE must be cleared as the unionfs vnode's
2075 * lock has been reset to point to the standard v_lock field,
2076 * which has not previously been held.
2078 if (flags & LK_UPGRADE) {
2079 ap->a_flags &= ~LK_TYPE_MASK;
2080 ap->a_flags |= LK_EXCLUSIVE;
2082 return (vop_stdlock(ap));
2086 unionfs_unlock(struct vop_unlock_args *ap)
2091 struct unionfs_node *unp;
2095 KASSERT_UNIONFS_VNODE(ap->a_vp);
2101 unp = VTOUNIONFS(vp);
2103 goto unionfs_unlock_null_vnode;
2104 lvp = unp->un_lowervp;
2105 uvp = unp->un_uppervp;
2107 if (lvp != NULLVP) {
2109 error = VOP_UNLOCK(lvp);
2112 if (error == 0 && uvp != NULLVP) {
2115 error = VOP_UNLOCK(uvp);
2125 unionfs_unlock_null_vnode:
2126 return (vop_stdunlock(ap));
2130 unionfs_pathconf(struct vop_pathconf_args *ap)
2132 struct unionfs_node *unp;
2135 KASSERT_UNIONFS_VNODE(ap->a_vp);
2137 unp = VTOUNIONFS(ap->a_vp);
2138 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2140 return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
2144 unionfs_advlock(struct vop_advlock_args *ap)
2146 struct unionfs_node *unp;
2147 struct unionfs_node_status *unsp;
2153 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
2155 KASSERT_UNIONFS_VNODE(ap->a_vp);
2160 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2162 unp = VTOUNIONFS(ap->a_vp);
2163 uvp = unp->un_uppervp;
2165 if (uvp == NULLVP) {
2166 error = unionfs_copyfile(unp, 1, td->td_ucred, td);
2168 goto unionfs_advlock_abort;
2169 uvp = unp->un_uppervp;
2171 unionfs_get_node_status(unp, td, &unsp);
2172 if (unsp->uns_lower_opencnt > 0) {
2173 /* try reopen the vnode */
2174 error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
2175 td->td_ucred, td, NULL);
2177 goto unionfs_advlock_abort;
2178 unsp->uns_upper_opencnt++;
2179 VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode,
2181 unsp->uns_lower_opencnt--;
2183 unionfs_tryrem_node_status(unp, unsp);
2188 error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
2190 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2194 unionfs_advlock_abort:
2197 UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2203 unionfs_strategy(struct vop_strategy_args *ap)
2205 struct unionfs_node *unp;
2208 KASSERT_UNIONFS_VNODE(ap->a_vp);
2210 unp = VTOUNIONFS(ap->a_vp);
2211 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2215 panic("unionfs_strategy: nullvp");
2217 if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
2218 panic("unionfs_strategy: writing to lowervp");
2221 return (VOP_STRATEGY(vp, ap->a_bp));
2225 unionfs_getacl(struct vop_getacl_args *ap)
2227 struct unionfs_node *unp;
2231 KASSERT_UNIONFS_VNODE(ap->a_vp);
2233 unp = VTOUNIONFS(ap->a_vp);
2234 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2236 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
2238 error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2240 UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
2246 unionfs_setacl(struct vop_setacl_args *ap)
2248 struct unionfs_node *unp;
2254 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
2256 KASSERT_UNIONFS_VNODE(ap->a_vp);
2259 unp = VTOUNIONFS(ap->a_vp);
2260 uvp = unp->un_uppervp;
2261 lvp = unp->un_lowervp;
2264 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2267 if (uvp == NULLVP && lvp->v_type == VREG) {
2268 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2270 uvp = unp->un_uppervp;
2274 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
2276 UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
2282 unionfs_aclcheck(struct vop_aclcheck_args *ap)
2284 struct unionfs_node *unp;
2288 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
2290 KASSERT_UNIONFS_VNODE(ap->a_vp);
2292 unp = VTOUNIONFS(ap->a_vp);
2293 vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2295 error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2297 UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
2303 unionfs_openextattr(struct vop_openextattr_args *ap)
2305 struct unionfs_node *unp;
2310 KASSERT_UNIONFS_VNODE(ap->a_vp);
2313 unp = VTOUNIONFS(vp);
2314 tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2316 if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
2317 (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
2320 error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
2323 if (vn_lock(vp, LK_UPGRADE) != 0)
2324 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2325 if (!VN_IS_DOOMED(vp)) {
2326 if (tvp == unp->un_uppervp)
2327 unp->un_flag |= UNIONFS_OPENEXTU;
2329 unp->un_flag |= UNIONFS_OPENEXTL;
2331 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2338 unionfs_closeextattr(struct vop_closeextattr_args *ap)
2340 struct unionfs_node *unp;
2345 KASSERT_UNIONFS_VNODE(ap->a_vp);
2348 unp = VTOUNIONFS(vp);
2351 if (unp->un_flag & UNIONFS_OPENEXTU)
2352 tvp = unp->un_uppervp;
2353 else if (unp->un_flag & UNIONFS_OPENEXTL)
2354 tvp = unp->un_lowervp;
2357 return (EOPNOTSUPP);
2359 error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
2362 if (vn_lock(vp, LK_UPGRADE) != 0)
2363 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2364 if (!VN_IS_DOOMED(vp)) {
2365 if (tvp == unp->un_uppervp)
2366 unp->un_flag &= ~UNIONFS_OPENEXTU;
2368 unp->un_flag &= ~UNIONFS_OPENEXTL;
2370 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2377 unionfs_getextattr(struct vop_getextattr_args *ap)
2379 struct unionfs_node *unp;
2382 KASSERT_UNIONFS_VNODE(ap->a_vp);
2384 unp = VTOUNIONFS(ap->a_vp);
2387 if (unp->un_flag & UNIONFS_OPENEXTU)
2388 vp = unp->un_uppervp;
2389 else if (unp->un_flag & UNIONFS_OPENEXTL)
2390 vp = unp->un_lowervp;
2393 return (EOPNOTSUPP);
2395 return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
2396 ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
2400 unionfs_setextattr(struct vop_setextattr_args *ap)
2402 struct unionfs_node *unp;
2410 KASSERT_UNIONFS_VNODE(ap->a_vp);
2413 unp = VTOUNIONFS(ap->a_vp);
2414 uvp = unp->un_uppervp;
2415 lvp = unp->un_lowervp;
2420 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n",
2423 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2426 if (unp->un_flag & UNIONFS_OPENEXTU)
2427 ovp = unp->un_uppervp;
2428 else if (unp->un_flag & UNIONFS_OPENEXTL)
2429 ovp = unp->un_lowervp;
2432 return (EOPNOTSUPP);
2434 if (ovp == lvp && lvp->v_type == VREG) {
2435 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2436 if (uvp == NULLVP &&
2437 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2438 unionfs_setextattr_reopen:
2439 if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2440 VOP_OPENEXTATTR(lvp, cred, td)) {
2442 panic("unionfs: VOP_OPENEXTATTR failed");
2444 unp->un_flag &= ~UNIONFS_OPENEXTL;
2446 goto unionfs_setextattr_abort;
2448 uvp = unp->un_uppervp;
2449 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2450 goto unionfs_setextattr_reopen;
2451 unp->un_flag &= ~UNIONFS_OPENEXTL;
2452 unp->un_flag |= UNIONFS_OPENEXTU;
2457 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2458 ap->a_uio, cred, td);
2460 unionfs_setextattr_abort:
2461 UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
2467 unionfs_listextattr(struct vop_listextattr_args *ap)
2469 struct unionfs_node *unp;
2472 KASSERT_UNIONFS_VNODE(ap->a_vp);
2474 unp = VTOUNIONFS(ap->a_vp);
2477 if (unp->un_flag & UNIONFS_OPENEXTU)
2478 vp = unp->un_uppervp;
2479 else if (unp->un_flag & UNIONFS_OPENEXTL)
2480 vp = unp->un_lowervp;
2483 return (EOPNOTSUPP);
2485 return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
2486 ap->a_size, ap->a_cred, ap->a_td));
2490 unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
2492 struct unionfs_node *unp;
2500 KASSERT_UNIONFS_VNODE(ap->a_vp);
2503 unp = VTOUNIONFS(ap->a_vp);
2504 uvp = unp->un_uppervp;
2505 lvp = unp->un_lowervp;
2510 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n",
2513 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2516 if (unp->un_flag & UNIONFS_OPENEXTU)
2517 ovp = unp->un_uppervp;
2518 else if (unp->un_flag & UNIONFS_OPENEXTL)
2519 ovp = unp->un_lowervp;
2522 return (EOPNOTSUPP);
2524 if (ovp == lvp && lvp->v_type == VREG) {
2525 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2526 if (uvp == NULLVP &&
2527 (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2528 unionfs_deleteextattr_reopen:
2529 if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2530 VOP_OPENEXTATTR(lvp, cred, td)) {
2532 panic("unionfs: VOP_OPENEXTATTR failed");
2534 unp->un_flag &= ~UNIONFS_OPENEXTL;
2536 goto unionfs_deleteextattr_abort;
2538 uvp = unp->un_uppervp;
2539 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2540 goto unionfs_deleteextattr_reopen;
2541 unp->un_flag &= ~UNIONFS_OPENEXTL;
2542 unp->un_flag |= UNIONFS_OPENEXTU;
2547 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2548 ap->a_cred, ap->a_td);
2550 unionfs_deleteextattr_abort:
2551 UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
2557 unionfs_setlabel(struct vop_setlabel_args *ap)
2559 struct unionfs_node *unp;
2565 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
2567 KASSERT_UNIONFS_VNODE(ap->a_vp);
2570 unp = VTOUNIONFS(ap->a_vp);
2571 uvp = unp->un_uppervp;
2572 lvp = unp->un_lowervp;
2575 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2578 if (uvp == NULLVP && lvp->v_type == VREG) {
2579 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2581 uvp = unp->un_uppervp;
2585 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
2587 UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
2593 unionfs_vptofh(struct vop_vptofh_args *ap)
2595 return (EOPNOTSUPP);
2599 unionfs_add_writecount(struct vop_add_writecount_args *ap)
2601 struct vnode *tvp, *vp;
2602 struct unionfs_node *unp;
2603 int error, writerefs __diagused;
2606 unp = VTOUNIONFS(vp);
2607 tvp = unp->un_uppervp;
2608 KASSERT(tvp != NULL,
2609 ("%s: adding write ref without upper vnode", __func__));
2610 error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc);
2614 * We need to track the write refs we've passed to the underlying
2615 * vnodes so that we can undo them in case we are forcibly unmounted.
2617 writerefs = atomic_fetchadd_int(&vp->v_writecount, ap->a_inc);
2618 /* text refs are bypassed to lowervp */
2619 VNASSERT(writerefs >= 0, vp,
2620 ("%s: invalid write count %d", __func__, writerefs));
2621 VNASSERT(writerefs + ap->a_inc >= 0, vp,
2622 ("%s: invalid write count inc %d + %d", __func__,
2623 writerefs, ap->a_inc));
2628 unionfs_vput_pair(struct vop_vput_pair_args *ap)
2631 struct vnode *dvp, *vp, **vpp, *lvp, *ldvp, *uvp, *udvp, *tempvp;
2632 struct unionfs_node *dunp, *unp;
2642 dunp = VTOUNIONFS(dvp);
2643 udvp = dunp->un_uppervp;
2644 ldvp = dunp->un_lowervp;
2647 * Underlying vnodes should be locked because the encompassing unionfs
2648 * node is locked, but will not be referenced, as the reference will
2649 * only be on the unionfs node. Reference them now so that the vput()s
2650 * performed by VOP_VPUT_PAIR() will have a reference to drop.
2661 unp = VTOUNIONFS(vp);
2662 uvp = unp->un_uppervp;
2663 lvp = unp->un_lowervp;
2670 * If we're being asked to return a locked child vnode, then
2671 * we may need to create a replacement vnode in case the
2672 * original is reclaimed while the lock is dropped. In that
2673 * case we'll need to ensure the mount and the underlying
2674 * vnodes aren't also recycled during that window.
2676 if (!ap->a_unlock_vp) {
2688 * TODO: Because unionfs_lock() locks both the lower and upper vnodes
2689 * (if available), we must also call VOP_VPUT_PAIR() on both the lower
2690 * and upper parent/child pairs. If unionfs_lock() is reworked to lock
2691 * only a single vnode, this code will need to change to also only
2692 * operate on one vnode pair.
2694 ASSERT_VOP_LOCKED(ldvp, __func__);
2695 ASSERT_VOP_LOCKED(udvp, __func__);
2696 ASSERT_VOP_LOCKED(lvp, __func__);
2697 ASSERT_VOP_LOCKED(uvp, __func__);
2699 KASSERT(lvp == NULLVP || ldvp != NULLVP,
2700 ("%s: NULL ldvp with non-NULL lvp", __func__));
2702 res = VOP_VPUT_PAIR(ldvp, lvp != NULLVP ? &lvp : NULL, true);
2703 KASSERT(uvp == NULLVP || udvp != NULLVP,
2704 ("%s: NULL udvp with non-NULL uvp", __func__));
2706 res = VOP_VPUT_PAIR(udvp, uvp != NULLVP ? &uvp : NULL, true);
2708 ASSERT_VOP_UNLOCKED(ldvp, __func__);
2709 ASSERT_VOP_UNLOCKED(udvp, __func__);
2710 ASSERT_VOP_UNLOCKED(lvp, __func__);
2711 ASSERT_VOP_UNLOCKED(uvp, __func__);
2714 * VOP_VPUT_PAIR() dropped the references we added to the underlying
2715 * vnodes, now drop the caller's reference to the unionfs vnodes.
2717 if (vp != NULLVP && ap->a_unlock_vp)
2721 if (vp == NULLVP || ap->a_unlock_vp)
2725 * We're being asked to return a locked vnode. At this point, the
2726 * underlying vnodes have been unlocked, so vp may have been reclaimed.
2728 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2729 if (vp->v_data == NULL && vfs_busy(mp, MBF_NOWAIT) == 0) {
2731 error = unionfs_nodeget(mp, uvp, lvp, dvp, &tempvp, NULL);
2733 vn_lock(tempvp, LK_EXCLUSIVE | LK_RETRY);
2736 vget(vp, LK_EXCLUSIVE | LK_RETRY);
2750 unionfs_set_text(struct vop_set_text_args *ap)
2753 struct unionfs_node *unp;
2757 * We assume text refs are managed against lvp/uvp through the
2758 * executable mapping backed by its VM object. We therefore don't
2759 * need to track leased text refs in the case of a forcible unmount.
2761 unp = VTOUNIONFS(ap->a_vp);
2762 ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2763 tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2764 error = VOP_SET_TEXT(tvp);
2769 unionfs_unset_text(struct vop_unset_text_args *ap)
2772 struct unionfs_node *unp;
2774 ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2775 unp = VTOUNIONFS(ap->a_vp);
2776 tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2777 VOP_UNSET_TEXT_CHECKED(tvp);
2781 struct vop_vector unionfs_vnodeops = {
2782 .vop_default = &default_vnodeops,
2784 .vop_access = unionfs_access,
2785 .vop_aclcheck = unionfs_aclcheck,
2786 .vop_advlock = unionfs_advlock,
2787 .vop_bmap = VOP_EOPNOTSUPP,
2788 .vop_cachedlookup = unionfs_lookup,
2789 .vop_close = unionfs_close,
2790 .vop_closeextattr = unionfs_closeextattr,
2791 .vop_create = unionfs_create,
2792 .vop_deleteextattr = unionfs_deleteextattr,
2793 .vop_fsync = unionfs_fsync,
2794 .vop_getacl = unionfs_getacl,
2795 .vop_getattr = unionfs_getattr,
2796 .vop_getextattr = unionfs_getextattr,
2797 .vop_getwritemount = unionfs_getwritemount,
2798 .vop_inactive = unionfs_inactive,
2799 .vop_need_inactive = vop_stdneed_inactive,
2800 .vop_islocked = vop_stdislocked,
2801 .vop_ioctl = unionfs_ioctl,
2802 .vop_link = unionfs_link,
2803 .vop_listextattr = unionfs_listextattr,
2804 .vop_lock1 = unionfs_lock,
2805 .vop_lookup = vfs_cache_lookup,
2806 .vop_mkdir = unionfs_mkdir,
2807 .vop_mknod = unionfs_mknod,
2808 .vop_open = unionfs_open,
2809 .vop_openextattr = unionfs_openextattr,
2810 .vop_pathconf = unionfs_pathconf,
2811 .vop_poll = unionfs_poll,
2812 .vop_print = unionfs_print,
2813 .vop_read = unionfs_read,
2814 .vop_readdir = unionfs_readdir,
2815 .vop_readlink = unionfs_readlink,
2816 .vop_reclaim = unionfs_reclaim,
2817 .vop_remove = unionfs_remove,
2818 .vop_rename = unionfs_rename,
2819 .vop_rmdir = unionfs_rmdir,
2820 .vop_setacl = unionfs_setacl,
2821 .vop_setattr = unionfs_setattr,
2822 .vop_setextattr = unionfs_setextattr,
2823 .vop_setlabel = unionfs_setlabel,
2824 .vop_strategy = unionfs_strategy,
2825 .vop_symlink = unionfs_symlink,
2826 .vop_unlock = unionfs_unlock,
2827 .vop_whiteout = unionfs_whiteout,
2828 .vop_write = unionfs_write,
2829 .vop_vptofh = unionfs_vptofh,
2830 .vop_add_writecount = unionfs_add_writecount,
2831 .vop_vput_pair = unionfs_vput_pair,
2832 .vop_set_text = unionfs_set_text,
2833 .vop_unset_text = unionfs_unset_text,
2835 VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);