union_vnops.c revision 105077
128415Speter/*
234768Speter * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
328415Speter * Copyright (c) 1992, 1993, 1994, 1995
428415Speter *	The Regents of the University of California.  All rights reserved.
528415Speter *
628415Speter * This code is derived from software contributed to Berkeley by
728415Speter * Jan-Simon Pendry.
828415Speter *
928415Speter * Redistribution and use in source and binary forms, with or without
1034768Speter * modification, are permitted provided that the following conditions
1134768Speter * are met:
1228415Speter * 1. Redistributions of source code must retain the above copyright
1350477Speter *    notice, this list of conditions and the following disclaimer.
1428415Speter * 2. Redistributions in binary form must reproduce the above copyright
1528415Speter *    notice, this list of conditions and the following disclaimer in the
1628415Speter *    documentation and/or other materials provided with the distribution.
1734768Speter * 3. All advertising materials mentioning features or use of this software
1828415Speter *    must display the following acknowledgement:
1928415Speter *	This product includes software developed by the University of
2028415Speter *	California, Berkeley and its contributors.
2128415Speter * 4. Neither the name of the University nor the names of its contributors
2228415Speter *    may be used to endorse or promote products derived from this software
2334768Speter *    without specific prior written permission.
2434768Speter *
2534768Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2634768Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2755205Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2834768Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2934768Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3034768Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3134768Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3234768Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3328415Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3434768Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3528415Speter * SUCH DAMAGE.
3628415Speter *
3728415Speter *	@(#)union_vnops.c	8.32 (Berkeley) 6/23/95
3828415Speter * $FreeBSD: head/sys/fs/unionfs/union_vnops.c 105077 2002-10-14 03:20:36Z mckusick $
3928415Speter */
4028415Speter
4128415Speter#include <sys/param.h>
4228415Speter#include <sys/systm.h>
4334768Speter#include <sys/fcntl.h>
4428415Speter#include <sys/stat.h>
4534768Speter#include <sys/kernel.h>
4628415Speter#include <sys/vnode.h>
4728415Speter#include <sys/mount.h>
4855205Speter#include <sys/namei.h>
4928415Speter#include <sys/malloc.h>
5028415Speter#include <sys/bio.h>
5128415Speter#include <sys/buf.h>
5228415Speter#include <sys/lock.h>
5328415Speter#include <sys/sysctl.h>
5455205Speter#include <fs/unionfs/union.h>
5534768Speter
5634768Speter#include <vm/vm.h>
5734768Speter#include <vm/vnode_pager.h>
5834768Speter
59110235Salfred#include <vm/vm_page.h>
60130799Smarkm#include <vm/vm_object.h>
61130799Smarkm
6234768Speterint uniondebug = 0;
6334768Speter
6434768Speter#if UDEBUG_ENABLED
6534768SpeterSYSCTL_INT(_vfs, OID_AUTO, uniondebug, CTLFLAG_RW, &uniondebug, 0, "");
6634768Speter#else
6734768SpeterSYSCTL_INT(_vfs, OID_AUTO, uniondebug, CTLFLAG_RD, &uniondebug, 0, "");
6834768Speter#endif
6934768Speter
7034768Speterstatic int	union_access(struct vop_access_args *ap);
7134768Speterstatic int	union_advlock(struct vop_advlock_args *ap);
7234768Speterstatic int	union_close(struct vop_close_args *ap);
7334768Speterstatic int	union_create(struct vop_create_args *ap);
7434768Speterstatic int	union_createvobject(struct vop_createvobject_args *ap);
7534768Speterstatic int	union_destroyvobject(struct vop_destroyvobject_args *ap);
7634768Speterstatic int	union_fsync(struct vop_fsync_args *ap);
7734768Speterstatic int	union_getattr(struct vop_getattr_args *ap);
7834768Speterstatic int	union_getvobject(struct vop_getvobject_args *ap);
7934768Speterstatic int	union_inactive(struct vop_inactive_args *ap);
8034768Speterstatic int	union_ioctl(struct vop_ioctl_args *ap);
8134768Speterstatic int	union_lease(struct vop_lease_args *ap);
8234768Speterstatic int	union_link(struct vop_link_args *ap);
8355205Speterstatic int	union_lookup(struct vop_lookup_args *ap);
8434768Speterstatic int	union_lookup1(struct vnode *udvp, struct vnode **dvp,
8528415Speter				   struct vnode **vpp,
8628415Speter				   struct componentname *cnp);
8728415Speterstatic int	union_mkdir(struct vop_mkdir_args *ap);
8828415Speterstatic int	union_mknod(struct vop_mknod_args *ap);
8928415Speterstatic int	union_open(struct vop_open_args *ap);
9028415Speterstatic int	union_pathconf(struct vop_pathconf_args *ap);
9128415Speterstatic int	union_print(struct vop_print_args *ap);
9228415Speterstatic int	union_read(struct vop_read_args *ap);
9328415Speterstatic int	union_readdir(struct vop_readdir_args *ap);
9428415Speterstatic int	union_readlink(struct vop_readlink_args *ap);
9528415Speterstatic int	union_getwritemount(struct vop_getwritemount_args *ap);
9634768Speterstatic int	union_reclaim(struct vop_reclaim_args *ap);
9734768Speterstatic int	union_remove(struct vop_remove_args *ap);
9828415Speterstatic int	union_rename(struct vop_rename_args *ap);
9934768Speterstatic int	union_revoke(struct vop_revoke_args *ap);
10034768Speterstatic int	union_rmdir(struct vop_rmdir_args *ap);
10134768Speterstatic int	union_poll(struct vop_poll_args *ap);
10243305Sdillonstatic int	union_setattr(struct vop_setattr_args *ap);
10328415Speterstatic int	union_strategy(struct vop_strategy_args *ap);
10428415Speterstatic int	union_symlink(struct vop_symlink_args *ap);
10528415Speterstatic int	union_whiteout(struct vop_whiteout_args *ap);
10628415Speterstatic int	union_write(struct vop_read_args *ap);
10728415Speter
10828415Speterstatic __inline
10928415Speterstruct vnode *
11028415Speterunion_lock_upper(struct union_node *un, struct thread *td)
11128415Speter{
11228415Speter	struct vnode *uppervp;
11328415Speter
11428415Speter	if ((uppervp = un->un_uppervp) != NULL) {
11528415Speter		VREF(uppervp);
11628415Speter		vn_lock(uppervp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY, td);
11728415Speter	}
11828415Speter	KASSERT((uppervp == NULL || vrefcnt(uppervp) > 0), ("uppervp usecount is 0"));
11928415Speter	return(uppervp);
12028415Speter}
12128415Speter
12228415Speterstatic __inline
12328415Spetervoid
12428415Speterunion_unlock_upper(struct vnode *uppervp, struct thread *td)
12528415Speter{
12628415Speter	vput(uppervp);
12728415Speter}
12834768Speter
12934768Speterstatic __inline
13034768Speterstruct vnode *
13134768Speterunion_lock_other(struct union_node *un, struct thread *td)
13234768Speter{
13334768Speter	struct vnode *vp;
13434768Speter
13534768Speter	if (un->un_uppervp != NULL) {
13634768Speter		vp = union_lock_upper(un, td);
13734768Speter	} else if ((vp = un->un_lowervp) != NULL) {
13834768Speter		VREF(vp);
13934768Speter		vn_lock(vp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY, td);
14034768Speter	}
14134768Speter	return(vp);
14234768Speter}
14334768Speter
14434768Speterstatic __inline
14534768Spetervoid
14634768Speterunion_unlock_other(struct vnode *vp, struct thread *td)
14734768Speter{
14834768Speter	vput(vp);
14934768Speter}
15034768Speter
15134768Speter/*
15234768Speter *	union_lookup:
15334768Speter *
15434768Speter *	udvp	must be exclusively locked on call and will remain
15534768Speter *		exclusively locked on return.  This is the mount point
15634768Speter *		for our filesystem.
15734768Speter *
15834768Speter *	dvp	Our base directory, locked and referenced.
15934768Speter *		The passed dvp will be dereferenced and unlocked on return
16034768Speter *		and a new dvp will be returned which is locked and
16134768Speter *		referenced in the same variable.
16234768Speter *
16334768Speter *	vpp	is filled in with the result if no error occured,
16434768Speter *		locked and ref'd.
16534768Speter *
16634768Speter *		If an error is returned, *vpp is set to NULLVP.  If no
16734768Speter *		error occurs, *vpp is returned with a reference and an
16834768Speter *		exclusive lock.
16934768Speter */
17034768Speter
17134768Speterstatic int
17234768Speterunion_lookup1(udvp, pdvp, vpp, cnp)
17334768Speter	struct vnode *udvp;
17434768Speter	struct vnode **pdvp;
17534768Speter	struct vnode **vpp;
17634768Speter	struct componentname *cnp;
17734768Speter{
17834768Speter	int error;
17934768Speter	struct thread *td = cnp->cn_thread;
18034768Speter	struct vnode *dvp = *pdvp;
18134768Speter	struct vnode *tdvp;
18234768Speter	struct mount *mp;
18334768Speter
18434768Speter	/*
18534768Speter	 * If stepping up the directory tree, check for going
18634768Speter	 * back across the mount point, in which case do what
18734768Speter	 * lookup would do by stepping back down the mount
18834768Speter	 * hierarchy.
18928415Speter	 */
19028415Speter	if (cnp->cn_flags & ISDOTDOT) {
19134768Speter		while ((dvp != udvp) && (dvp->v_vflag & VV_ROOT)) {
19234768Speter			/*
19334768Speter			 * Don't do the NOCROSSMOUNT check
19428415Speter			 * at this level.  By definition,
19534768Speter			 * union fs deals with namespaces, not
19634768Speter			 * filesystems.
19728415Speter			 */
19834768Speter			tdvp = dvp;
19934768Speter			dvp = dvp->v_mount->mnt_vnodecovered;
20034768Speter			VREF(dvp);
20134768Speter			vput(tdvp);
20234768Speter			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
20334768Speter		}
20434768Speter	}
20534768Speter
20634768Speter	/*
20728415Speter	 * Set return dvp to be the upperdvp 'parent directory.
20828415Speter	 */
20928415Speter	*pdvp = dvp;
21028415Speter
21134768Speter	/*
21234768Speter	 * If the VOP_LOOKUP() call generates an error, tdvp is invalid and
21334768Speter	 * no changes will have been made to dvp, so we are set to return.
21434768Speter	 */
21534768Speter
21628415Speter        error = VOP_LOOKUP(dvp, &tdvp, cnp);
21734768Speter	if (error) {
21828415Speter		UDEBUG(("dvp %p error %d flags %lx\n", dvp, error, cnp->cn_flags));
21934768Speter		*vpp = NULL;
22028415Speter		return (error);
22128415Speter	}
22234768Speter
22328415Speter	/*
22428415Speter	 * The parent directory will have been unlocked, unless lookup
22528415Speter	 * found the last component or if dvp == tdvp (tdvp must be locked).
22628415Speter	 *
22728415Speter	 * We want our dvp to remain locked and ref'd.  We also want tdvp
22828415Speter	 * to remain locked and ref'd.
22928415Speter	 */
23028415Speter	UDEBUG(("parentdir %p result %p flag %lx\n", dvp, tdvp, cnp->cn_flags));
23128415Speter
23234768Speter	if (dvp != tdvp && (cnp->cn_flags & ISLASTCN) == 0)
23328415Speter		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
23428415Speter
23528415Speter	/*
23628415Speter	 * Lastly check if the current node is a mount point in
23728415Speter	 * which case walk up the mount hierarchy making sure not to
23828415Speter	 * bump into the root of the mount tree (ie. dvp != udvp).
23928415Speter	 *
24028415Speter	 * We use dvp as a temporary variable here, it is no longer related
24128415Speter	 * to the dvp above.  However, we have to ensure that both *pdvp and
24228415Speter	 * tdvp are locked on return.
24328415Speter	 */
24428415Speter
24528415Speter	dvp = tdvp;
24628415Speter	while (
24728415Speter	    dvp != udvp &&
24828415Speter	    (dvp->v_type == VDIR) &&
24934768Speter	    (mp = dvp->v_mountedhere)
25028415Speter	) {
25134768Speter		int relock_pdvp = 0;
25234768Speter
25328415Speter		if (vfs_busy(mp, 0, 0, td))
25428415Speter			continue;
25528415Speter
25634768Speter		if (dvp == *pdvp)
25734768Speter			relock_pdvp = 1;
25828415Speter		vput(dvp);
25934768Speter		dvp = NULL;
26034768Speter		error = VFS_ROOT(mp, &dvp);
26134768Speter
26234768Speter		vfs_unbusy(mp, td);
26328415Speter
26434768Speter		if (relock_pdvp)
26528415Speter			vn_lock(*pdvp, LK_EXCLUSIVE | LK_RETRY, td);
26628415Speter
26728415Speter		if (error) {
26828415Speter			*vpp = NULL;
26928415Speter			return (error);
27028415Speter		}
27128415Speter	}
27228415Speter	*vpp = dvp;
27334768Speter	return (0);
27428415Speter}
27534768Speter
27634768Speterstatic int
27728415Speterunion_lookup(ap)
27834768Speter	struct vop_lookup_args /* {
27934768Speter		struct vnodeop_desc *a_desc;
28028415Speter		struct vnode *a_dvp;
28128415Speter		struct vnode **a_vpp;
28228415Speter		struct componentname *a_cnp;
28328415Speter	} */ *ap;
28428415Speter{
28528415Speter	int error;
28628415Speter	int uerror, lerror;
28728415Speter	struct vnode *uppervp, *lowervp;
28828415Speter	struct vnode *upperdvp, *lowerdvp;
28928415Speter	struct vnode *dvp = ap->a_dvp;		/* starting dir */
29028415Speter	struct union_node *dun = VTOUNION(dvp);	/* associated union node */
29128415Speter	struct componentname *cnp = ap->a_cnp;
29228415Speter	struct thread *td = cnp->cn_thread;
29328415Speter	int lockparent = cnp->cn_flags & LOCKPARENT;
29428415Speter	struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
29528415Speter	struct ucred *saved_cred = NULL;
29628415Speter	int iswhiteout;
29728415Speter	struct vattr va;
29828415Speter
29928415Speter	*ap->a_vpp = NULLVP;
30028415Speter
30128415Speter	/*
30228415Speter	 * Disallow write attempts to the filesystem mounted read-only.
30328415Speter	 */
30428415Speter	if ((cnp->cn_flags & ISLASTCN) &&
30528415Speter	    (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
30628415Speter	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
30728415Speter		return (EROFS);
30828415Speter	}
30928415Speter
31028415Speter	/*
31128415Speter	 * For any lookups we do, always return with the parent locked.
31228415Speter	 */
31328415Speter	cnp->cn_flags |= LOCKPARENT;
31428415Speter
31528415Speter	lowerdvp = dun->un_lowervp;
31628415Speter	uppervp = NULLVP;
31728415Speter	lowervp = NULLVP;
31828415Speter	iswhiteout = 0;
31928415Speter
32028415Speter	uerror = ENOENT;
32128415Speter	lerror = ENOENT;
32228415Speter
32328415Speter	/*
32428415Speter	 * Get a private lock on uppervp and a reference, effectively
32528415Speter	 * taking it out of the union_node's control.
32628415Speter	 *
32728415Speter	 * We must lock upperdvp while holding our lock on dvp
32828415Speter	 * to avoid a deadlock.
32928415Speter	 */
33028415Speter	upperdvp = union_lock_upper(dun, td);
33128415Speter
33228415Speter	/*
33328415Speter	 * Do the lookup in the upper level.
33428415Speter	 * If that level consumes additional pathnames,
33528415Speter	 * then assume that something special is going
33628415Speter	 * on and just return that vnode.
33728415Speter	 */
33828415Speter	if (upperdvp != NULLVP) {
33928415Speter		/*
34028415Speter		 * We do not have to worry about the DOTDOT case, we've
34128415Speter		 * already unlocked dvp.
34228415Speter		 */
34328415Speter		UDEBUG(("A %p\n", upperdvp));
34428415Speter
34534768Speter		/*
34628415Speter		 * Do the lookup.   We must supply a locked and referenced
34728415Speter		 * upperdvp to the function and will get a new locked and
34834768Speter		 * referenced upperdvp back, with the old having been
34928415Speter		 * dereferenced.
35028415Speter		 *
35128415Speter		 * If an error is returned, uppervp will be NULLVP.  If no
35234768Speter		 * error occurs, uppervp will be the locked and referenced.
35328415Speter		 * Return vnode, or possibly NULL, depending on what is being
35434768Speter		 * requested.  It is possible that the returned uppervp
35528415Speter		 * will be the same as upperdvp.
35628415Speter		 */
35728415Speter		uerror = union_lookup1(um->um_uppervp, &upperdvp, &uppervp, cnp);
35828415Speter		UDEBUG((
35928415Speter		    "uerror %d upperdvp %p %d/%d, uppervp %p ref=%d/lck=%d\n",
36028415Speter		    uerror,
36128415Speter		    upperdvp,
36228415Speter		    vrefcnt(upperdvp),
36328415Speter		    VOP_ISLOCKED(upperdvp, NULL),
36428415Speter		    uppervp,
36528415Speter		    (uppervp ? vrefcnt(uppervp) : -99),
36628415Speter		    (uppervp ? VOP_ISLOCKED(uppervp, NULL) : -99)
36728415Speter		));
36828415Speter
36928415Speter		/*
37028415Speter		 * Disallow write attempts to the filesystem mounted read-only.
37128415Speter		 */
37228415Speter		if (uerror == EJUSTRETURN && (cnp->cn_flags & ISLASTCN) &&
37328415Speter		    (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
37428415Speter		    (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)) {
37528415Speter			error = EROFS;
37628415Speter			goto out;
37728415Speter		}
37828415Speter
37928415Speter		/*
38028415Speter		 * Special case: If cn_consume != 0 then skip out.  The result
38128415Speter		 * of the lookup is transfered to our return variable.  If
38228415Speter		 * an error occured we have to throw away the results.
38328415Speter		 */
38428415Speter
38528415Speter		if (cnp->cn_consume != 0) {
38628415Speter			if ((error = uerror) == 0) {
38728415Speter				*ap->a_vpp = uppervp;
38828415Speter				uppervp = NULL;
38928415Speter			}
39028415Speter			goto out;
39128415Speter		}
39228415Speter
39328415Speter		/*
39428415Speter		 * Calculate whiteout, fall through.
39528415Speter		 */
39628415Speter
39728415Speter		if (uerror == ENOENT || uerror == EJUSTRETURN) {
39828415Speter			if (cnp->cn_flags & ISWHITEOUT) {
39928415Speter				iswhiteout = 1;
40028415Speter			} else if (lowerdvp != NULLVP) {
40128415Speter				int terror;
40228415Speter
40328415Speter				terror = VOP_GETATTR(upperdvp, &va,
40428415Speter					cnp->cn_cred, cnp->cn_thread);
40528415Speter				if (terror == 0 && (va.va_flags & OPAQUE))
40628415Speter					iswhiteout = 1;
40728415Speter			}
40828415Speter		}
40928415Speter	}
41028415Speter
41128415Speter	/*
41228415Speter	 * In a similar way to the upper layer, do the lookup
41328415Speter	 * in the lower layer.   This time, if there is some
41428415Speter	 * component magic going on, then vput whatever we got
41528415Speter	 * back from the upper layer and return the lower vnode
41628415Speter	 * instead.
41728415Speter	 */
41828415Speter
41928415Speter	if (lowerdvp != NULLVP && !iswhiteout) {
42028415Speter		int nameiop;
42128415Speter
42228415Speter		UDEBUG(("B %p\n", lowerdvp));
42328415Speter
42428415Speter		/*
42528415Speter		 * Force only LOOKUPs on the lower node, since
42628415Speter		 * we won't be making changes to it anyway.
42728415Speter		 */
42828415Speter		nameiop = cnp->cn_nameiop;
42928415Speter		cnp->cn_nameiop = LOOKUP;
43028415Speter		if (um->um_op == UNMNT_BELOW) {
43128415Speter			saved_cred = cnp->cn_cred;
43228415Speter			cnp->cn_cred = um->um_cred;
43328415Speter		}
43428415Speter
43528415Speter		/*
43628415Speter		 * We shouldn't have to worry about locking interactions
43734768Speter		 * between the lower layer and our union layer (w.r.t.
43828415Speter		 * `..' processing) because we don't futz with lowervp
43928415Speter		 * locks in the union-node instantiation code path.
44028415Speter		 *
44128415Speter		 * union_lookup1() requires lowervp to be locked on entry,
44228415Speter		 * and it will be unlocked on return.  The ref count will
44328415Speter		 * not change.  On return lowervp doesn't represent anything
44428415Speter		 * to us so we NULL it out.
44528415Speter		 */
44628415Speter		VREF(lowerdvp);
44728415Speter		vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, td);
44828415Speter		lerror = union_lookup1(um->um_lowervp, &lowerdvp, &lowervp, cnp);
44928415Speter		if (lowerdvp == lowervp)
45028415Speter			vrele(lowerdvp);
45128415Speter		else
45228415Speter			vput(lowerdvp);
45328415Speter		lowerdvp = NULL;	/* lowerdvp invalid after vput */
45428415Speter
45528415Speter		if (um->um_op == UNMNT_BELOW)
45628415Speter			cnp->cn_cred = saved_cred;
45728415Speter		cnp->cn_nameiop = nameiop;
45828415Speter
45928415Speter		if (cnp->cn_consume != 0 || lerror == EACCES) {
46028415Speter			if ((error = lerror) == 0) {
46128415Speter				*ap->a_vpp = lowervp;
46228415Speter				lowervp = NULL;
46328415Speter			}
46428415Speter			goto out;
46528415Speter		}
46628415Speter	} else {
46728415Speter		UDEBUG(("C %p\n", lowerdvp));
46828415Speter		if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
46928415Speter			if ((lowervp = LOWERVP(dun->un_pvp)) != NULL) {
47028415Speter				VREF(lowervp);
47128415Speter				vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, td);
47228415Speter				lerror = 0;
47328415Speter			}
47428415Speter		}
47528415Speter	}
47628415Speter
47728415Speter	/*
47828415Speter	 * Ok.  Now we have uerror, uppervp, upperdvp, lerror, and lowervp.
47928415Speter	 *
48028415Speter	 * 1. If both layers returned an error, select the upper layer.
48128415Speter	 *
48228415Speter	 * 2. If the upper layer failed and the bottom layer succeeded,
48328415Speter	 *    two subcases occur:
48428415Speter	 *
48528415Speter	 *	a.  The bottom vnode is not a directory, in which case
48628415Speter	 *	    just return a new union vnode referencing an
48728415Speter	 *	    empty top layer and the existing bottom layer.
48828415Speter	 *
48928415Speter	 *	b.  The bottom vnode is a directory, in which case
49028415Speter	 *	    create a new directory in the top layer and
49128415Speter	 *	    and fall through to case 3.
49228415Speter	 *
49328415Speter	 * 3. If the top layer succeeded, then return a new union
49428415Speter	 *    vnode referencing whatever the new top layer and
49528415Speter	 *    whatever the bottom layer returned.
49628415Speter	 */
49728415Speter
49828415Speter	/* case 1. */
49928415Speter	if ((uerror != 0) && (lerror != 0)) {
50028415Speter		error = uerror;
50128415Speter		goto out;
50228415Speter	}
50328415Speter
50428415Speter	/* case 2. */
50528415Speter	if (uerror != 0 /* && (lerror == 0) */ ) {
50628415Speter		if (lowervp->v_type == VDIR) { /* case 2b. */
50728415Speter			KASSERT(uppervp == NULL, ("uppervp unexpectedly non-NULL"));
50828415Speter			/*
50928415Speter			 * Oops, uppervp has a problem, we may have to shadow.
51028415Speter			 */
51128415Speter			uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
51228415Speter			if (uerror) {
51328415Speter				error = uerror;
51428415Speter				goto out;
51528415Speter			}
51628415Speter		}
51728415Speter	}
51828415Speter
51928415Speter	/*
52028415Speter	 * Must call union_allocvp() with both the upper and lower vnodes
52128415Speter	 * referenced and the upper vnode locked.   ap->a_vpp is returned
52228415Speter	 * referenced and locked.  lowervp, uppervp, and upperdvp are
52328415Speter	 * absorbed by union_allocvp() whether it succeeds or fails.
52428415Speter	 *
52528415Speter	 * upperdvp is the parent directory of uppervp which may be
52628415Speter	 * different, depending on the path, from dvp->un_uppervp.  That's
52728415Speter	 * why it is a separate argument.  Note that it must be unlocked.
52828415Speter	 *
52928415Speter	 * dvp must be locked on entry to the call and will be locked on
53028415Speter	 * return.
53134768Speter	 */
53234768Speter
53334768Speter	if (uppervp && uppervp != upperdvp)
53434768Speter		VOP_UNLOCK(uppervp, 0, td);
53534768Speter	if (lowervp)
53634768Speter		VOP_UNLOCK(lowervp, 0, td);
53728415Speter	if (upperdvp)
53834768Speter		VOP_UNLOCK(upperdvp, 0, td);
53928415Speter
54034768Speter	error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
54134768Speter			      uppervp, lowervp, 1);
54228415Speter
54334768Speter	UDEBUG(("Create %p = %p %p refs=%d\n", *ap->a_vpp, uppervp, lowervp, (*ap->a_vpp) ? vrefcnt(*ap->a_vpp) : -99));
54428415Speter
54534768Speter	uppervp = NULL;
54628415Speter	upperdvp = NULL;
54728415Speter	lowervp = NULL;
54828415Speter
54928415Speter	/*
55028415Speter	 *	Termination Code
55128415Speter	 *
55228415Speter	 *	- put away any extra junk laying around.  Note that lowervp
55328415Speter	 *	  (if not NULL) will never be the same as *ap->a_vp and
55428415Speter	 *	  neither will uppervp, because when we set that state we
55528415Speter	 *	  NULL-out lowervp or uppervp.  On the otherhand, upperdvp
55628415Speter	 *	  may match uppervp or *ap->a_vpp.
55728415Speter	 *
55828415Speter	 *	- relock/unlock dvp if appropriate.
55928415Speter	 */
56028415Speter
56128415Speterout:
56228415Speter	if (upperdvp) {
56328415Speter		if (upperdvp == uppervp || upperdvp == *ap->a_vpp)
56428415Speter			vrele(upperdvp);
56528415Speter		else
56628415Speter			vput(upperdvp);
56728415Speter	}
56828415Speter
56928415Speter	if (uppervp)
57028415Speter		vput(uppervp);
57128415Speter
57228415Speter	if (lowervp)
57328415Speter		vput(lowervp);
57428415Speter
57528415Speter	/*
57628415Speter	 * Restore LOCKPARENT state
57728415Speter	 */
57828415Speter
57928415Speter	if (!lockparent)
58028415Speter		cnp->cn_flags &= ~LOCKPARENT;
58128415Speter
58234768Speter	UDEBUG(("Out %d vpp %p/%d lower %p upper %p\n", error, *ap->a_vpp,
58334768Speter		((*ap->a_vpp) ? vrefcnt(*ap->a_vpp) : -99),
58428415Speter		lowervp, uppervp));
58528415Speter
58628415Speter	/*
58728415Speter	 * dvp lock state, determine whether to relock dvp.  dvp is expected
58828415Speter	 * to be locked on return if:
58928415Speter	 *
59028415Speter	 *	- there was an error (except not EJUSTRETURN), or
59128415Speter	 *	- we hit the last component and lockparent is true
59228415Speter	 *
59334768Speter	 * dvp_is_locked is the current state of the dvp lock, not counting
59428415Speter	 * the possibility that *ap->a_vpp == dvp (in which case it is locked
59534768Speter	 * anyway).  Note that *ap->a_vpp == dvp only if no error occured.
59634768Speter	 */
59734768Speter
59828415Speter	if (*ap->a_vpp != dvp) {
59928415Speter		if ((error == 0 || error == EJUSTRETURN) &&
60028415Speter		    (!lockparent || (cnp->cn_flags & ISLASTCN) == 0)) {
60128415Speter			VOP_UNLOCK(dvp, 0, td);
60228415Speter		}
60328415Speter	}
60428415Speter
60534768Speter	/*
60634768Speter	 * Diagnostics
60734768Speter	 */
60834768Speter
60934768Speter#ifdef DIAGNOSTIC
61034768Speter	if (cnp->cn_namelen == 1 &&
61134768Speter	    cnp->cn_nameptr[0] == '.' &&
61234768Speter	    *ap->a_vpp != dvp) {
61334768Speter		panic("union_lookup returning . (%p) not same as startdir (%p)", ap->a_vpp, dvp);
61434768Speter	}
61534768Speter#endif
61634768Speter
61734768Speter	return (error);
61834768Speter}
61934768Speter
62034768Speter/*
62134768Speter * 	union_create:
62234768Speter *
62334768Speter * a_dvp is locked on entry and remains locked on return.  a_vpp is returned
62434768Speter * locked if no error occurs, otherwise it is garbage.
62534768Speter */
62634768Speter
62734768Speterstatic int
62834768Speterunion_create(ap)
62934768Speter	struct vop_create_args /* {
63034768Speter		struct vnode *a_dvp;
63134768Speter		struct vnode **a_vpp;
63234768Speter		struct componentname *a_cnp;
63334768Speter		struct vattr *a_vap;
63434768Speter	} */ *ap;
63534768Speter{
63634768Speter	struct union_node *dun = VTOUNION(ap->a_dvp);
63734768Speter	struct componentname *cnp = ap->a_cnp;
63834768Speter	struct thread *td = cnp->cn_thread;
63934768Speter	struct vnode *dvp;
64034768Speter	int error = EROFS;
64134768Speter
64228415Speter	if ((dvp = union_lock_upper(dun, td)) != NULL) {
64328415Speter		struct vnode *vp;
64428415Speter		struct mount *mp;
64528415Speter
64628415Speter		error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap);
64728415Speter		if (error == 0) {
64828415Speter			mp = ap->a_dvp->v_mount;
64928415Speter			VOP_UNLOCK(vp, 0, td);
65028415Speter			UDEBUG(("ALLOCVP-1 FROM %p REFS %d\n", vp, vrefcnt(vp)));
65128415Speter			error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
65228415Speter				cnp, vp, NULLVP, 1);
65328415Speter			UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", *ap->a_vpp, vrefcnt(vp)));
65428415Speter		}
65528415Speter		union_unlock_upper(dvp, td);
65628415Speter	}
65728415Speter	return (error);
65828415Speter}
65928415Speter
66028415Speterstatic int
66128415Speterunion_whiteout(ap)
66228415Speter	struct vop_whiteout_args /* {
66328415Speter		struct vnode *a_dvp;
66428415Speter		struct componentname *a_cnp;
66534768Speter		int a_flags;
66628415Speter	} */ *ap;
66728415Speter{
66828415Speter	struct union_node *un = VTOUNION(ap->a_dvp);
66928415Speter	struct componentname *cnp = ap->a_cnp;
67034768Speter	struct vnode *uppervp;
67134768Speter	int error = EOPNOTSUPP;
67234768Speter
67334768Speter	if ((uppervp = union_lock_upper(un, cnp->cn_thread)) != NULLVP) {
67428415Speter		error = VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags);
67534768Speter		union_unlock_upper(uppervp, cnp->cn_thread);
67634768Speter	}
67734768Speter	return(error);
67834768Speter}
67934768Speter
68034768Speter/*
68128415Speter * 	union_mknod:
68228415Speter *
68328415Speter *	a_dvp is locked on entry and should remain locked on return.
68428415Speter *	a_vpp is garbagre whether an error occurs or not.
68528415Speter */
68628415Speter
68728415Speterstatic int
68828415Speterunion_mknod(ap)
68928415Speter	struct vop_mknod_args /* {
69034768Speter		struct vnode *a_dvp;
69134768Speter		struct vnode **a_vpp;
69228415Speter		struct componentname *a_cnp;
69328415Speter		struct vattr *a_vap;
69428415Speter	} */ *ap;
69528415Speter{
69628415Speter	struct union_node *dun = VTOUNION(ap->a_dvp);
69728415Speter	struct componentname *cnp = ap->a_cnp;
69828415Speter	struct vnode *dvp;
69928415Speter	int error = EROFS;
70028415Speter
70128415Speter	if ((dvp = union_lock_upper(dun, cnp->cn_thread)) != NULL) {
70228415Speter		error = VOP_MKNOD(dvp, ap->a_vpp, cnp, ap->a_vap);
70328415Speter		union_unlock_upper(dvp, cnp->cn_thread);
70428415Speter	}
70528415Speter	return (error);
70628415Speter}
70728415Speter
70828415Speter/*
70928415Speter *	union_open:
71028415Speter *
71128415Speter *	run open VOP.  When opening the underlying vnode we have to mimic
71228415Speter *	vn_open().  What we *really* need to do to avoid screwups if the
71328415Speter *	open semantics change is to call vn_open().  For example, ufs blows
71434768Speter *	up if you open a file but do not vmio it prior to writing.
71528415Speter */
71628415Speter
71728415Speterstatic int
71828415Speterunion_open(ap)
71928415Speter	struct vop_open_args /* {
72028415Speter		struct vnodeop_desc *a_desc;
72128415Speter		struct vnode *a_vp;
72228415Speter		int a_mode;
72328415Speter		struct ucred *a_cred;
72428415Speter		struct thread *a_td;
72534768Speter	} */ *ap;
72634768Speter{
72728415Speter	struct union_node *un = VTOUNION(ap->a_vp);
72834768Speter	struct vnode *tvp;
72934768Speter	int mode = ap->a_mode;
73028415Speter	struct ucred *cred = ap->a_cred;
73134768Speter	struct thread *td = ap->a_td;
73234768Speter	int error = 0;
73328415Speter	int tvpisupper = 1;
73428415Speter
73528415Speter	/*
73628415Speter	 * If there is an existing upper vp then simply open that.
73734768Speter	 * The upper vp takes precedence over the lower vp.  When opening
73834768Speter	 * a lower vp for writing copy it to the uppervp and then open the
73934768Speter	 * uppervp.
74028415Speter	 *
74128415Speter	 * At the end of this section tvp will be left locked.
74228415Speter	 */
74328415Speter	if ((tvp = union_lock_upper(un, td)) == NULLVP) {
74428415Speter		/*
74534768Speter		 * If the lower vnode is being opened for writing, then
74634768Speter		 * copy the file contents to the upper vnode and open that,
74728415Speter		 * otherwise can simply open the lower vnode.
74828415Speter		 */
74928415Speter		tvp = un->un_lowervp;
75034768Speter		if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
75128415Speter			int docopy = !(mode & O_TRUNC);
75234768Speter			error = union_copyup(un, docopy, cred, td);
75334768Speter			tvp = union_lock_upper(un, td);
75434768Speter		} else {
75534768Speter			un->un_openl++;
75634768Speter			VREF(tvp);
75734768Speter			vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, td);
75834768Speter			tvpisupper = 0;
75934768Speter		}
76034768Speter	}
76128415Speter
76228415Speter	/*
76328415Speter	 * We are holding the correct vnode, open it.
76434768Speter	 */
76534768Speter
76634768Speter	if (error == 0)
76734768Speter		error = VOP_OPEN(tvp, mode, cred, td);
76834768Speter
76934768Speter	/*
77034768Speter	 * This is absolutely necessary or UFS will blow up.
77128415Speter	 */
77228415Speter        if (error == 0 && vn_canvmio(tvp) == TRUE) {
77328415Speter                error = vfs_object_create(tvp, td, cred);
77428415Speter        }
77528415Speter
77628415Speter	/*
77728415Speter	 * Release any locks held.
77834768Speter	 */
77993013Sjedgar	if (tvpisupper) {
78034768Speter		if (tvp)
78128415Speter			union_unlock_upper(tvp, td);
78228415Speter	} else {
78334768Speter		vput(tvp);
78428415Speter	}
78528415Speter	return (error);
78628415Speter}
78728415Speter
78828415Speter/*
78928415Speter *	union_close:
79028415Speter *
79128415Speter *	It is unclear whether a_vp is passed locked or unlocked.  Whatever
79228415Speter *	the case we do not change it.
79328415Speter */
79428415Speter
79528415Speterstatic int
79628415Speterunion_close(ap)
79728415Speter	struct vop_close_args /* {
79834768Speter		struct vnode *a_vp;
79934768Speter		int  a_fflag;
80034768Speter		struct ucred *a_cred;
80128415Speter		struct thread *a_td;
80228415Speter	} */ *ap;
80328415Speter{
80434768Speter	struct union_node *un = VTOUNION(ap->a_vp);
80534768Speter	struct vnode *vp;
80634768Speter
80728415Speter	if ((vp = un->un_uppervp) == NULLVP) {
80828415Speter#ifdef UNION_DIAGNOSTIC
80928415Speter		if (un->un_openl <= 0)
81043305Sdillon			panic("union: un_openl cnt");
81128415Speter#endif
81228415Speter		--un->un_openl;
81328415Speter		vp = un->un_lowervp;
81434768Speter	}
81534768Speter	ap->a_vp = vp;
81628415Speter	return (VCALL(vp, VOFFSET(vop_close), ap));
81728415Speter}
81828415Speter
81928415Speter/*
82028415Speter * Check access permission on the union vnode.
82128415Speter * The access check being enforced is to check
82228415Speter * against both the underlying vnode, and any
82328415Speter * copied vnode.  This ensures that no additional
82428415Speter * file permissions are given away simply because
82534768Speter * the user caused an implicit file copy.
82634768Speter */
82734768Speterstatic int
82834768Speterunion_access(ap)
82934768Speter	struct vop_access_args /* {
83034768Speter		struct vnodeop_desc *a_desc;
83134768Speter		struct vnode *a_vp;
83234768Speter		int a_mode;
83334768Speter		struct ucred *a_cred;
83434768Speter		struct thread *a_td;
83534768Speter	} */ *ap;
83634768Speter{
83734768Speter	struct union_node *un = VTOUNION(ap->a_vp);
83834768Speter	struct thread *td = ap->a_td;
83934768Speter	int error = EACCES;
84034768Speter	struct vnode *vp;
84134768Speter
84234768Speter	/*
84334768Speter	 * Disallow write attempts on filesystems mounted read-only.
84434768Speter	 */
84534768Speter	if ((ap->a_mode & VWRITE) &&
84634768Speter	    (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
84734768Speter		switch (ap->a_vp->v_type) {
84834768Speter		case VREG:
84934768Speter		case VDIR:
85034768Speter		case VLNK:
85134768Speter			return (EROFS);
85234768Speter		default:
85334768Speter			break;
85434768Speter		}
85534768Speter	}
85634768Speter
85734768Speter	if ((vp = union_lock_upper(un, td)) != NULLVP) {
85834768Speter		ap->a_vp = vp;
85934768Speter		error = VCALL(vp, VOFFSET(vop_access), ap);
86034768Speter		union_unlock_upper(vp, td);
86134768Speter		return(error);
86234768Speter	}
86334768Speter
86434768Speter	if ((vp = un->un_lowervp) != NULLVP) {
86534768Speter		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
86634768Speter		ap->a_vp = vp;
86734768Speter
86828415Speter		/*
86934768Speter		 * Remove VWRITE from a_mode if our mount point is RW, because
87028415Speter		 * we want to allow writes and lowervp may be read-only.
87128415Speter		 */
87228415Speter		if ((un->un_vnode->v_mount->mnt_flag & MNT_RDONLY) == 0)
87328415Speter			ap->a_mode &= ~VWRITE;
87434768Speter
87528415Speter		error = VCALL(vp, VOFFSET(vop_access), ap);
87628415Speter		if (error == 0) {
87728415Speter			struct union_mount *um;
87828415Speter
87928415Speter			um = MOUNTTOUNIONMOUNT(un->un_vnode->v_mount);
88028415Speter
88128415Speter			if (um->um_op == UNMNT_BELOW) {
88228415Speter				ap->a_cred = um->um_cred;
88328415Speter				error = VCALL(vp, VOFFSET(vop_access), ap);
88428415Speter			}
88528415Speter		}
88628415Speter		VOP_UNLOCK(vp, 0, td);
88728415Speter	}
88834768Speter	return(error);
88934768Speter}
89028415Speter
89134768Speter/*
89228415Speter * We handle getattr only to change the fsid and
89328415Speter * track object sizes
89428415Speter *
89528415Speter * It's not clear whether VOP_GETATTR is to be
89628415Speter * called with the vnode locked or not.  stat() calls
89734768Speter * it with (vp) locked, and fstat() calls it with
89834768Speter * (vp) unlocked.
89934768Speter *
90034768Speter * Because of this we cannot use our normal locking functions
90134768Speter * if we do not intend to lock the main a_vp node.  At the moment
90234768Speter * we are running without any specific locking at all, but beware
90334768Speter * to any programmer that care must be taken if locking is added
90434768Speter * to this function.
90534768Speter */
90634768Speter
90734768Speterstatic int
90834768Speterunion_getattr(ap)
90934768Speter	struct vop_getattr_args /* {
91034768Speter		struct vnode *a_vp;
91134768Speter		struct vattr *a_vap;
91234768Speter		struct ucred *a_cred;
91334768Speter		struct thread *a_td;
91434768Speter	} */ *ap;
91534768Speter{
91634768Speter	int error;
91734768Speter	struct union_node *un = VTOUNION(ap->a_vp);
91834768Speter	struct vnode *vp;
91934768Speter	struct vattr *vap;
92034768Speter	struct vattr va;
92134768Speter
92234768Speter	/*
92334768Speter	 * Some programs walk the filesystem hierarchy by counting
92434768Speter	 * links to directories to avoid stat'ing all the time.
92534768Speter	 * This means the link count on directories needs to be "correct".
92634768Speter	 * The only way to do that is to call getattr on both layers
92734768Speter	 * and fix up the link count.  The link count will not necessarily
92834768Speter	 * be accurate but will be large enough to defeat the tree walkers.
92934768Speter	 */
93034768Speter
93134768Speter	vap = ap->a_vap;
93234768Speter
93328415Speter	if ((vp = un->un_uppervp) != NULLVP) {
93428415Speter		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td);
93528415Speter		if (error)
93628415Speter			return (error);
93728415Speter		/* XXX isn't this dangerous without a lock? */
93828415Speter		union_newsize(ap->a_vp, vap->va_size, VNOVAL);
93928415Speter	}
94028415Speter
94128415Speter	if (vp == NULLVP) {
94228415Speter		vp = un->un_lowervp;
94328415Speter	} else if (vp->v_type == VDIR && un->un_lowervp != NULLVP) {
94428415Speter		vp = un->un_lowervp;
94528415Speter		vap = &va;
94628415Speter	} else {
94734768Speter		vp = NULLVP;
94834768Speter	}
94934768Speter
95034768Speter	if (vp != NULLVP) {
95128415Speter		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td);
95228415Speter		if (error)
95334768Speter			return (error);
95428415Speter		/* XXX isn't this dangerous without a lock? */
95534768Speter		union_newsize(ap->a_vp, VNOVAL, vap->va_size);
95634768Speter	}
95728415Speter
95828415Speter	if ((vap != ap->a_vap) && (vap->va_type == VDIR))
95928415Speter		ap->a_vap->va_nlink += vap->va_nlink;
96028415Speter	return (0);
96134768Speter}
96234768Speter
96328415Speterstatic int
96428415Speterunion_setattr(ap)
96534768Speter	struct vop_setattr_args /* {
96628415Speter		struct vnode *a_vp;
96734768Speter		struct vattr *a_vap;
96834768Speter		struct ucred *a_cred;
96934768Speter		struct thread *a_td;
97034768Speter	} */ *ap;
97128415Speter{
97228415Speter	struct union_node *un = VTOUNION(ap->a_vp);
97328415Speter	struct thread *td = ap->a_td;
97428415Speter	struct vattr *vap = ap->a_vap;
97528415Speter	struct vnode *uppervp;
97634768Speter	int error;
97728415Speter
97828415Speter	/*
97934768Speter	 * Disallow write attempts on filesystems mounted read-only.
98034768Speter	 */
98128415Speter	if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
98234768Speter	    (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
98334768Speter	     vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
98434768Speter	     vap->va_mtime.tv_sec != VNOVAL ||
98534768Speter	     vap->va_mode != (mode_t)VNOVAL)) {
98634768Speter		return (EROFS);
98734768Speter	}
98834768Speter
98934768Speter	/*
99028415Speter	 * Handle case of truncating lower object to zero size
99128415Speter	 * by creating a zero length upper object.  This is to
99228415Speter	 * handle the case of open with O_TRUNC and O_CREAT.
99328415Speter	 */
99434768Speter	if (un->un_uppervp == NULLVP && (un->un_lowervp->v_type == VREG)) {
99534768Speter		error = union_copyup(un, (ap->a_vap->va_size != 0),
99634768Speter			    ap->a_cred, ap->a_td);
99728415Speter		if (error)
99828415Speter			return (error);
99934768Speter	}
100028415Speter
100134768Speter	/*
100234768Speter	 * Try to set attributes in upper layer,
100328415Speter	 * otherwise return read-only filesystem error.
100428415Speter	 */
100528415Speter	error = EROFS;
100634768Speter	if ((uppervp = union_lock_upper(un, td)) != NULLVP) {
100728415Speter		error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
100828415Speter					ap->a_cred, ap->a_td);
100934768Speter		if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
101034768Speter			union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
101134768Speter		union_unlock_upper(uppervp, td);
101234768Speter	}
101334768Speter	return (error);
101434768Speter}
101534768Speter
101634768Speterstatic int
101734768Speterunion_read(ap)
101828415Speter	struct vop_read_args /* {
101928415Speter		struct vnode *a_vp;
102028415Speter		struct uio *a_uio;
102134768Speter		int  a_ioflag;
102228415Speter		struct ucred *a_cred;
102334768Speter	} */ *ap;
102434768Speter{
102534768Speter	struct union_node *un = VTOUNION(ap->a_vp);
102634768Speter	struct thread *td = ap->a_uio->uio_td;
102734768Speter	struct vnode *uvp;
102834768Speter	int error;
102934768Speter
103034768Speter	uvp = union_lock_other(un, td);
103134768Speter	KASSERT(uvp != NULL, ("union_read: backing vnode missing!"));
103234768Speter
103328415Speter	error = VOP_READ(uvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
103434768Speter	union_unlock_other(uvp, td);
103534768Speter
103634768Speter	/*
103728415Speter	 * XXX
103834768Speter	 * Perhaps the size of the underlying object has changed under
103934768Speter	 * our feet.  Take advantage of the offset information present
104034768Speter	 * in the uio structure.
104128415Speter	 */
104228415Speter	if (error == 0) {
104328415Speter		struct union_node *un = VTOUNION(ap->a_vp);
104434768Speter		off_t cur = ap->a_uio->uio_offset;
104528415Speter
104628415Speter		if (uvp == un->un_uppervp) {
104728415Speter			if (cur > un->un_uppersz)
104828415Speter				union_newsize(ap->a_vp, cur, VNOVAL);
104928415Speter		} else {
105034768Speter			if (cur > un->un_lowersz)
105134768Speter				union_newsize(ap->a_vp, VNOVAL, cur);
105234768Speter		}
105328415Speter	}
105434768Speter	return (error);
105534768Speter}
105634768Speter
105734768Speterstatic int
105828415Speterunion_write(ap)
105934768Speter	struct vop_read_args /* {
106034768Speter		struct vnode *a_vp;
106134768Speter		struct uio *a_uio;
106234768Speter		int  a_ioflag;
106328415Speter		struct ucred *a_cred;
106434768Speter	} */ *ap;
106534768Speter{
106634768Speter	struct union_node *un = VTOUNION(ap->a_vp);
106734768Speter	struct thread *td = ap->a_uio->uio_td;
106834768Speter	struct vnode *uppervp;
106934768Speter	int error;
107028415Speter
107134768Speter	if ((uppervp = union_lock_upper(un, td)) == NULLVP)
107234768Speter		panic("union: missing upper layer in write");
107334768Speter
107434768Speter	error = VOP_WRITE(uppervp, ap->a_uio, ap->a_ioflag, ap->a_cred);
107534768Speter
107634768Speter	/*
107734768Speter	 * The size of the underlying object may be changed by the
107834768Speter	 * write.
107934768Speter	 */
108034768Speter	if (error == 0) {
108134768Speter		off_t cur = ap->a_uio->uio_offset;
108234768Speter
108334768Speter		if (cur > un->un_uppersz)
108434768Speter			union_newsize(ap->a_vp, cur, VNOVAL);
108534768Speter	}
108634768Speter	union_unlock_upper(uppervp, td);
108734768Speter	return (error);
108834768Speter}
108934768Speter
109034768Speterstatic int
109134768Speterunion_lease(ap)
109228415Speter	struct vop_lease_args /* {
109334768Speter		struct vnode *a_vp;
109428415Speter		struct thread *a_td;
109528415Speter		struct ucred *a_cred;
109628415Speter		int a_flag;
109728415Speter	} */ *ap;
109834768Speter{
109928415Speter	struct vnode *ovp = OTHERVP(ap->a_vp);
110028415Speter
110134768Speter	ap->a_vp = ovp;
110234768Speter	return (VCALL(ovp, VOFFSET(vop_lease), ap));
110328415Speter}
110428415Speter
110528415Speterstatic int
110628415Speterunion_ioctl(ap)
110734768Speter	struct vop_ioctl_args /* {
110834768Speter		struct vnode *a_vp;
110928415Speter		int  a_command;
111028415Speter		caddr_t  a_data;
111128415Speter		int  a_fflag;
111228415Speter		struct ucred *a_cred;
111334768Speter		struct thread *a_td;
111428415Speter	} */ *ap;
111534768Speter{
111634768Speter	struct vnode *ovp = OTHERVP(ap->a_vp);
111728415Speter
111834768Speter	ap->a_vp = ovp;
111934768Speter	return (VCALL(ovp, VOFFSET(vop_ioctl), ap));
112028415Speter}
112134768Speter
112234768Speterstatic int
112334768Speterunion_poll(ap)
112434768Speter	struct vop_poll_args /* {
112534768Speter		struct vnode *a_vp;
112628415Speter		int  a_events;
112734768Speter		struct ucred *a_cred;
112834768Speter		struct thread *a_td;
112934768Speter	} */ *ap;
113034768Speter{
113134768Speter	struct vnode *ovp = OTHERVP(ap->a_vp);
113234768Speter
113334768Speter	ap->a_vp = ovp;
113428415Speter	return (VCALL(ovp, VOFFSET(vop_poll), ap));
113528415Speter}
113634768Speter
113734768Speterstatic int
113834768Speterunion_revoke(ap)
113934768Speter	struct vop_revoke_args /* {
114034768Speter		struct vnode *a_vp;
114134768Speter		int a_flags;
114234768Speter		struct thread *a_td;
114334768Speter	} */ *ap;
114434768Speter{
114534768Speter	struct vnode *vp = ap->a_vp;
114634768Speter
114734768Speter	if (UPPERVP(vp))
114834768Speter		VOP_REVOKE(UPPERVP(vp), ap->a_flags);
114934768Speter	if (LOWERVP(vp))
115034768Speter		VOP_REVOKE(LOWERVP(vp), ap->a_flags);
115134768Speter	vgone(vp);
115234768Speter	return (0);
115334768Speter}
115437065Speter
115534768Speterstatic int
115634768Speterunion_fsync(ap)
115734768Speter	struct vop_fsync_args /* {
115834768Speter		struct vnode *a_vp;
115937065Speter		struct ucred *a_cred;
116034768Speter		int  a_waitfor;
116134768Speter		struct thread *a_td;
116234768Speter	} */ *ap;
116334768Speter{
116434768Speter	int error = 0;
116534768Speter	struct thread *td = ap->a_td;
116634768Speter	struct vnode *targetvp;
116734768Speter	struct union_node *un = VTOUNION(ap->a_vp);
116834768Speter
116934768Speter	if ((targetvp = union_lock_other(un, td)) != NULLVP) {
117034768Speter		error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, td);
117134768Speter		union_unlock_other(targetvp, td);
117234768Speter	}
117334768Speter
117434768Speter	return (error);
117534768Speter}
117634768Speter
117734768Speter/*
117834768Speter *	union_remove:
117934768Speter *
118034768Speter *	Remove the specified cnp.  The dvp and vp are passed to us locked
118134768Speter *	and must remain locked on return.
118234768Speter */
118334768Speter
118434768Speterstatic int
118534768Speterunion_remove(ap)
118634768Speter	struct vop_remove_args /* {
118728415Speter		struct vnode *a_dvp;
118828415Speter		struct vnode *a_vp;
118928415Speter		struct componentname *a_cnp;
119028415Speter	} */ *ap;
119134768Speter{
119234768Speter	struct union_node *dun = VTOUNION(ap->a_dvp);
119334768Speter	struct union_node *un = VTOUNION(ap->a_vp);
119434768Speter	struct componentname *cnp = ap->a_cnp;
119534768Speter	struct thread *td = cnp->cn_thread;
119634768Speter	struct vnode *uppervp;
119734768Speter	struct vnode *upperdvp;
119834768Speter	int error;
119934768Speter
120034768Speter	if ((upperdvp = union_lock_upper(dun, td)) == NULLVP)
120134768Speter		panic("union remove: null upper vnode");
120234768Speter
120328415Speter	if ((uppervp = union_lock_upper(un, td)) != NULLVP) {
120434768Speter		if (union_dowhiteout(un, cnp->cn_cred, td))
120534768Speter			cnp->cn_flags |= DOWHITEOUT;
120634768Speter		error = VOP_REMOVE(upperdvp, uppervp, cnp);
120734768Speter#if 0
120828415Speter		/* XXX */
120928415Speter		if (!error)
121034768Speter			union_removed_upper(un);
121128415Speter#endif
121228415Speter		union_unlock_upper(uppervp, td);
121328415Speter	} else {
121428415Speter		error = union_mkwhiteout(
121528415Speter			    MOUNTTOUNIONMOUNT(ap->a_dvp->v_mount),
121628415Speter			    upperdvp, ap->a_cnp, un->un_path);
121728415Speter	}
121828415Speter	union_unlock_upper(upperdvp, td);
121928415Speter	return (error);
122028415Speter}
122134768Speter
122234768Speter/*
122328415Speter *	union_link:
122428415Speter *
122528415Speter *	tdvp and vp will be locked on entry.
122628415Speter *	tdvp and vp should remain locked on return.
122728415Speter */
122828415Speter
122928415Speterstatic int
123028415Speterunion_link(ap)
123128415Speter	struct vop_link_args /* {
123228415Speter		struct vnode *a_tdvp;
123328415Speter		struct vnode *a_vp;
123428415Speter		struct componentname *a_cnp;
123528415Speter	} */ *ap;
123628415Speter{
123728415Speter	struct componentname *cnp = ap->a_cnp;
123828415Speter	struct thread *td = cnp->cn_thread;
123928415Speter	struct union_node *dun = VTOUNION(ap->a_tdvp);
124028415Speter	struct vnode *vp;
124128415Speter	struct vnode *tdvp;
124228415Speter	int error = 0;
124328415Speter
124428415Speter	if (ap->a_tdvp->v_op != ap->a_vp->v_op) {
124528415Speter		vp = ap->a_vp;
124628415Speter	} else {
124728415Speter		struct union_node *tun = VTOUNION(ap->a_vp);
124828415Speter
124928415Speter		if (tun->un_uppervp == NULLVP) {
125028415Speter#if 0
125134768Speter			if (dun->un_uppervp == tun->un_dirvp) {
125228415Speter				if (dun->un_flags & UN_ULOCK) {
125328415Speter					dun->un_flags &= ~UN_ULOCK;
125428415Speter					VOP_UNLOCK(dun->un_uppervp, 0, td);
125528415Speter				}
125628415Speter			}
125728415Speter#endif
125828415Speter			error = union_copyup(tun, 1, cnp->cn_cred, td);
125928415Speter#if 0
126028415Speter			if (dun->un_uppervp == tun->un_dirvp) {
126128415Speter				vn_lock(dun->un_uppervp,
126228415Speter					    LK_EXCLUSIVE | LK_RETRY, td);
126328415Speter				dun->un_flags |= UN_ULOCK;
126428415Speter			}
126528415Speter#endif
126634768Speter			if (error)
126728415Speter				return (error);
126828415Speter		}
126928415Speter		vp = tun->un_uppervp;
127028415Speter		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
127128415Speter	}
127234768Speter
127328415Speter	/*
127428415Speter	 * Make sure upper is locked, then unlock the union directory we were
127528415Speter	 * called with to avoid a deadlock while we are calling VOP_LINK() on
127628415Speter	 * the upper (with tdvp locked and vp not locked).  Our ap->a_tdvp
127728415Speter	 * is expected to be locked on return.
127828415Speter	 */
127928415Speter
128028415Speter	if ((tdvp = union_lock_upper(dun, td)) == NULLVP)
128134768Speter		return (EROFS);
128228415Speter
128328415Speter	VOP_UNLOCK(ap->a_tdvp, 0, td);		/* unlock calling node */
128428415Speter	error = VOP_LINK(tdvp, vp, cnp);	/* call link on upper */
128528415Speter
128628415Speter	/*
128728415Speter	 * Unlock tun->un_uppervp if we locked it above.
128828415Speter	 */
128928415Speter	if (ap->a_tdvp->v_op == ap->a_vp->v_op)
129028415Speter		VOP_UNLOCK(vp, 0, td);
129128415Speter	/*
129228415Speter	 * We have to unlock tdvp prior to relocking our calling node in
129328415Speter	 * order to avoid a deadlock.  We also have to unlock ap->a_vp
129428415Speter	 * before relocking the directory, but then we have to relock
129528415Speter	 * ap->a_vp as our caller expects.
129628415Speter	 */
129728415Speter	VOP_UNLOCK(ap->a_vp, 0, td);
129828415Speter	union_unlock_upper(tdvp, td);
129928415Speter	vn_lock(ap->a_tdvp, LK_EXCLUSIVE | LK_RETRY, td);
130028415Speter	vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td);
130128415Speter	return (error);
130228415Speter}
130328415Speter
130428415Speterstatic int
130528415Speterunion_rename(ap)
130628415Speter	struct vop_rename_args  /* {
130728415Speter		struct vnode *a_fdvp;
130828415Speter		struct vnode *a_fvp;
130928415Speter		struct componentname *a_fcnp;
131028415Speter		struct vnode *a_tdvp;
131128415Speter		struct vnode *a_tvp;
131234768Speter		struct componentname *a_tcnp;
131334768Speter	} */ *ap;
131434768Speter{
131534768Speter	int error;
131634768Speter	struct vnode *fdvp = ap->a_fdvp;
131728415Speter	struct vnode *fvp = ap->a_fvp;
131828415Speter	struct vnode *tdvp = ap->a_tdvp;
131928415Speter	struct vnode *tvp = ap->a_tvp;
132028415Speter
132128415Speter	/*
132228415Speter	 * Figure out what fdvp to pass to our upper or lower vnode.  If we
132328415Speter	 * replace the fdvp, release the original one and ref the new one.
132428415Speter	 */
132528415Speter
132628415Speter	if (fdvp->v_op == union_vnodeop_p) {	/* always true */
132728415Speter		struct union_node *un = VTOUNION(fdvp);
132828415Speter		if (un->un_uppervp == NULLVP) {
132928415Speter			/*
133028415Speter			 * this should never happen in normal
133128415Speter			 * operation but might if there was
133228415Speter			 * a problem creating the top-level shadow
133328415Speter			 * directory.
133428415Speter			 */
133528415Speter			error = EXDEV;
133628415Speter			goto bad;
133728415Speter		}
133828415Speter		fdvp = un->un_uppervp;
133928415Speter		VREF(fdvp);
134028415Speter		vrele(ap->a_fdvp);
134128415Speter	}
134228415Speter
134328415Speter	/*
134428415Speter	 * Figure out what fvp to pass to our upper or lower vnode.  If we
134528415Speter	 * replace the fvp, release the original one and ref the new one.
134628415Speter	 */
134728415Speter
134828415Speter	if (fvp->v_op == union_vnodeop_p) {	/* always true */
134928415Speter		struct union_node *un = VTOUNION(fvp);
135028415Speter#if 0
135128415Speter		struct union_mount *um = MOUNTTOUNIONMOUNT(fvp->v_mount);
135228415Speter#endif
135328415Speter
135428415Speter		if (un->un_uppervp == NULLVP) {
135528415Speter			switch(fvp->v_type) {
135628415Speter			case VREG:
135728415Speter				vn_lock(un->un_vnode, LK_EXCLUSIVE | LK_RETRY, ap->a_fcnp->cn_thread);
135828415Speter				error = union_copyup(un, 1, ap->a_fcnp->cn_cred, ap->a_fcnp->cn_thread);
135928415Speter				VOP_UNLOCK(un->un_vnode, 0, ap->a_fcnp->cn_thread);
136028415Speter				if (error)
136128415Speter					goto bad;
136228415Speter				break;
136328415Speter			case VDIR:
136428415Speter				/*
136528415Speter				 * XXX not yet.
136628415Speter				 *
136728415Speter				 * There is only one way to rename a directory
136828415Speter				 * based in the lowervp, and that is to copy
136928415Speter				 * the entire directory hierarchy.  Otherwise
137028415Speter				 * it would not last across a reboot.
137128415Speter				 */
137228415Speter#if 0
137328415Speter				vrele(fvp);
137428415Speter				fvp = NULL;
137528415Speter				vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY, ap->a_fcnp->cn_thread);
137628415Speter				error = union_mkshadow(um, fdvp,
137728415Speter					    ap->a_fcnp, &un->un_uppervp);
137828415Speter				VOP_UNLOCK(fdvp, 0, ap->a_fcnp->cn_thread);
137928415Speter				if (un->un_uppervp)
138028415Speter					VOP_UNLOCK(un->un_uppervp, 0, ap->a_fcnp->cn_thread);
138128415Speter				if (error)
138228415Speter					goto bad;
138328415Speter				break;
138428415Speter#endif
138528415Speter			default:
138628415Speter				error = EXDEV;
138728415Speter				goto bad;
138828415Speter			}
138928415Speter		}
139028415Speter
139128415Speter		if (un->un_lowervp != NULLVP)
139228415Speter			ap->a_fcnp->cn_flags |= DOWHITEOUT;
139328415Speter		fvp = un->un_uppervp;
139428415Speter		VREF(fvp);
139534768Speter		vrele(ap->a_fvp);
139628415Speter	}
139728415Speter
139828415Speter	/*
139928415Speter	 * Figure out what tdvp (destination directory) to pass to the
140028415Speter	 * lower level.  If we replace it with uppervp, we need to vput the
140128415Speter	 * old one.  The exclusive lock is transfered to what we will pass
140228415Speter	 * down in the VOP_RENAME() and we replace uppervp with a simple
140328415Speter	 * reference.
140428415Speter	 */
140528415Speter
140634768Speter	if (tdvp->v_op == union_vnodeop_p) {
140734768Speter		struct union_node *un = VTOUNION(tdvp);
140828415Speter
140928415Speter		if (un->un_uppervp == NULLVP) {
141028415Speter			/*
141128415Speter			 * This should never happen in normal
141228415Speter			 * operation but might if there was
141328415Speter			 * a problem creating the top-level shadow
141428415Speter			 * directory.
141528415Speter			 */
141628415Speter			error = EXDEV;
141728415Speter			goto bad;
141828415Speter		}
141928415Speter
142028415Speter		/*
142134768Speter		 * New tdvp is a lock and reference on uppervp.
142228415Speter		 * Put away the old tdvp.
142334768Speter		 */
142434768Speter		tdvp = union_lock_upper(un, ap->a_tcnp->cn_thread);
142534768Speter		vput(ap->a_tdvp);
142634768Speter	}
142734768Speter
142828415Speter	/*
142928415Speter	 * Figure out what tvp (destination file) to pass to the
143034768Speter	 * lower level.
143128415Speter	 *
143228415Speter	 * If the uppervp file does not exist, put away the (wrong)
143328415Speter	 * file and change tvp to NULL.
143428415Speter	 */
143528415Speter
143628415Speter	if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
143728415Speter		struct union_node *un = VTOUNION(tvp);
143828415Speter
143928415Speter		tvp = union_lock_upper(un, ap->a_tcnp->cn_thread);
144028415Speter		vput(ap->a_tvp);
144128415Speter		/* note: tvp may be NULL */
144228415Speter	}
144328415Speter
144428415Speter	/*
144528415Speter	 * VOP_RENAME() releases/vputs prior to returning, so we have no
144628415Speter	 * cleanup to do.
144728415Speter	 */
144828415Speter
144928415Speter	return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
145028415Speter
145128415Speter	/*
145228415Speter	 * Error.  We still have to release / vput the various elements.
145328415Speter	 */
145428415Speter
145528415Speterbad:
145628415Speter	vrele(fdvp);
145728415Speter	if (fvp)
145828415Speter		vrele(fvp);
145928415Speter	vput(tdvp);
146028415Speter	if (tvp != NULLVP) {
146128415Speter		if (tvp != tdvp)
146228415Speter			vput(tvp);
146334768Speter		else
146428415Speter			vrele(tvp);
146528415Speter	}
146628415Speter	return (error);
146728415Speter}
146828415Speter
146928415Speterstatic int
147028415Speterunion_mkdir(ap)
147128415Speter	struct vop_mkdir_args /* {
147228415Speter		struct vnode *a_dvp;
147328415Speter		struct vnode **a_vpp;
147428415Speter		struct componentname *a_cnp;
147528415Speter		struct vattr *a_vap;
147628415Speter	} */ *ap;
147728415Speter{
147828415Speter	struct union_node *dun = VTOUNION(ap->a_dvp);
147928415Speter	struct componentname *cnp = ap->a_cnp;
148028415Speter	struct thread *td = cnp->cn_thread;
148128415Speter	struct vnode *upperdvp;
148234768Speter	int error = EROFS;
148334768Speter
148434768Speter	if ((upperdvp = union_lock_upper(dun, td)) != NULLVP) {
148534768Speter		struct vnode *vp;
148628415Speter
148728415Speter		error = VOP_MKDIR(upperdvp, &vp, cnp, ap->a_vap);
148828415Speter		union_unlock_upper(upperdvp, td);
148928415Speter
149028415Speter		if (error == 0) {
149128415Speter			VOP_UNLOCK(vp, 0, td);
149228415Speter			UDEBUG(("ALLOCVP-2 FROM %p REFS %d\n", vp, vrefcnt(vp)));
149328415Speter			error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount,
149428415Speter				ap->a_dvp, NULLVP, cnp, vp, NULLVP, 1);
149528415Speter			UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", *ap->a_vpp, vrefcnt(vp)));
149628415Speter		}
149728415Speter	}
149828415Speter	return (error);
149928415Speter}
150028415Speter
150128415Speterstatic int
150228415Speterunion_rmdir(ap)
150328415Speter	struct vop_rmdir_args /* {
150428415Speter		struct vnode *a_dvp;
150528415Speter		struct vnode *a_vp;
150628415Speter		struct componentname *a_cnp;
150728415Speter	} */ *ap;
150828415Speter{
150928415Speter	struct union_node *dun = VTOUNION(ap->a_dvp);
151028415Speter	struct union_node *un = VTOUNION(ap->a_vp);
151128415Speter	struct componentname *cnp = ap->a_cnp;
151228415Speter	struct thread *td = cnp->cn_thread;
151328415Speter	struct vnode *upperdvp;
151428415Speter	struct vnode *uppervp;
151528415Speter	int error;
151628415Speter
151728415Speter	if ((upperdvp = union_lock_upper(dun, td)) == NULLVP)
151828415Speter		panic("union rmdir: null upper vnode");
151928415Speter
152028415Speter	if ((uppervp = union_lock_upper(un, td)) != NULLVP) {
152128415Speter		if (union_dowhiteout(un, cnp->cn_cred, td))
152228415Speter			cnp->cn_flags |= DOWHITEOUT;
152328415Speter		error = VOP_RMDIR(upperdvp, uppervp, ap->a_cnp);
152428415Speter		union_unlock_upper(uppervp, td);
152528415Speter	} else {
152628415Speter		error = union_mkwhiteout(
152728415Speter			    MOUNTTOUNIONMOUNT(ap->a_dvp->v_mount),
152828415Speter			    dun->un_uppervp, ap->a_cnp, un->un_path);
152928415Speter	}
153028415Speter	union_unlock_upper(upperdvp, td);
153128415Speter	return (error);
153228415Speter}
153328415Speter
153428415Speter/*
153528415Speter *	union_symlink:
153628415Speter *
153728415Speter *	dvp is locked on entry and remains locked on return.  a_vpp is garbage
153828415Speter *	(unused).
153928415Speter */
154028415Speter
154128415Speterstatic int
154228415Speterunion_symlink(ap)
154334768Speter	struct vop_symlink_args /* {
154434768Speter		struct vnode *a_dvp;
154534768Speter		struct vnode **a_vpp;
154634768Speter		struct componentname *a_cnp;
154734768Speter		struct vattr *a_vap;
154834768Speter		char *a_target;
154928415Speter	} */ *ap;
155028415Speter{
155128415Speter	struct union_node *dun = VTOUNION(ap->a_dvp);
155228415Speter	struct componentname *cnp = ap->a_cnp;
155328415Speter	struct thread *td = cnp->cn_thread;
155428415Speter	struct vnode *dvp;
155534768Speter	int error = EROFS;
155634768Speter
155734768Speter	if ((dvp = union_lock_upper(dun, td)) != NULLVP) {
155828415Speter		error = VOP_SYMLINK(dvp, ap->a_vpp, cnp, ap->a_vap,
155928415Speter			    ap->a_target);
156028415Speter		union_unlock_upper(dvp, td);
156134768Speter	}
156234768Speter	return (error);
156334768Speter}
156434768Speter
156534768Speter/*
156634768Speter * union_readdir ()works in concert with getdirentries() and
156734768Speter * readdir(3) to provide a list of entries in the unioned
156834768Speter * directories.  getdirentries()  is responsible for walking
156934768Speter * down the union stack.  readdir(3) is responsible for
157034768Speter * eliminating duplicate names from the returned data stream.
157134768Speter */
157234768Speterstatic int
157334768Speterunion_readdir(ap)
157434768Speter	struct vop_readdir_args /* {
157534768Speter		struct vnode *a_vp;
157634768Speter		struct uio *a_uio;
157734768Speter		struct ucred *a_cred;
157834768Speter		int *a_eofflag;
157934768Speter		u_long *a_cookies;
158034768Speter		int a_ncookies;
158134768Speter	} */ *ap;
158234768Speter{
158334768Speter	struct union_node *un = VTOUNION(ap->a_vp);
158434768Speter	struct thread *td = ap->a_uio->uio_td;
158534768Speter	struct vnode *uvp;
158634768Speter	int error = 0;
158734768Speter
158834768Speter	if ((uvp = union_lock_upper(un, td)) != NULLVP) {
158934768Speter		ap->a_vp = uvp;
159034768Speter		error = VCALL(uvp, VOFFSET(vop_readdir), ap);
159134768Speter		union_unlock_upper(uvp, td);
159234768Speter	}
159334768Speter	return(error);
159434768Speter}
159534768Speter
159634768Speterstatic int
159734768Speterunion_readlink(ap)
159834768Speter	struct vop_readlink_args /* {
159934768Speter		struct vnode *a_vp;
160034768Speter		struct uio *a_uio;
160134768Speter		struct ucred *a_cred;
160234768Speter	} */ *ap;
160334768Speter{
160434768Speter	int error;
160534768Speter	struct union_node *un = VTOUNION(ap->a_vp);
160634768Speter	struct uio *uio = ap->a_uio;
160734768Speter	struct thread *td = uio->uio_td;
160834768Speter	struct vnode *vp;
160934768Speter
161034768Speter	vp = union_lock_other(un, td);
161134768Speter	KASSERT(vp != NULL, ("union_readlink: backing vnode missing!"));
161234768Speter
161334768Speter	ap->a_vp = vp;
161434768Speter	error = VCALL(vp, VOFFSET(vop_readlink), ap);
161534768Speter	union_unlock_other(vp, td);
161634768Speter
161734768Speter	return (error);
161834768Speter}
161934768Speter
162034768Speterstatic int
162134768Speterunion_getwritemount(ap)
162234768Speter	struct vop_getwritemount_args /* {
162334768Speter		struct vnode *a_vp;
162428415Speter		struct mount **a_mpp;
162528415Speter	} */ *ap;
162628415Speter{
162734768Speter	struct vnode *vp = ap->a_vp;
162828415Speter	struct vnode *uvp = UPPERVP(vp);
162928415Speter
163028415Speter	if (uvp == NULL) {
163128415Speter		VI_LOCK(vp);
163234768Speter		if (vp->v_iflag & VI_FREE) {
163328415Speter			VI_UNLOCK(vp);
163428415Speter			return (EOPNOTSUPP);
163528415Speter		}
163628415Speter		VI_UNLOCK(vp);
163728415Speter		return (EACCES);
163828415Speter	}
163928415Speter	return(VOP_GETWRITEMOUNT(uvp, ap->a_mpp));
164028415Speter}
164128415Speter
164234768Speter/*
164334768Speter *	union_inactive:
164434768Speter *
164528415Speter *	Called with the vnode locked.  We are expected to unlock the vnode.
164628415Speter */
164728415Speter
164828415Speterstatic int
164928415Speterunion_inactive(ap)
165028415Speter	struct vop_inactive_args /* {
165128415Speter		struct vnode *a_vp;
165228415Speter		struct thread *a_td;
165328415Speter	} */ *ap;
165428415Speter{
165528415Speter	struct vnode *vp = ap->a_vp;
165628415Speter	struct thread *td = ap->a_td;
165728415Speter	struct union_node *un = VTOUNION(vp);
165828415Speter	struct vnode **vpp;
165928415Speter
166028415Speter	/*
166128415Speter	 * Do nothing (and _don't_ bypass).
166228415Speter	 * Wait to vrele lowervp until reclaim,
166328415Speter	 * so that until then our union_node is in the
166428415Speter	 * cache and reusable.
166528415Speter	 *
166628415Speter	 */
166728415Speter
166828415Speter	if (un->un_dircache != 0) {
166928415Speter		for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
167028415Speter			vrele(*vpp);
167134768Speter		free (un->un_dircache, M_TEMP);
167234768Speter		un->un_dircache = 0;
167328415Speter	}
167428415Speter
167528415Speter#if 0
167628415Speter	if ((un->un_flags & UN_ULOCK) && un->un_uppervp) {
167728415Speter		un->un_flags &= ~UN_ULOCK;
167828415Speter		VOP_UNLOCK(un->un_uppervp, 0, td);
167928415Speter	}
168028415Speter#endif
168128415Speter
168228415Speter	VOP_UNLOCK(vp, 0, td);
168328415Speter
168428415Speter	if ((un->un_flags & UN_CACHED) == 0)
168528415Speter		vgone(vp);
168628415Speter
168728415Speter	return (0);
168828415Speter}
168928415Speter
169028415Speterstatic int
169128415Speterunion_reclaim(ap)
169228415Speter	struct vop_reclaim_args /* {
169328415Speter		struct vnode *a_vp;
169428415Speter	} */ *ap;
169528415Speter{
169628415Speter	union_freevp(ap->a_vp);
169728415Speter
169828415Speter	return (0);
169928415Speter}
170028415Speter
170128415Speter/*
170228415Speter * unionvp do not hold a VM object and there is no need to create one for
170328415Speter * upper or lower vp because it is done in the union_open()
170428415Speter */
170534768Speterstatic int
170628415Speterunion_createvobject(ap)
170728415Speter	struct vop_createvobject_args /* {
170828415Speter		struct vnode *vp;
170934768Speter		struct ucred *cred;
171028415Speter		struct thread *td;
171134768Speter	} */ *ap;
171234768Speter{
171328415Speter	struct vnode *vp = ap->a_vp;
171428415Speter
171528415Speter	vp->v_vflag |= VV_OBJBUF;
171628415Speter	return (0);
171728415Speter}
171828415Speter
171928415Speter/*
172034768Speter * We have nothing to destroy and this operation shouldn't be bypassed.
172128415Speter */
172228415Speterstatic int
172328415Speterunion_destroyvobject(ap)
172428415Speter	struct vop_destroyvobject_args /* {
172528415Speter		struct vnode *vp;
172628415Speter	} */ *ap;
172728415Speter{
172828415Speter	struct vnode *vp = ap->a_vp;
172928415Speter
173028415Speter	vp->v_vflag &= ~VV_OBJBUF;
173128415Speter	return (0);
173228415Speter}
173328415Speter
173428415Speter/*
173528415Speter * Get VM object from the upper or lower vp
173634768Speter */
173734768Speterstatic int
173834768Speterunion_getvobject(ap)
173928415Speter	struct vop_getvobject_args /* {
174028415Speter		struct vnode *vp;
174128415Speter		struct vm_object **objpp;
174228415Speter	} */ *ap;
174328415Speter{
174428415Speter	struct vnode *ovp = OTHERVP(ap->a_vp);
174528415Speter
174628415Speter	if (ovp == NULL)
174728415Speter		return EINVAL;
174828415Speter	return (VOP_GETVOBJECT(ovp, ap->a_objpp));
174928415Speter}
175028415Speter
175128415Speterstatic int
175228415Speterunion_print(ap)
175328415Speter	struct vop_print_args /* {
175428415Speter		struct vnode *a_vp;
175528415Speter	} */ *ap;
175628415Speter{
175728415Speter	struct vnode *vp = ap->a_vp;
175828415Speter
175928415Speter	printf("\ttag %s, vp=%p, uppervp=%p, lowervp=%p\n", vp->v_tag,
176028415Speter	       vp, UPPERVP(vp), LOWERVP(vp));
176128415Speter	if (UPPERVP(vp) != NULLVP)
176228415Speter		vprint("union: upper", UPPERVP(vp));
176328415Speter	if (LOWERVP(vp) != NULLVP)
176428415Speter		vprint("union: lower", LOWERVP(vp));
176528415Speter
176628415Speter	return (0);
176728415Speter}
176828415Speter
176928415Speterstatic int
177028415Speterunion_pathconf(ap)
177128415Speter	struct vop_pathconf_args /* {
177228415Speter		struct vnode *a_vp;
177328415Speter		int a_name;
177428415Speter		int *a_retval;
177528415Speter	} */ *ap;
177628415Speter{
177728415Speter	int error;
177828415Speter	struct thread *td = curthread;		/* XXX */
177928415Speter	struct union_node *un = VTOUNION(ap->a_vp);
178028415Speter	struct vnode *vp;
178128415Speter
178228415Speter	vp = union_lock_other(un, td);
178328415Speter	KASSERT(vp != NULL, ("union_pathconf: backing vnode missing!"));
178434768Speter
178534768Speter	ap->a_vp = vp;
178628415Speter	error = VCALL(vp, VOFFSET(vop_pathconf), ap);
178728415Speter	union_unlock_other(vp, td);
178828415Speter
178928415Speter	return (error);
179028415Speter}
179128415Speter
179228415Speterstatic int
179328415Speterunion_advlock(ap)
179428415Speter	struct vop_advlock_args /* {
179528415Speter		struct vnode *a_vp;
179628415Speter		caddr_t  a_id;
179728415Speter		int  a_op;
179828415Speter		struct flock *a_fl;
179928415Speter		int  a_flags;
180028415Speter	} */ *ap;
180128415Speter{
180228415Speter	register struct vnode *ovp = OTHERVP(ap->a_vp);
180334768Speter
180428415Speter	ap->a_vp = ovp;
180528415Speter	return (VCALL(ovp, VOFFSET(vop_advlock), ap));
180628415Speter}
180728415Speter
180828415Speter
180928415Speter/*
181028415Speter * XXX - vop_strategy must be hand coded because it has no
181134768Speter * YYY - and it is not coherent with anything
181234768Speter *
181328415Speter * vnode in its arguments.
181428415Speter * This goes away with a merged VM/buffer cache.
181528415Speter */
181634768Speterstatic int
181728415Speterunion_strategy(ap)
181828415Speter	struct vop_strategy_args /* {
181928415Speter		struct vnode *a_vp;
182028415Speter		struct buf *a_bp;
182128415Speter	} */ *ap;
182228415Speter{
182328415Speter	struct buf *bp = ap->a_bp;
182428415Speter	struct vnode *othervp = OTHERVP(bp->b_vp);
182528415Speter
182628415Speter#ifdef DIAGNOSTIC
182728415Speter	if (othervp == NULLVP)
182828415Speter		panic("union_strategy: nil vp");
182934768Speter	if ((bp->b_iocmd == BIO_WRITE) &&
183028415Speter	    (othervp == LOWERVP(bp->b_vp)))
183128415Speter		panic("union_strategy: writing to lowervp");
183234768Speter#endif
183334768Speter	return (VOP_STRATEGY(othervp, bp));
183428415Speter}
183534768Speter
183628415Speter/*
183734768Speter * Global vfs data structures
183828415Speter */
183934768Spetervop_t **union_vnodeop_p;
184028415Speterstatic struct vnodeopv_entry_desc union_vnodeop_entries[] = {
184128415Speter	{ &vop_default_desc,		(vop_t *) vop_defaultop },
184228415Speter	{ &vop_access_desc,		(vop_t *) union_access },
184328415Speter	{ &vop_advlock_desc,		(vop_t *) union_advlock },
184428415Speter	{ &vop_bmap_desc,		(vop_t *) vop_eopnotsupp },
184528415Speter	{ &vop_close_desc,		(vop_t *) union_close },
184628415Speter	{ &vop_create_desc,		(vop_t *) union_create },
184728415Speter	{ &vop_createvobject_desc,	(vop_t *) union_createvobject },
184828415Speter	{ &vop_destroyvobject_desc,	(vop_t *) union_destroyvobject },
184928415Speter	{ &vop_fsync_desc,		(vop_t *) union_fsync },
185028415Speter	{ &vop_getattr_desc,		(vop_t *) union_getattr },
185128415Speter	{ &vop_getvobject_desc,		(vop_t *) union_getvobject },
185228415Speter	{ &vop_inactive_desc,		(vop_t *) union_inactive },
185328415Speter	{ &vop_ioctl_desc,		(vop_t *) union_ioctl },
185428415Speter	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
185528415Speter	{ &vop_lease_desc,		(vop_t *) union_lease },
185628415Speter	{ &vop_link_desc,		(vop_t *) union_link },
185728415Speter	{ &vop_lookup_desc,		(vop_t *) union_lookup },
185828415Speter	{ &vop_mkdir_desc,		(vop_t *) union_mkdir },
185928415Speter	{ &vop_mknod_desc,		(vop_t *) union_mknod },
186028415Speter	{ &vop_open_desc,		(vop_t *) union_open },
186128415Speter	{ &vop_pathconf_desc,		(vop_t *) union_pathconf },
186228415Speter	{ &vop_poll_desc,		(vop_t *) union_poll },
186328415Speter	{ &vop_print_desc,		(vop_t *) union_print },
186428415Speter	{ &vop_read_desc,		(vop_t *) union_read },
186528415Speter	{ &vop_readdir_desc,		(vop_t *) union_readdir },
186628415Speter	{ &vop_readlink_desc,		(vop_t *) union_readlink },
186728415Speter	{ &vop_getwritemount_desc,	(vop_t *) union_getwritemount },
186828415Speter	{ &vop_reclaim_desc,		(vop_t *) union_reclaim },
186934768Speter	{ &vop_remove_desc,		(vop_t *) union_remove },
187028415Speter	{ &vop_rename_desc,		(vop_t *) union_rename },
187134768Speter	{ &vop_revoke_desc,		(vop_t *) union_revoke },
187234768Speter	{ &vop_rmdir_desc,		(vop_t *) union_rmdir },
187328415Speter	{ &vop_setattr_desc,		(vop_t *) union_setattr },
187428415Speter	{ &vop_strategy_desc,		(vop_t *) union_strategy },
187528415Speter	{ &vop_symlink_desc,		(vop_t *) union_symlink },
187628415Speter	{ &vop_whiteout_desc,		(vop_t *) union_whiteout },
187728415Speter	{ &vop_write_desc,		(vop_t *) union_write },
187828415Speter	{ NULL, NULL }
187928415Speter};
188028415Speterstatic struct vnodeopv_desc union_vnodeop_opv_desc =
188128415Speter	{ &union_vnodeop_p, union_vnodeop_entries };
188228415Speter
188328415SpeterVNODEOP_SET(union_vnodeop_opv_desc);
188428415Speter