xref: /csrg-svn/sys/miscfs/union/union_vnops.c (revision 67751)
165935Spendry /*
265935Spendry  * Copyright (c) 1992, 1993, 1994 The Regents of the University of California.
365935Spendry  * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry.
465935Spendry  * All rights reserved.
565935Spendry  *
665935Spendry  * This code is derived from software contributed to Berkeley by
765963Spendry  * Jan-Simon Pendry.
865935Spendry  *
965935Spendry  * %sccs.include.redist.c%
1065935Spendry  *
11*67751Spendry  *	@(#)union_vnops.c	8.20 (Berkeley) 08/31/94
1265935Spendry  */
1365935Spendry 
1465935Spendry #include <sys/param.h>
1565935Spendry #include <sys/systm.h>
1665935Spendry #include <sys/proc.h>
1765935Spendry #include <sys/file.h>
1865935Spendry #include <sys/time.h>
1967575Spendry #include <sys/stat.h>
2065935Spendry #include <sys/types.h>
2165935Spendry #include <sys/vnode.h>
2265935Spendry #include <sys/mount.h>
2365935Spendry #include <sys/namei.h>
2465935Spendry #include <sys/malloc.h>
2565935Spendry #include <sys/buf.h>
2666053Spendry #include <sys/queue.h>
2766055Spendry #include <miscfs/union/union.h>
2865935Spendry 
2966152Spendry #define FIXUP(un) { \
3066152Spendry 	if (((un)->un_flags & UN_ULOCK) == 0) { \
3166152Spendry 		union_fixup(un); \
3266152Spendry 	} \
3366152Spendry }
3466152Spendry 
3566152Spendry static void
3666152Spendry union_fixup(un)
3766152Spendry 	struct union_node *un;
3866152Spendry {
3966152Spendry 
4066152Spendry 	VOP_LOCK(un->un_uppervp);
4166152Spendry 	un->un_flags |= UN_ULOCK;
4266152Spendry }
4366152Spendry 
4465935Spendry static int
4567064Spendry union_lookup1(udvp, dvpp, vpp, cnp)
4665989Spendry 	struct vnode *udvp;
4767064Spendry 	struct vnode **dvpp;
4865935Spendry 	struct vnode **vpp;
4965935Spendry 	struct componentname *cnp;
5065935Spendry {
5165935Spendry 	int error;
5265935Spendry 	struct vnode *tdvp;
5367064Spendry 	struct vnode *dvp;
5465935Spendry 	struct mount *mp;
5565935Spendry 
5667064Spendry 	dvp = *dvpp;
5767064Spendry 
5865994Spendry 	/*
5965994Spendry 	 * If stepping up the directory tree, check for going
6065994Spendry 	 * back across the mount point, in which case do what
6165994Spendry 	 * lookup would do by stepping back down the mount
6265994Spendry 	 * hierarchy.
6365994Spendry 	 */
6465935Spendry 	if (cnp->cn_flags & ISDOTDOT) {
6567064Spendry 		while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
6666034Spendry 			/*
6766034Spendry 			 * Don't do the NOCROSSMOUNT check
6866034Spendry 			 * at this level.  By definition,
6966034Spendry 			 * union fs deals with namespaces, not
7066034Spendry 			 * filesystems.
7166034Spendry 			 */
7265935Spendry 			tdvp = dvp;
7367064Spendry 			*dvpp = dvp = dvp->v_mount->mnt_vnodecovered;
7465935Spendry 			vput(tdvp);
7565935Spendry 			VREF(dvp);
7665935Spendry 			VOP_LOCK(dvp);
7765935Spendry 		}
7865935Spendry 	}
7966027Spendry 
8065935Spendry         error = VOP_LOOKUP(dvp, &tdvp, cnp);
8165935Spendry 	if (error)
8265935Spendry 		return (error);
8365935Spendry 
8465994Spendry 	/*
8566027Spendry 	 * The parent directory will have been unlocked, unless lookup
8666027Spendry 	 * found the last component.  In which case, re-lock the node
8766027Spendry 	 * here to allow it to be unlocked again (phew) in union_lookup.
8865994Spendry 	 */
8966027Spendry 	if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN))
9065994Spendry 		VOP_LOCK(dvp);
9165994Spendry 
9265935Spendry 	dvp = tdvp;
9365994Spendry 
9465994Spendry 	/*
9565994Spendry 	 * Lastly check if the current node is a mount point in
9666034Spendry 	 * which case walk up the mount hierarchy making sure not to
9765994Spendry 	 * bump into the root of the mount tree (ie. dvp != udvp).
9865994Spendry 	 */
9965989Spendry 	while (dvp != udvp && (dvp->v_type == VDIR) &&
10066034Spendry 	       (mp = dvp->v_mountedhere)) {
10165935Spendry 
10265935Spendry 		if (mp->mnt_flag & MNT_MLOCK) {
10365935Spendry 			mp->mnt_flag |= MNT_MWAIT;
10465935Spendry 			sleep((caddr_t) mp, PVFS);
10565935Spendry 			continue;
10665935Spendry 		}
10765935Spendry 
10865935Spendry 		if (error = VFS_ROOT(mp, &tdvp)) {
10965935Spendry 			vput(dvp);
11065935Spendry 			return (error);
11165935Spendry 		}
11265935Spendry 
11365965Spendry 		vput(dvp);
11465935Spendry 		dvp = tdvp;
11565935Spendry 	}
11665935Spendry 
11765935Spendry 	*vpp = dvp;
11865935Spendry 	return (0);
11965935Spendry }
12065935Spendry 
12165935Spendry int
12265935Spendry union_lookup(ap)
12365935Spendry 	struct vop_lookup_args /* {
12465935Spendry 		struct vnodeop_desc *a_desc;
12565935Spendry 		struct vnode *a_dvp;
12665935Spendry 		struct vnode **a_vpp;
12765935Spendry 		struct componentname *a_cnp;
12865935Spendry 	} */ *ap;
12965935Spendry {
13065965Spendry 	int error;
13165935Spendry 	int uerror, lerror;
13265935Spendry 	struct vnode *uppervp, *lowervp;
13365935Spendry 	struct vnode *upperdvp, *lowerdvp;
13465935Spendry 	struct vnode *dvp = ap->a_dvp;
13565989Spendry 	struct union_node *dun = VTOUNION(dvp);
13665935Spendry 	struct componentname *cnp = ap->a_cnp;
13765935Spendry 	int lockparent = cnp->cn_flags & LOCKPARENT;
13865994Spendry 	int rdonly = cnp->cn_flags & RDONLY;
13965997Spendry 	struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
14066152Spendry 	struct ucred *saved_cred;
14167575Spendry 	int iswhiteout;
14267575Spendry 	struct vattr va;
14365935Spendry 
14467446Spendry #ifdef notyet
14567446Spendry 	if (cnp->cn_namelen == 3 &&
14667446Spendry 			cnp->cn_nameptr[2] == '.' &&
14767446Spendry 			cnp->cn_nameptr[1] == '.' &&
14867446Spendry 			cnp->cn_nameptr[0] == '.') {
14967446Spendry 		dvp = *ap->a_vpp = LOWERVP(ap->a_dvp);
15067446Spendry 		if (dvp == NULLVP)
15167446Spendry 			return (ENOENT);
15267446Spendry 		VREF(dvp);
15367446Spendry 		VOP_LOCK(dvp);
15467446Spendry 		if (!lockparent || !(cnp->cn_flags & ISLASTCN))
15567446Spendry 			VOP_UNLOCK(ap->a_dvp);
15667446Spendry 		return (0);
15767446Spendry 	}
15867446Spendry #endif
15967446Spendry 
16065965Spendry 	cnp->cn_flags |= LOCKPARENT;
16165965Spendry 
16265935Spendry 	upperdvp = dun->un_uppervp;
16365935Spendry 	lowerdvp = dun->un_lowervp;
16465997Spendry 	uppervp = NULLVP;
16565997Spendry 	lowervp = NULLVP;
16667575Spendry 	iswhiteout = 0;
16765935Spendry 
16865935Spendry 	/*
16965935Spendry 	 * do the lookup in the upper level.
17065935Spendry 	 * if that level comsumes additional pathnames,
17165935Spendry 	 * then assume that something special is going
17265935Spendry 	 * on and just return that vnode.
17365935Spendry 	 */
17467076Spendry 	if (upperdvp != NULLVP) {
17566152Spendry 		FIXUP(dun);
17667064Spendry 		uerror = union_lookup1(um->um_uppervp, &upperdvp,
17765997Spendry 					&uppervp, cnp);
17866051Spendry 		/*if (uppervp == upperdvp)
17966051Spendry 			dun->un_flags |= UN_KLOCK;*/
18065965Spendry 
18165935Spendry 		if (cnp->cn_consume != 0) {
18265935Spendry 			*ap->a_vpp = uppervp;
18365965Spendry 			if (!lockparent)
18465965Spendry 				cnp->cn_flags &= ~LOCKPARENT;
18565935Spendry 			return (uerror);
18665935Spendry 		}
18767575Spendry 		if (uerror == ENOENT || uerror == EJUSTRETURN) {
18867575Spendry 			if (cnp->cn_flags & ISWHITEOUT) {
18967575Spendry 				iswhiteout = 1;
19067575Spendry 			} else if (lowerdvp != NULLVP) {
19167575Spendry 				lerror = VOP_GETATTR(upperdvp, &va,
19267575Spendry 					cnp->cn_cred, cnp->cn_proc);
19367575Spendry 				if (lerror == 0 && (va.va_flags & OPAQUE))
19467575Spendry 					iswhiteout = 1;
19567575Spendry 			}
19667575Spendry 		}
19765935Spendry 	} else {
19865935Spendry 		uerror = ENOENT;
19965935Spendry 	}
20065935Spendry 
20165935Spendry 	/*
20265935Spendry 	 * in a similar way to the upper layer, do the lookup
20365935Spendry 	 * in the lower layer.   this time, if there is some
20465935Spendry 	 * component magic going on, then vput whatever we got
20565935Spendry 	 * back from the upper layer and return the lower vnode
20665935Spendry 	 * instead.
20765935Spendry 	 */
20867575Spendry 	if (lowerdvp != NULLVP && !iswhiteout) {
20966051Spendry 		int nameiop;
21066051Spendry 
21165965Spendry 		VOP_LOCK(lowerdvp);
21266051Spendry 
21366051Spendry 		/*
21466051Spendry 		 * Only do a LOOKUP on the bottom node, since
21566051Spendry 		 * we won't be making changes to it anyway.
21666051Spendry 		 */
21766051Spendry 		nameiop = cnp->cn_nameiop;
21866051Spendry 		cnp->cn_nameiop = LOOKUP;
21966152Spendry 		if (um->um_op == UNMNT_BELOW) {
22066152Spendry 			saved_cred = cnp->cn_cred;
22166152Spendry 			cnp->cn_cred = um->um_cred;
22266152Spendry 		}
22367064Spendry 		lerror = union_lookup1(um->um_lowervp, &lowerdvp,
22466051Spendry 				&lowervp, cnp);
22566152Spendry 		if (um->um_op == UNMNT_BELOW)
22666152Spendry 			cnp->cn_cred = saved_cred;
22766051Spendry 		cnp->cn_nameiop = nameiop;
22866051Spendry 
22965989Spendry 		if (lowervp != lowerdvp)
23065989Spendry 			VOP_UNLOCK(lowerdvp);
23165965Spendry 
23265935Spendry 		if (cnp->cn_consume != 0) {
23367076Spendry 			if (uppervp != NULLVP) {
23466051Spendry 				if (uppervp == upperdvp)
23566051Spendry 					vrele(uppervp);
23666051Spendry 				else
23766051Spendry 					vput(uppervp);
23865997Spendry 				uppervp = NULLVP;
23965935Spendry 			}
24065935Spendry 			*ap->a_vpp = lowervp;
24165965Spendry 			if (!lockparent)
24265965Spendry 				cnp->cn_flags &= ~LOCKPARENT;
24365935Spendry 			return (lerror);
24465935Spendry 		}
24565935Spendry 	} else {
24665935Spendry 		lerror = ENOENT;
24767416Spendry 		if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
24867416Spendry 			lowervp = LOWERVP(dun->un_pvp);
24967416Spendry 			if (lowervp != NULLVP) {
25067416Spendry 				VREF(lowervp);
25167416Spendry 				VOP_LOCK(lowervp);
25267416Spendry 				lerror = 0;
25367416Spendry 			}
25467416Spendry 		}
25565935Spendry 	}
25665935Spendry 
25765965Spendry 	if (!lockparent)
25865965Spendry 		cnp->cn_flags &= ~LOCKPARENT;
25965965Spendry 
26065935Spendry 	/*
26165935Spendry 	 * at this point, we have uerror and lerror indicating
26265935Spendry 	 * possible errors with the lookups in the upper and lower
26365935Spendry 	 * layers.  additionally, uppervp and lowervp are (locked)
26465935Spendry 	 * references to existing vnodes in the upper and lower layers.
26565935Spendry 	 *
26665935Spendry 	 * there are now three cases to consider.
26765935Spendry 	 * 1. if both layers returned an error, then return whatever
26865935Spendry 	 *    error the upper layer generated.
26965935Spendry 	 *
27065935Spendry 	 * 2. if the top layer failed and the bottom layer succeeded
27165935Spendry 	 *    then two subcases occur.
27265935Spendry 	 *    a.  the bottom vnode is not a directory, in which
27365935Spendry 	 *	  case just return a new union vnode referencing
27465935Spendry 	 *	  an empty top layer and the existing bottom layer.
27565935Spendry 	 *    b.  the bottom vnode is a directory, in which case
27665935Spendry 	 *	  create a new directory in the top-level and
27765935Spendry 	 *	  continue as in case 3.
27865935Spendry 	 *
27965935Spendry 	 * 3. if the top layer succeeded then return a new union
28065935Spendry 	 *    vnode referencing whatever the new top layer and
28165935Spendry 	 *    whatever the bottom layer returned.
28265935Spendry 	 */
28365935Spendry 
28466027Spendry 	*ap->a_vpp = NULLVP;
28566027Spendry 
28665935Spendry 	/* case 1. */
28765935Spendry 	if ((uerror != 0) && (lerror != 0)) {
28865935Spendry 		return (uerror);
28965935Spendry 	}
29065935Spendry 
29165935Spendry 	/* case 2. */
29265935Spendry 	if (uerror != 0 /* && (lerror == 0) */ ) {
29365935Spendry 		if (lowervp->v_type == VDIR) { /* case 2b. */
29466051Spendry 			dun->un_flags &= ~UN_ULOCK;
29566051Spendry 			VOP_UNLOCK(upperdvp);
29665997Spendry 			uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
29766051Spendry 			VOP_LOCK(upperdvp);
29866051Spendry 			dun->un_flags |= UN_ULOCK;
29966051Spendry 
30065935Spendry 			if (uerror) {
30167076Spendry 				if (lowervp != NULLVP) {
30265935Spendry 					vput(lowervp);
30365997Spendry 					lowervp = NULLVP;
30465935Spendry 				}
30565935Spendry 				return (uerror);
30665935Spendry 			}
30765935Spendry 		}
30865935Spendry 	}
30965935Spendry 
31067076Spendry 	if (lowervp != NULLVP)
31165965Spendry 		VOP_UNLOCK(lowervp);
31265965Spendry 
31365997Spendry 	error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
31465997Spendry 			      uppervp, lowervp);
31565997Spendry 
31665965Spendry 	if (error) {
31767076Spendry 		if (uppervp != NULLVP)
31866051Spendry 			vput(uppervp);
31967076Spendry 		if (lowervp != NULLVP)
32065965Spendry 			vrele(lowervp);
32165965Spendry 	} else {
32265994Spendry 		if (*ap->a_vpp != dvp)
32365994Spendry 			if (!lockparent || !(cnp->cn_flags & ISLASTCN))
32465994Spendry 				VOP_UNLOCK(dvp);
32565965Spendry 	}
32665965Spendry 
32765965Spendry 	return (error);
32865935Spendry }
32965935Spendry 
33065963Spendry int
33165963Spendry union_create(ap)
33265963Spendry 	struct vop_create_args /* {
33365963Spendry 		struct vnode *a_dvp;
33465963Spendry 		struct vnode **a_vpp;
33565963Spendry 		struct componentname *a_cnp;
33665963Spendry 		struct vattr *a_vap;
33765963Spendry 	} */ *ap;
33865963Spendry {
33965963Spendry 	struct union_node *un = VTOUNION(ap->a_dvp);
34065963Spendry 	struct vnode *dvp = un->un_uppervp;
34165963Spendry 
34267076Spendry 	if (dvp != NULLVP) {
34365963Spendry 		int error;
34465963Spendry 		struct vnode *vp;
34565963Spendry 
34666152Spendry 		FIXUP(un);
34766152Spendry 
34865963Spendry 		VREF(dvp);
34966051Spendry 		un->un_flags |= UN_KLOCK;
35065963Spendry 		vput(ap->a_dvp);
35165963Spendry 		error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap);
35265963Spendry 		if (error)
35365963Spendry 			return (error);
35465963Spendry 
35565963Spendry 		error = union_allocvp(
35665963Spendry 				ap->a_vpp,
35765989Spendry 				ap->a_dvp->v_mount,
35865989Spendry 				ap->a_dvp,
35965965Spendry 				NULLVP,
36065963Spendry 				ap->a_cnp,
36165963Spendry 				vp,
36265963Spendry 				NULLVP);
36365965Spendry 		if (error)
36466051Spendry 			vput(vp);
36565963Spendry 		return (error);
36665963Spendry 	}
36765963Spendry 
36865963Spendry 	vput(ap->a_dvp);
36965963Spendry 	return (EROFS);
37065963Spendry }
37165963Spendry 
37265963Spendry int
37367575Spendry union_whiteout(ap)
37467575Spendry 	struct vop_whiteout_args /* {
37567575Spendry 		struct vnode *a_dvp;
37667575Spendry 		struct componentname *a_cnp;
37767575Spendry 		int a_flags;
37867575Spendry 	} */ *ap;
37967575Spendry {
38067575Spendry 	struct union_node *un = VTOUNION(ap->a_dvp);
38167575Spendry 
38267575Spendry 	if (un->un_uppervp == NULLVP)
38367575Spendry 		return (EOPNOTSUPP);
38467575Spendry 
38567575Spendry 	FIXUP(un);
38667575Spendry 	return (VOP_WHITEOUT(un->un_uppervp, ap->a_cnp, ap->a_flags));
38767575Spendry }
38867575Spendry 
38967575Spendry int
39065963Spendry union_mknod(ap)
39165963Spendry 	struct vop_mknod_args /* {
39265963Spendry 		struct vnode *a_dvp;
39365963Spendry 		struct vnode **a_vpp;
39465963Spendry 		struct componentname *a_cnp;
39565963Spendry 		struct vattr *a_vap;
39665963Spendry 	} */ *ap;
39765963Spendry {
39865963Spendry 	struct union_node *un = VTOUNION(ap->a_dvp);
39965963Spendry 	struct vnode *dvp = un->un_uppervp;
40065963Spendry 
40167076Spendry 	if (dvp != NULLVP) {
40265963Spendry 		int error;
40365963Spendry 		struct vnode *vp;
40465963Spendry 
40566152Spendry 		FIXUP(un);
40666152Spendry 
40765963Spendry 		VREF(dvp);
40866051Spendry 		un->un_flags |= UN_KLOCK;
40965963Spendry 		vput(ap->a_dvp);
41065963Spendry 		error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap);
41165963Spendry 		if (error)
41265963Spendry 			return (error);
41365963Spendry 
41467076Spendry 		if (vp != NULLVP) {
41565965Spendry 			error = union_allocvp(
41665965Spendry 					ap->a_vpp,
41765989Spendry 					ap->a_dvp->v_mount,
41865989Spendry 					ap->a_dvp,
41965965Spendry 					NULLVP,
42065965Spendry 					ap->a_cnp,
42165965Spendry 					vp,
42265965Spendry 					NULLVP);
42365965Spendry 			if (error)
42466051Spendry 				vput(vp);
42565965Spendry 		}
42665963Spendry 		return (error);
42765963Spendry 	}
42865963Spendry 
42965963Spendry 	vput(ap->a_dvp);
43065963Spendry 	return (EROFS);
43165963Spendry }
43265963Spendry 
43365935Spendry int
43465935Spendry union_open(ap)
43565935Spendry 	struct vop_open_args /* {
43665935Spendry 		struct vnodeop_desc *a_desc;
43765935Spendry 		struct vnode *a_vp;
43865935Spendry 		int a_mode;
43965935Spendry 		struct ucred *a_cred;
44065935Spendry 		struct proc *a_p;
44165935Spendry 	} */ *ap;
44265935Spendry {
44365935Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
44465965Spendry 	struct vnode *tvp;
44565935Spendry 	int mode = ap->a_mode;
44665935Spendry 	struct ucred *cred = ap->a_cred;
44765935Spendry 	struct proc *p = ap->a_p;
44865965Spendry 	int error;
44965935Spendry 
45065935Spendry 	/*
45165935Spendry 	 * If there is an existing upper vp then simply open that.
45265935Spendry 	 */
45365965Spendry 	tvp = un->un_uppervp;
45465965Spendry 	if (tvp == NULLVP) {
45565935Spendry 		/*
45665965Spendry 		 * If the lower vnode is being opened for writing, then
45765965Spendry 		 * copy the file contents to the upper vnode and open that,
45865965Spendry 		 * otherwise can simply open the lower vnode.
45965935Spendry 		 */
46065965Spendry 		tvp = un->un_lowervp;
46165965Spendry 		if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
46267169Spendry 			error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
46365965Spendry 			if (error == 0)
46465965Spendry 				error = VOP_OPEN(un->un_uppervp, mode, cred, p);
46565965Spendry 			return (error);
46665935Spendry 		}
46766051Spendry 
46866051Spendry 		/*
46966051Spendry 		 * Just open the lower vnode
47066051Spendry 		 */
47166027Spendry 		un->un_openl++;
47266051Spendry 		VOP_LOCK(tvp);
47366051Spendry 		error = VOP_OPEN(tvp, mode, cred, p);
47466051Spendry 		VOP_UNLOCK(tvp);
47566051Spendry 
47666051Spendry 		return (error);
47765935Spendry 	}
47865935Spendry 
47966152Spendry 	FIXUP(un);
48066152Spendry 
48165965Spendry 	error = VOP_OPEN(tvp, mode, cred, p);
48265965Spendry 
48365965Spendry 	return (error);
48465935Spendry }
48565935Spendry 
48665963Spendry int
48765963Spendry union_close(ap)
48865963Spendry 	struct vop_close_args /* {
48965963Spendry 		struct vnode *a_vp;
49065963Spendry 		int  a_fflag;
49165963Spendry 		struct ucred *a_cred;
49265963Spendry 		struct proc *a_p;
49365963Spendry 	} */ *ap;
49465963Spendry {
49565997Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
49665997Spendry 	struct vnode *vp;
49765963Spendry 
49867076Spendry 	if (un->un_uppervp != NULLVP) {
49965997Spendry 		vp = un->un_uppervp;
50065997Spendry 	} else {
50166027Spendry #ifdef UNION_DIAGNOSTIC
50266027Spendry 		if (un->un_openl <= 0)
50366027Spendry 			panic("union: un_openl cnt");
50465997Spendry #endif
50566027Spendry 		--un->un_openl;
50665997Spendry 		vp = un->un_lowervp;
50765997Spendry 	}
50866027Spendry 
50965997Spendry 	return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p));
51065963Spendry }
51165963Spendry 
51265935Spendry /*
51365963Spendry  * Check access permission on the union vnode.
51465963Spendry  * The access check being enforced is to check
51565963Spendry  * against both the underlying vnode, and any
51665963Spendry  * copied vnode.  This ensures that no additional
51765963Spendry  * file permissions are given away simply because
51865963Spendry  * the user caused an implicit file copy.
51965963Spendry  */
52065963Spendry int
52165963Spendry union_access(ap)
52265963Spendry 	struct vop_access_args /* {
52365963Spendry 		struct vnodeop_desc *a_desc;
52465963Spendry 		struct vnode *a_vp;
52565963Spendry 		int a_mode;
52665963Spendry 		struct ucred *a_cred;
52765963Spendry 		struct proc *a_p;
52865963Spendry 	} */ *ap;
52965963Spendry {
53065963Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
53166149Spendry 	int error = EACCES;
53265963Spendry 	struct vnode *vp;
53365963Spendry 
53467076Spendry 	if ((vp = un->un_uppervp) != NULLVP) {
53566152Spendry 		FIXUP(un);
53666152Spendry 		return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p));
53766152Spendry 	}
53866152Spendry 
53967076Spendry 	if ((vp = un->un_lowervp) != NULLVP) {
54065965Spendry 		VOP_LOCK(vp);
54165963Spendry 		error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);
54266152Spendry 		if (error == 0) {
54366152Spendry 			struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);
54466152Spendry 
54566152Spendry 			if (um->um_op == UNMNT_BELOW)
54666152Spendry 				error = VOP_ACCESS(vp, ap->a_mode,
54766152Spendry 						um->um_cred, ap->a_p);
54866152Spendry 		}
54965965Spendry 		VOP_UNLOCK(vp);
55065963Spendry 		if (error)
55165963Spendry 			return (error);
55265963Spendry 	}
55365963Spendry 
55465965Spendry 	return (error);
55565963Spendry }
55665963Spendry 
55765963Spendry /*
55867109Spendry  * We handle getattr only to change the fsid and
55967109Spendry  * track object sizes
56065935Spendry  */
56165935Spendry int
56265935Spendry union_getattr(ap)
56365935Spendry 	struct vop_getattr_args /* {
56465935Spendry 		struct vnode *a_vp;
56565935Spendry 		struct vattr *a_vap;
56665935Spendry 		struct ucred *a_cred;
56765935Spendry 		struct proc *a_p;
56865935Spendry 	} */ *ap;
56965935Spendry {
57065935Spendry 	int error;
57166062Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
57266062Spendry 	struct vnode *vp = un->un_uppervp;
57366062Spendry 	struct vattr *vap;
57466062Spendry 	struct vattr va;
57565935Spendry 
57666062Spendry 
57766062Spendry 	/*
57866062Spendry 	 * Some programs walk the filesystem hierarchy by counting
57966062Spendry 	 * links to directories to avoid stat'ing all the time.
58066062Spendry 	 * This means the link count on directories needs to be "correct".
58166062Spendry 	 * The only way to do that is to call getattr on both layers
58266062Spendry 	 * and fix up the link count.  The link count will not necessarily
58366062Spendry 	 * be accurate but will be large enough to defeat the tree walkers.
58466062Spendry 	 */
58566062Spendry 
58666062Spendry 	vap = ap->a_vap;
58766062Spendry 
58866062Spendry 	vp = un->un_uppervp;
58966062Spendry 	if (vp != NULLVP) {
59067073Spendry 		/*
59167073Spendry 		 * It's not clear whether VOP_GETATTR is to be
59267073Spendry 		 * called with the vnode locked or not.  stat() calls
59367073Spendry 		 * it with (vp) locked, and fstat calls it with
59467073Spendry 		 * (vp) unlocked.
59567073Spendry 		 * In the mean time, compensate here by checking
59667073Spendry 		 * the union_node's lock flag.
59767073Spendry 		 */
59867073Spendry 		if (un->un_flags & UN_LOCKED)
59967073Spendry 			FIXUP(un);
60067073Spendry 
60166062Spendry 		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
60266062Spendry 		if (error)
60366062Spendry 			return (error);
60467109Spendry 		union_newsize(ap->a_vp, vap->va_size, VNOVAL);
60566062Spendry 	}
60666062Spendry 
60766062Spendry 	if (vp == NULLVP) {
60866062Spendry 		vp = un->un_lowervp;
60966062Spendry 	} else if (vp->v_type == VDIR) {
61066062Spendry 		vp = un->un_lowervp;
61166062Spendry 		vap = &va;
61266062Spendry 	} else {
61366062Spendry 		vp = NULLVP;
61466062Spendry 	}
61566062Spendry 
61666062Spendry 	if (vp != NULLVP) {
61766051Spendry 		VOP_LOCK(vp);
61866062Spendry 		error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
61966051Spendry 		VOP_UNLOCK(vp);
62066062Spendry 		if (error)
62166062Spendry 			return (error);
62267109Spendry 		union_newsize(ap->a_vp, VNOVAL, vap->va_size);
62366062Spendry 	}
62465965Spendry 
62566062Spendry 	if ((vap != ap->a_vap) && (vap->va_type == VDIR))
62666062Spendry 		ap->a_vap->va_nlink += vap->va_nlink;
62766062Spendry 
62867400Spendry 	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
62965935Spendry 	return (0);
63065935Spendry }
63165935Spendry 
63265963Spendry int
63365965Spendry union_setattr(ap)
63465963Spendry 	struct vop_setattr_args /* {
63565963Spendry 		struct vnode *a_vp;
63665963Spendry 		struct vattr *a_vap;
63765963Spendry 		struct ucred *a_cred;
63865963Spendry 		struct proc *a_p;
63965963Spendry 	} */ *ap;
64065963Spendry {
64165963Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
64265963Spendry 	int error;
64365963Spendry 
64466057Spendry 	/*
64566057Spendry 	 * Handle case of truncating lower object to zero size,
64666057Spendry 	 * by creating a zero length upper object.  This is to
64766057Spendry 	 * handle the case of open with O_TRUNC and O_CREAT.
64866057Spendry 	 */
64966057Spendry 	if ((un->un_uppervp == NULLVP) &&
65066057Spendry 	    /* assert(un->un_lowervp != NULLVP) */
65167575Spendry 	    (un->un_lowervp->v_type == VREG)) {
65267575Spendry 		error = union_copyup(un, (ap->a_vap->va_size != 0),
65367575Spendry 						ap->a_cred, ap->a_p);
65466057Spendry 		if (error)
65566057Spendry 			return (error);
65666057Spendry 	}
65766057Spendry 
65866057Spendry 	/*
65966057Spendry 	 * Try to set attributes in upper layer,
66066057Spendry 	 * otherwise return read-only filesystem error.
66166057Spendry 	 */
66266057Spendry 	if (un->un_uppervp != NULLVP) {
66366152Spendry 		FIXUP(un);
66465963Spendry 		error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
66565963Spendry 					ap->a_cred, ap->a_p);
66667109Spendry 		if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
66767109Spendry 			union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
66865963Spendry 	} else {
66965963Spendry 		error = EROFS;
67065963Spendry 	}
67165963Spendry 
67265963Spendry 	return (error);
67365963Spendry }
67465963Spendry 
67565963Spendry int
67665963Spendry union_read(ap)
67765963Spendry 	struct vop_read_args /* {
67865963Spendry 		struct vnode *a_vp;
67965963Spendry 		struct uio *a_uio;
68065963Spendry 		int  a_ioflag;
68165963Spendry 		struct ucred *a_cred;
68265963Spendry 	} */ *ap;
68365963Spendry {
68465963Spendry 	int error;
68565963Spendry 	struct vnode *vp = OTHERVP(ap->a_vp);
68666051Spendry 	int dolock = (vp == LOWERVP(ap->a_vp));
68765963Spendry 
68866051Spendry 	if (dolock)
68966051Spendry 		VOP_LOCK(vp);
69066152Spendry 	else
69166152Spendry 		FIXUP(VTOUNION(ap->a_vp));
69265963Spendry 	error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
69366051Spendry 	if (dolock)
69466051Spendry 		VOP_UNLOCK(vp);
69565963Spendry 
69667109Spendry 	/*
69767109Spendry 	 * XXX
69867109Spendry 	 * perhaps the size of the underlying object has changed under
69967109Spendry 	 * our feet.  take advantage of the offset information present
70067109Spendry 	 * in the uio structure.
70167109Spendry 	 */
70267109Spendry 	if (error == 0) {
70367109Spendry 		struct union_node *un = VTOUNION(ap->a_vp);
70467109Spendry 		off_t cur = ap->a_uio->uio_offset;
70567109Spendry 
70667109Spendry 		if (vp == un->un_uppervp) {
70767109Spendry 			if (cur > un->un_uppersz)
70867109Spendry 				union_newsize(ap->a_vp, cur, VNOVAL);
70967109Spendry 		} else {
71067109Spendry 			if (cur > un->un_lowersz)
71167109Spendry 				union_newsize(ap->a_vp, VNOVAL, cur);
71267109Spendry 		}
71367109Spendry 	}
71467109Spendry 
71565963Spendry 	return (error);
71665963Spendry }
71765963Spendry 
71865963Spendry int
71965963Spendry union_write(ap)
72065963Spendry 	struct vop_read_args /* {
72165963Spendry 		struct vnode *a_vp;
72265963Spendry 		struct uio *a_uio;
72365963Spendry 		int  a_ioflag;
72465963Spendry 		struct ucred *a_cred;
72565963Spendry 	} */ *ap;
72665963Spendry {
72765963Spendry 	int error;
72867575Spendry 	struct vnode *vp;
72967575Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
73065963Spendry 
73167575Spendry 	vp = UPPERVP(ap->a_vp);
73267575Spendry 	if (vp == NULLVP)
73367575Spendry 		panic("union: missing upper layer in write");
73467575Spendry 
73567575Spendry 	FIXUP(un);
73665963Spendry 	error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
73765963Spendry 
73867109Spendry 	/*
73967109Spendry 	 * the size of the underlying object may be changed by the
74067109Spendry 	 * write.
74167109Spendry 	 */
74267109Spendry 	if (error == 0) {
74367109Spendry 		off_t cur = ap->a_uio->uio_offset;
74467109Spendry 
74567575Spendry 		if (cur > un->un_uppersz)
74667575Spendry 			union_newsize(ap->a_vp, cur, VNOVAL);
74767109Spendry 	}
74867109Spendry 
74965963Spendry 	return (error);
75065963Spendry }
75165963Spendry 
752*67751Spendry union_lease(ap)
753*67751Spendry 	struct vop_lease_args /* {
754*67751Spendry 		struct vnode *a_vp;
755*67751Spendry 		struct proc *a_p;
756*67751Spendry 		struct ucred *a_cred;
757*67751Spendry 		int a_flag;
758*67751Spendry 	} */ *ap;
759*67751Spendry {
760*67751Spendry 
761*67751Spendry 	return (VOP_LEASE(OTHERVP(ap->a_vp), ap->a_p, ap->a_cred, ap->a_flag));
762*67751Spendry }
763*67751Spendry 
76465963Spendry int
76565963Spendry union_ioctl(ap)
76665963Spendry 	struct vop_ioctl_args /* {
76765963Spendry 		struct vnode *a_vp;
76865963Spendry 		int  a_command;
76965963Spendry 		caddr_t  a_data;
77065963Spendry 		int  a_fflag;
77165963Spendry 		struct ucred *a_cred;
77265963Spendry 		struct proc *a_p;
77365963Spendry 	} */ *ap;
77465963Spendry {
77565963Spendry 
77665963Spendry 	return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data,
77765963Spendry 				ap->a_fflag, ap->a_cred, ap->a_p));
77865963Spendry }
77965963Spendry 
78065963Spendry int
78165963Spendry union_select(ap)
78265963Spendry 	struct vop_select_args /* {
78365963Spendry 		struct vnode *a_vp;
78465963Spendry 		int  a_which;
78565963Spendry 		int  a_fflags;
78665963Spendry 		struct ucred *a_cred;
78765963Spendry 		struct proc *a_p;
78865963Spendry 	} */ *ap;
78965963Spendry {
79065963Spendry 
79165963Spendry 	return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags,
79265963Spendry 				ap->a_cred, ap->a_p));
79365963Spendry }
79465963Spendry 
79565963Spendry int
79665963Spendry union_mmap(ap)
79765963Spendry 	struct vop_mmap_args /* {
79865963Spendry 		struct vnode *a_vp;
79965963Spendry 		int  a_fflags;
80065963Spendry 		struct ucred *a_cred;
80165963Spendry 		struct proc *a_p;
80265963Spendry 	} */ *ap;
80365963Spendry {
80465963Spendry 
80565963Spendry 	return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags,
80665963Spendry 				ap->a_cred, ap->a_p));
80765963Spendry }
80865963Spendry 
80965963Spendry int
81065963Spendry union_fsync(ap)
81165963Spendry 	struct vop_fsync_args /* {
81265963Spendry 		struct vnode *a_vp;
81365963Spendry 		struct ucred *a_cred;
81465963Spendry 		int  a_waitfor;
81565963Spendry 		struct proc *a_p;
81665963Spendry 	} */ *ap;
81765963Spendry {
81865963Spendry 	int error = 0;
81965963Spendry 	struct vnode *targetvp = OTHERVP(ap->a_vp);
82065963Spendry 
82167076Spendry 	if (targetvp != NULLVP) {
82266051Spendry 		int dolock = (targetvp == LOWERVP(ap->a_vp));
82366051Spendry 
82466051Spendry 		if (dolock)
82566051Spendry 			VOP_LOCK(targetvp);
82666152Spendry 		else
82766152Spendry 			FIXUP(VTOUNION(ap->a_vp));
82865963Spendry 		error = VOP_FSYNC(targetvp, ap->a_cred,
82965963Spendry 					ap->a_waitfor, ap->a_p);
83066051Spendry 		if (dolock)
83166051Spendry 			VOP_UNLOCK(targetvp);
83265963Spendry 	}
83365963Spendry 
83465963Spendry 	return (error);
83565963Spendry }
83665963Spendry 
83765963Spendry int
83865963Spendry union_seek(ap)
83965963Spendry 	struct vop_seek_args /* {
84065963Spendry 		struct vnode *a_vp;
84165963Spendry 		off_t  a_oldoff;
84265963Spendry 		off_t  a_newoff;
84365963Spendry 		struct ucred *a_cred;
84465963Spendry 	} */ *ap;
84565963Spendry {
84665963Spendry 
84765963Spendry 	return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred));
84865963Spendry }
84965963Spendry 
85065963Spendry int
85165963Spendry union_remove(ap)
85265963Spendry 	struct vop_remove_args /* {
85365963Spendry 		struct vnode *a_dvp;
85465963Spendry 		struct vnode *a_vp;
85565963Spendry 		struct componentname *a_cnp;
85665963Spendry 	} */ *ap;
85765963Spendry {
85865963Spendry 	int error;
85965963Spendry 	struct union_node *dun = VTOUNION(ap->a_dvp);
86065963Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
86165963Spendry 
86267575Spendry 	if (dun->un_uppervp == NULLVP)
86367575Spendry 		panic("union remove: null upper vnode");
86467575Spendry 
86567575Spendry 	if (un->un_uppervp != NULLVP) {
86665963Spendry 		struct vnode *dvp = dun->un_uppervp;
86765963Spendry 		struct vnode *vp = un->un_uppervp;
86865963Spendry 
86966152Spendry 		FIXUP(dun);
87065963Spendry 		VREF(dvp);
87166051Spendry 		dun->un_flags |= UN_KLOCK;
87265963Spendry 		vput(ap->a_dvp);
87366152Spendry 		FIXUP(un);
87465963Spendry 		VREF(vp);
87566051Spendry 		un->un_flags |= UN_KLOCK;
87665963Spendry 		vput(ap->a_vp);
87765963Spendry 
87867575Spendry 		if (un->un_lowervp != NULLVP)
87967575Spendry 			ap->a_cnp->cn_flags |= DOWHITEOUT;
88065963Spendry 		error = VOP_REMOVE(dvp, vp, ap->a_cnp);
88166027Spendry 		if (!error)
88266027Spendry 			union_removed_upper(un);
88365963Spendry 	} else {
88467575Spendry 		FIXUP(dun);
88567575Spendry 		error = union_mkwhiteout(
88667575Spendry 			MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
88767575Spendry 			dun->un_uppervp, ap->a_cnp, un->un_path);
88865963Spendry 		vput(ap->a_dvp);
88965963Spendry 		vput(ap->a_vp);
89065963Spendry 	}
89165963Spendry 
89265963Spendry 	return (error);
89365963Spendry }
89465963Spendry 
89565963Spendry int
89665963Spendry union_link(ap)
89765963Spendry 	struct vop_link_args /* {
89865963Spendry 		struct vnode *a_vp;
89965963Spendry 		struct vnode *a_tdvp;
90065963Spendry 		struct componentname *a_cnp;
90165963Spendry 	} */ *ap;
90265963Spendry {
90367169Spendry 	int error = 0;
90467169Spendry 	struct union_node *un;
90567169Spendry 	struct vnode *vp;
90667169Spendry 	struct vnode *tdvp;
90765963Spendry 
90867169Spendry 	un = VTOUNION(ap->a_vp);
90965963Spendry 
91067169Spendry 	if (ap->a_vp->v_op != ap->a_tdvp->v_op) {
91167169Spendry 		tdvp = ap->a_tdvp;
91267169Spendry 	} else {
91367169Spendry 		struct union_node *tdun = VTOUNION(ap->a_tdvp);
91467169Spendry 		if (tdun->un_uppervp == NULLVP) {
91567169Spendry 			VOP_LOCK(ap->a_tdvp);
91667169Spendry 			if (un->un_uppervp == tdun->un_dirvp) {
91767169Spendry 				un->un_flags &= ~UN_ULOCK;
91867169Spendry 				VOP_UNLOCK(un->un_uppervp);
91967169Spendry 			}
92067169Spendry 			error = union_copyup(tdun, 1, ap->a_cnp->cn_cred,
92167169Spendry 						ap->a_cnp->cn_proc);
92267169Spendry 			if (un->un_uppervp == tdun->un_dirvp) {
92367169Spendry 				VOP_LOCK(un->un_uppervp);
92467169Spendry 				un->un_flags |= UN_ULOCK;
92567169Spendry 			}
92667169Spendry 			VOP_UNLOCK(ap->a_tdvp);
92767169Spendry 		}
92867169Spendry 		tdvp = tdun->un_uppervp;
92967169Spendry 	}
93065963Spendry 
93167169Spendry 	vp = un->un_uppervp;
93267169Spendry 	if (vp == NULLVP)
93367169Spendry 		error = EROFS;
93467169Spendry 
93567169Spendry 	if (error) {
93665963Spendry 		vput(ap->a_vp);
93767169Spendry 		return (error);
93865963Spendry 	}
93965963Spendry 
94067169Spendry 	FIXUP(un);
94167169Spendry 	VREF(vp);
94267169Spendry 	un->un_flags |= UN_KLOCK;
94367169Spendry 	vput(ap->a_vp);
94467169Spendry 
94567169Spendry 	return (VOP_LINK(vp, tdvp, ap->a_cnp));
94665963Spendry }
94765963Spendry 
94865963Spendry int
94965963Spendry union_rename(ap)
95065963Spendry 	struct vop_rename_args  /* {
95165963Spendry 		struct vnode *a_fdvp;
95265963Spendry 		struct vnode *a_fvp;
95365963Spendry 		struct componentname *a_fcnp;
95465963Spendry 		struct vnode *a_tdvp;
95565963Spendry 		struct vnode *a_tvp;
95665963Spendry 		struct componentname *a_tcnp;
95765963Spendry 	} */ *ap;
95865963Spendry {
95965963Spendry 	int error;
96065963Spendry 
96165963Spendry 	struct vnode *fdvp = ap->a_fdvp;
96265963Spendry 	struct vnode *fvp = ap->a_fvp;
96365963Spendry 	struct vnode *tdvp = ap->a_tdvp;
96465963Spendry 	struct vnode *tvp = ap->a_tvp;
96565963Spendry 
96665963Spendry 	if (fdvp->v_op == union_vnodeop_p) {	/* always true */
96765963Spendry 		struct union_node *un = VTOUNION(fdvp);
96865997Spendry 		if (un->un_uppervp == NULLVP) {
96967575Spendry 			/*
97067575Spendry 			 * this should never happen in normal
97167575Spendry 			 * operation but might if there was
97267575Spendry 			 * a problem creating the top-level shadow
97367575Spendry 			 * directory.
97467575Spendry 			 */
97567575Spendry 			error = EXDEV;
97665963Spendry 			goto bad;
97765963Spendry 		}
97865963Spendry 
97965963Spendry 		fdvp = un->un_uppervp;
98065963Spendry 		VREF(fdvp);
98165963Spendry 		vrele(ap->a_fdvp);
98265963Spendry 	}
98365963Spendry 
98465963Spendry 	if (fvp->v_op == union_vnodeop_p) {	/* always true */
98565963Spendry 		struct union_node *un = VTOUNION(fvp);
98665997Spendry 		if (un->un_uppervp == NULLVP) {
98767575Spendry 			/* XXX: should do a copyup */
98867575Spendry 			error = EXDEV;
98965963Spendry 			goto bad;
99065963Spendry 		}
99165963Spendry 
99267575Spendry 		if (un->un_lowervp != NULLVP)
99367575Spendry 			ap->a_fcnp->cn_flags |= DOWHITEOUT;
99467575Spendry 
99565963Spendry 		fvp = un->un_uppervp;
99665963Spendry 		VREF(fvp);
99765963Spendry 		vrele(ap->a_fvp);
99865963Spendry 	}
99965963Spendry 
100065963Spendry 	if (tdvp->v_op == union_vnodeop_p) {
100165963Spendry 		struct union_node *un = VTOUNION(tdvp);
100265997Spendry 		if (un->un_uppervp == NULLVP) {
100367076Spendry 			/*
100467076Spendry 			 * this should never happen in normal
100567076Spendry 			 * operation but might if there was
100667076Spendry 			 * a problem creating the top-level shadow
100767076Spendry 			 * directory.
100867076Spendry 			 */
100967575Spendry 			error = EXDEV;
101065963Spendry 			goto bad;
101165963Spendry 		}
101265963Spendry 
101365963Spendry 		tdvp = un->un_uppervp;
101465963Spendry 		VREF(tdvp);
101566051Spendry 		un->un_flags |= UN_KLOCK;
101665997Spendry 		vput(ap->a_tdvp);
101765963Spendry 	}
101865963Spendry 
101967076Spendry 	if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
102065963Spendry 		struct union_node *un = VTOUNION(tvp);
102165963Spendry 
102265963Spendry 		tvp = un->un_uppervp;
102367076Spendry 		if (tvp != NULLVP) {
102467076Spendry 			VREF(tvp);
102567076Spendry 			un->un_flags |= UN_KLOCK;
102667076Spendry 		}
102765963Spendry 		vput(ap->a_tvp);
102865963Spendry 	}
102965963Spendry 
103065963Spendry 	return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
103165963Spendry 
103265963Spendry bad:
103365963Spendry 	vrele(fdvp);
103465963Spendry 	vrele(fvp);
103565963Spendry 	vput(tdvp);
103667076Spendry 	if (tvp != NULLVP)
103765963Spendry 		vput(tvp);
103865963Spendry 
103965963Spendry 	return (error);
104065963Spendry }
104165963Spendry 
104265963Spendry int
104365963Spendry union_mkdir(ap)
104465963Spendry 	struct vop_mkdir_args /* {
104565963Spendry 		struct vnode *a_dvp;
104665963Spendry 		struct vnode **a_vpp;
104765963Spendry 		struct componentname *a_cnp;
104865963Spendry 		struct vattr *a_vap;
104965963Spendry 	} */ *ap;
105065963Spendry {
105165963Spendry 	struct union_node *un = VTOUNION(ap->a_dvp);
105265963Spendry 	struct vnode *dvp = un->un_uppervp;
105365963Spendry 
105467076Spendry 	if (dvp != NULLVP) {
105565963Spendry 		int error;
105665963Spendry 		struct vnode *vp;
105765963Spendry 
105866152Spendry 		FIXUP(un);
105965963Spendry 		VREF(dvp);
106066051Spendry 		un->un_flags |= UN_KLOCK;
106165963Spendry 		vput(ap->a_dvp);
106265963Spendry 		error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap);
106365963Spendry 		if (error)
106465963Spendry 			return (error);
106565963Spendry 
106665963Spendry 		error = union_allocvp(
106765963Spendry 				ap->a_vpp,
106865989Spendry 				ap->a_dvp->v_mount,
106965989Spendry 				ap->a_dvp,
107065965Spendry 				NULLVP,
107165963Spendry 				ap->a_cnp,
107265963Spendry 				vp,
107365963Spendry 				NULLVP);
107465965Spendry 		if (error)
107566051Spendry 			vput(vp);
107665963Spendry 		return (error);
107765963Spendry 	}
107865963Spendry 
107965963Spendry 	vput(ap->a_dvp);
108065963Spendry 	return (EROFS);
108165963Spendry }
108265963Spendry 
108365963Spendry int
108465963Spendry union_rmdir(ap)
108565963Spendry 	struct vop_rmdir_args /* {
108665963Spendry 		struct vnode *a_dvp;
108765963Spendry 		struct vnode *a_vp;
108865963Spendry 		struct componentname *a_cnp;
108965963Spendry 	} */ *ap;
109065963Spendry {
109165963Spendry 	int error;
109265963Spendry 	struct union_node *dun = VTOUNION(ap->a_dvp);
109365963Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
109465963Spendry 
109567575Spendry 	if (dun->un_uppervp == NULLVP)
109667575Spendry 		panic("union rmdir: null upper vnode");
109767575Spendry 
109867575Spendry 	if (un->un_uppervp != NULLVP) {
109965963Spendry 		struct vnode *dvp = dun->un_uppervp;
110065963Spendry 		struct vnode *vp = un->un_uppervp;
110165963Spendry 
110266152Spendry 		FIXUP(dun);
110365963Spendry 		VREF(dvp);
110466051Spendry 		dun->un_flags |= UN_KLOCK;
110565963Spendry 		vput(ap->a_dvp);
110666152Spendry 		FIXUP(un);
110765963Spendry 		VREF(vp);
110866051Spendry 		un->un_flags |= UN_KLOCK;
110965963Spendry 		vput(ap->a_vp);
111065963Spendry 
111167575Spendry 		if (un->un_lowervp != NULLVP)
111267575Spendry 			ap->a_cnp->cn_flags |= DOWHITEOUT;
111366051Spendry 		error = VOP_RMDIR(dvp, vp, ap->a_cnp);
111466027Spendry 		if (!error)
111566027Spendry 			union_removed_upper(un);
111665963Spendry 	} else {
111767575Spendry 		FIXUP(dun);
111867575Spendry 		error = union_mkwhiteout(
111967575Spendry 			MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
112067575Spendry 			dun->un_uppervp, ap->a_cnp, un->un_path);
112165963Spendry 		vput(ap->a_dvp);
112265963Spendry 		vput(ap->a_vp);
112365963Spendry 	}
112465963Spendry 
112565963Spendry 	return (error);
112665963Spendry }
112765963Spendry 
112865963Spendry int
112965963Spendry union_symlink(ap)
113065963Spendry 	struct vop_symlink_args /* {
113165963Spendry 		struct vnode *a_dvp;
113265963Spendry 		struct vnode **a_vpp;
113365963Spendry 		struct componentname *a_cnp;
113465963Spendry 		struct vattr *a_vap;
113565963Spendry 		char *a_target;
113665963Spendry 	} */ *ap;
113765963Spendry {
113865963Spendry 	struct union_node *un = VTOUNION(ap->a_dvp);
113965963Spendry 	struct vnode *dvp = un->un_uppervp;
114065963Spendry 
114167076Spendry 	if (dvp != NULLVP) {
114265963Spendry 		int error;
114365963Spendry 		struct vnode *vp;
114465963Spendry 		struct mount *mp = ap->a_dvp->v_mount;
114565963Spendry 
114666152Spendry 		FIXUP(un);
114765963Spendry 		VREF(dvp);
114866051Spendry 		un->un_flags |= UN_KLOCK;
114965963Spendry 		vput(ap->a_dvp);
115065963Spendry 		error = VOP_SYMLINK(dvp, &vp, ap->a_cnp,
115165963Spendry 					ap->a_vap, ap->a_target);
115265997Spendry 		*ap->a_vpp = NULLVP;
115365963Spendry 		return (error);
115465963Spendry 	}
115565963Spendry 
115665963Spendry 	vput(ap->a_dvp);
115765963Spendry 	return (EROFS);
115865963Spendry }
115965963Spendry 
116065935Spendry /*
116165935Spendry  * union_readdir works in concert with getdirentries and
116265935Spendry  * readdir(3) to provide a list of entries in the unioned
116365935Spendry  * directories.  getdirentries is responsible for walking
116465935Spendry  * down the union stack.  readdir(3) is responsible for
116565935Spendry  * eliminating duplicate names from the returned data stream.
116665935Spendry  */
116765935Spendry int
116865935Spendry union_readdir(ap)
116965935Spendry 	struct vop_readdir_args /* {
117065935Spendry 		struct vnodeop_desc *a_desc;
117165935Spendry 		struct vnode *a_vp;
117265935Spendry 		struct uio *a_uio;
117365935Spendry 		struct ucred *a_cred;
117467369Smckusick 		int *a_eofflag;
117567369Smckusick 		u_long *a_cookies;
117667369Smckusick 		int a_ncookies;
117765935Spendry 	} */ *ap;
117865935Spendry {
117967369Smckusick 	register struct union_node *un = VTOUNION(ap->a_vp);
118067369Smckusick 	register struct vnode *uvp = un->un_uppervp;
118165935Spendry 
118267369Smckusick 	if (uvp == NULLVP)
118367369Smckusick 		return (0);
118465935Spendry 
118567369Smckusick 	FIXUP(un);
118667369Smckusick 	ap->a_vp = uvp;
118767369Smckusick 	return (VOCALL(uvp->v_op, VOFFSET(vop_readdir), ap));
118865935Spendry }
118965935Spendry 
119065935Spendry int
119165963Spendry union_readlink(ap)
119265963Spendry 	struct vop_readlink_args /* {
119365963Spendry 		struct vnode *a_vp;
119465963Spendry 		struct uio *a_uio;
119565963Spendry 		struct ucred *a_cred;
119665963Spendry 	} */ *ap;
119765963Spendry {
119865963Spendry 	int error;
119965963Spendry 	struct vnode *vp = OTHERVP(ap->a_vp);
120066051Spendry 	int dolock = (vp == LOWERVP(ap->a_vp));
120165963Spendry 
120266051Spendry 	if (dolock)
120366051Spendry 		VOP_LOCK(vp);
120466152Spendry 	else
120566152Spendry 		FIXUP(VTOUNION(ap->a_vp));
120665963Spendry 	error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
120766051Spendry 	if (dolock)
120866051Spendry 		VOP_UNLOCK(vp);
120965963Spendry 
121065963Spendry 	return (error);
121165963Spendry }
121265963Spendry 
121365963Spendry int
121465963Spendry union_abortop(ap)
121565963Spendry 	struct vop_abortop_args /* {
121665963Spendry 		struct vnode *a_dvp;
121765963Spendry 		struct componentname *a_cnp;
121865963Spendry 	} */ *ap;
121965963Spendry {
122065963Spendry 	int error;
122165965Spendry 	struct vnode *vp = OTHERVP(ap->a_dvp);
122265963Spendry 	struct union_node *un = VTOUNION(ap->a_dvp);
122365963Spendry 	int islocked = un->un_flags & UN_LOCKED;
122466051Spendry 	int dolock = (vp == LOWERVP(ap->a_dvp));
122565963Spendry 
122666152Spendry 	if (islocked) {
122766152Spendry 		if (dolock)
122866152Spendry 			VOP_LOCK(vp);
122966152Spendry 		else
123066152Spendry 			FIXUP(VTOUNION(ap->a_dvp));
123166152Spendry 	}
123265963Spendry 	error = VOP_ABORTOP(vp, ap->a_cnp);
123366051Spendry 	if (islocked && dolock)
123465963Spendry 		VOP_UNLOCK(vp);
123565963Spendry 
123665963Spendry 	return (error);
123765963Spendry }
123865963Spendry 
123965963Spendry int
124065935Spendry union_inactive(ap)
124165935Spendry 	struct vop_inactive_args /* {
124265935Spendry 		struct vnode *a_vp;
124365935Spendry 	} */ *ap;
124465935Spendry {
124567073Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
124665935Spendry 
124765935Spendry 	/*
124865935Spendry 	 * Do nothing (and _don't_ bypass).
124965935Spendry 	 * Wait to vrele lowervp until reclaim,
125065935Spendry 	 * so that until then our union_node is in the
125165935Spendry 	 * cache and reusable.
125265935Spendry 	 *
125365935Spendry 	 * NEEDSWORK: Someday, consider inactive'ing
125465935Spendry 	 * the lowervp and then trying to reactivate it
125565935Spendry 	 * with capabilities (v_id)
125665935Spendry 	 * like they do in the name lookup cache code.
125765935Spendry 	 * That's too much work for now.
125865935Spendry 	 */
125965989Spendry 
126066027Spendry #ifdef UNION_DIAGNOSTIC
126165989Spendry 	if (un->un_flags & UN_LOCKED)
126265989Spendry 		panic("union: inactivating locked node");
126367073Spendry 	if (un->un_flags & UN_ULOCK)
126467073Spendry 		panic("union: inactivating w/locked upper node");
126565989Spendry #endif
126665989Spendry 
126767073Spendry 	if ((un->un_flags & UN_CACHED) == 0)
126867073Spendry 		vgone(ap->a_vp);
126967073Spendry 
127065935Spendry 	return (0);
127165935Spendry }
127265935Spendry 
127365935Spendry int
127465935Spendry union_reclaim(ap)
127565935Spendry 	struct vop_reclaim_args /* {
127665935Spendry 		struct vnode *a_vp;
127765935Spendry 	} */ *ap;
127865935Spendry {
127965935Spendry 
128066053Spendry 	union_freevp(ap->a_vp);
128166053Spendry 
128265935Spendry 	return (0);
128365935Spendry }
128465935Spendry 
128565963Spendry int
128665963Spendry union_lock(ap)
128765963Spendry 	struct vop_lock_args *ap;
128865963Spendry {
128966149Spendry 	struct vnode *vp = ap->a_vp;
129066149Spendry 	struct union_node *un;
129165935Spendry 
129266149Spendry start:
129366149Spendry 	while (vp->v_flag & VXLOCK) {
129466149Spendry 		vp->v_flag |= VXWANT;
129566149Spendry 		sleep((caddr_t)vp, PINOD);
129666149Spendry 	}
129766149Spendry 
129866149Spendry 	un = VTOUNION(vp);
129966149Spendry 
130067076Spendry 	if (un->un_uppervp != NULLVP) {
130167230Spendry 		if (((un->un_flags & UN_ULOCK) == 0) &&
130267230Spendry 		    (vp->v_usecount != 0)) {
130366149Spendry 			un->un_flags |= UN_ULOCK;
130466051Spendry 			VOP_LOCK(un->un_uppervp);
130566051Spendry 		}
130666051Spendry #ifdef DIAGNOSTIC
130766051Spendry 		if (un->un_flags & UN_KLOCK)
130866051Spendry 			panic("union: dangling upper lock");
130966051Spendry #endif
131066051Spendry 	}
131166051Spendry 
131266149Spendry 	if (un->un_flags & UN_LOCKED) {
131365963Spendry #ifdef DIAGNOSTIC
131465989Spendry 		if (curproc && un->un_pid == curproc->p_pid &&
131565989Spendry 			    un->un_pid > -1 && curproc->p_pid > -1)
131665989Spendry 			panic("union: locking against myself");
131765963Spendry #endif
131865963Spendry 		un->un_flags |= UN_WANT;
131965963Spendry 		sleep((caddr_t) &un->un_flags, PINOD);
132066149Spendry 		goto start;
132165963Spendry 	}
132265989Spendry 
132365963Spendry #ifdef DIAGNOSTIC
132465989Spendry 	if (curproc)
132565989Spendry 		un->un_pid = curproc->p_pid;
132665989Spendry 	else
132765989Spendry 		un->un_pid = -1;
132865963Spendry #endif
132966028Spendry 
133066149Spendry 	un->un_flags |= UN_LOCKED;
133166028Spendry 	return (0);
133265963Spendry }
133365963Spendry 
133465935Spendry int
133565963Spendry union_unlock(ap)
133665963Spendry 	struct vop_lock_args *ap;
133765963Spendry {
133865963Spendry 	struct union_node *un = VTOUNION(ap->a_vp);
133965963Spendry 
134065963Spendry #ifdef DIAGNOSTIC
134165965Spendry 	if ((un->un_flags & UN_LOCKED) == 0)
134265965Spendry 		panic("union: unlock unlocked node");
134365989Spendry 	if (curproc && un->un_pid != curproc->p_pid &&
134465989Spendry 			curproc->p_pid > -1 && un->un_pid > -1)
134565963Spendry 		panic("union: unlocking other process's union node");
134665963Spendry #endif
134765963Spendry 
134865963Spendry 	un->un_flags &= ~UN_LOCKED;
134966051Spendry 
135066051Spendry 	if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK)
135166051Spendry 		VOP_UNLOCK(un->un_uppervp);
135266051Spendry 
135366051Spendry 	un->un_flags &= ~(UN_ULOCK|UN_KLOCK);
135466051Spendry 
135565963Spendry 	if (un->un_flags & UN_WANT) {
135665963Spendry 		un->un_flags &= ~UN_WANT;
135765963Spendry 		wakeup((caddr_t) &un->un_flags);
135865963Spendry 	}
135965963Spendry 
136065963Spendry #ifdef DIAGNOSTIC
136165963Spendry 	un->un_pid = 0;
136265963Spendry #endif
136366028Spendry 
136466028Spendry 	return (0);
136565963Spendry }
136665963Spendry 
136765963Spendry int
136865963Spendry union_bmap(ap)
136965963Spendry 	struct vop_bmap_args /* {
137065963Spendry 		struct vnode *a_vp;
137165963Spendry 		daddr_t  a_bn;
137265963Spendry 		struct vnode **a_vpp;
137365963Spendry 		daddr_t *a_bnp;
137465963Spendry 		int *a_runp;
137565963Spendry 	} */ *ap;
137665963Spendry {
137765963Spendry 	int error;
137865963Spendry 	struct vnode *vp = OTHERVP(ap->a_vp);
137966051Spendry 	int dolock = (vp == LOWERVP(ap->a_vp));
138065963Spendry 
138166051Spendry 	if (dolock)
138266051Spendry 		VOP_LOCK(vp);
138366152Spendry 	else
138466152Spendry 		FIXUP(VTOUNION(ap->a_vp));
138565963Spendry 	error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp);
138666051Spendry 	if (dolock)
138766051Spendry 		VOP_UNLOCK(vp);
138865963Spendry 
138965963Spendry 	return (error);
139065963Spendry }
139165963Spendry 
139265963Spendry int
139365935Spendry union_print(ap)
139465935Spendry 	struct vop_print_args /* {
139565935Spendry 		struct vnode *a_vp;
139665935Spendry 	} */ *ap;
139765935Spendry {
139865935Spendry 	struct vnode *vp = ap->a_vp;
139965935Spendry 
140065935Spendry 	printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n",
140165935Spendry 			vp, UPPERVP(vp), LOWERVP(vp));
140265935Spendry 	return (0);
140365935Spendry }
140465935Spendry 
140565963Spendry int
140665963Spendry union_islocked(ap)
140765963Spendry 	struct vop_islocked_args /* {
140865963Spendry 		struct vnode *a_vp;
140965963Spendry 	} */ *ap;
141065963Spendry {
141165935Spendry 
141265963Spendry 	return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0);
141365963Spendry }
141465963Spendry 
141565935Spendry int
141665963Spendry union_pathconf(ap)
141765963Spendry 	struct vop_pathconf_args /* {
141865963Spendry 		struct vnode *a_vp;
141965963Spendry 		int a_name;
142065963Spendry 		int *a_retval;
142165935Spendry 	} */ *ap;
142265935Spendry {
142365935Spendry 	int error;
142465963Spendry 	struct vnode *vp = OTHERVP(ap->a_vp);
142566051Spendry 	int dolock = (vp == LOWERVP(ap->a_vp));
142665935Spendry 
142766051Spendry 	if (dolock)
142866051Spendry 		VOP_LOCK(vp);
142966152Spendry 	else
143066152Spendry 		FIXUP(VTOUNION(ap->a_vp));
143165963Spendry 	error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval);
143266051Spendry 	if (dolock)
143366051Spendry 		VOP_UNLOCK(vp);
143465935Spendry 
143565963Spendry 	return (error);
143665963Spendry }
143765935Spendry 
143865963Spendry int
143965963Spendry union_advlock(ap)
144065963Spendry 	struct vop_advlock_args /* {
144165963Spendry 		struct vnode *a_vp;
144265963Spendry 		caddr_t  a_id;
144365963Spendry 		int  a_op;
144465963Spendry 		struct flock *a_fl;
144565963Spendry 		int  a_flags;
144665963Spendry 	} */ *ap;
144765963Spendry {
144865935Spendry 
144965963Spendry 	return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op,
145065963Spendry 				ap->a_fl, ap->a_flags));
145165935Spendry }
145265935Spendry 
145365935Spendry 
145465935Spendry /*
145565963Spendry  * XXX - vop_strategy must be hand coded because it has no
145665935Spendry  * vnode in its arguments.
145765935Spendry  * This goes away with a merged VM/buffer cache.
145865935Spendry  */
145965935Spendry int
146065963Spendry union_strategy(ap)
146165963Spendry 	struct vop_strategy_args /* {
146265935Spendry 		struct buf *a_bp;
146365935Spendry 	} */ *ap;
146465935Spendry {
146565935Spendry 	struct buf *bp = ap->a_bp;
146665935Spendry 	int error;
146765935Spendry 	struct vnode *savedvp;
146865935Spendry 
146965935Spendry 	savedvp = bp->b_vp;
147065963Spendry 	bp->b_vp = OTHERVP(bp->b_vp);
147165935Spendry 
147265935Spendry #ifdef DIAGNOSTIC
147365997Spendry 	if (bp->b_vp == NULLVP)
147465963Spendry 		panic("union_strategy: nil vp");
147565963Spendry 	if (((bp->b_flags & B_READ) == 0) &&
147665963Spendry 	    (bp->b_vp == LOWERVP(savedvp)))
147765963Spendry 		panic("union_strategy: writing to lowervp");
147865935Spendry #endif
147965935Spendry 
148065963Spendry 	error = VOP_STRATEGY(bp);
148165935Spendry 	bp->b_vp = savedvp;
148265935Spendry 
148365935Spendry 	return (error);
148465935Spendry }
148565935Spendry 
148665935Spendry /*
148765935Spendry  * Global vfs data structures
148865935Spendry  */
148965935Spendry int (**union_vnodeop_p)();
149065965Spendry struct vnodeopv_entry_desc union_vnodeop_entries[] = {
149165963Spendry 	{ &vop_default_desc, vn_default_error },
149265963Spendry 	{ &vop_lookup_desc, union_lookup },		/* lookup */
149365963Spendry 	{ &vop_create_desc, union_create },		/* create */
149467575Spendry 	{ &vop_whiteout_desc, union_whiteout },		/* whiteout */
149565963Spendry 	{ &vop_mknod_desc, union_mknod },		/* mknod */
149665963Spendry 	{ &vop_open_desc, union_open },			/* open */
149765963Spendry 	{ &vop_close_desc, union_close },		/* close */
149865963Spendry 	{ &vop_access_desc, union_access },		/* access */
149965963Spendry 	{ &vop_getattr_desc, union_getattr },		/* getattr */
150065963Spendry 	{ &vop_setattr_desc, union_setattr },		/* setattr */
150165963Spendry 	{ &vop_read_desc, union_read },			/* read */
150265963Spendry 	{ &vop_write_desc, union_write },		/* write */
1503*67751Spendry 	{ &vop_lease_desc, union_lease },		/* lease */
150465963Spendry 	{ &vop_ioctl_desc, union_ioctl },		/* ioctl */
150565963Spendry 	{ &vop_select_desc, union_select },		/* select */
150665963Spendry 	{ &vop_mmap_desc, union_mmap },			/* mmap */
150765963Spendry 	{ &vop_fsync_desc, union_fsync },		/* fsync */
150865963Spendry 	{ &vop_seek_desc, union_seek },			/* seek */
150965963Spendry 	{ &vop_remove_desc, union_remove },		/* remove */
151065963Spendry 	{ &vop_link_desc, union_link },			/* link */
151165963Spendry 	{ &vop_rename_desc, union_rename },		/* rename */
151265963Spendry 	{ &vop_mkdir_desc, union_mkdir },		/* mkdir */
151365963Spendry 	{ &vop_rmdir_desc, union_rmdir },		/* rmdir */
151465963Spendry 	{ &vop_symlink_desc, union_symlink },		/* symlink */
151565963Spendry 	{ &vop_readdir_desc, union_readdir },		/* readdir */
151665963Spendry 	{ &vop_readlink_desc, union_readlink },		/* readlink */
151765963Spendry 	{ &vop_abortop_desc, union_abortop },		/* abortop */
151865963Spendry 	{ &vop_inactive_desc, union_inactive },		/* inactive */
151965963Spendry 	{ &vop_reclaim_desc, union_reclaim },		/* reclaim */
152065963Spendry 	{ &vop_lock_desc, union_lock },			/* lock */
152165963Spendry 	{ &vop_unlock_desc, union_unlock },		/* unlock */
152265963Spendry 	{ &vop_bmap_desc, union_bmap },			/* bmap */
152365963Spendry 	{ &vop_strategy_desc, union_strategy },		/* strategy */
152465963Spendry 	{ &vop_print_desc, union_print },		/* print */
152565963Spendry 	{ &vop_islocked_desc, union_islocked },		/* islocked */
152665963Spendry 	{ &vop_pathconf_desc, union_pathconf },		/* pathconf */
152765963Spendry 	{ &vop_advlock_desc, union_advlock },		/* advlock */
152865963Spendry #ifdef notdef
152965963Spendry 	{ &vop_blkatoff_desc, union_blkatoff },		/* blkatoff */
153065963Spendry 	{ &vop_valloc_desc, union_valloc },		/* valloc */
153165963Spendry 	{ &vop_vfree_desc, union_vfree },		/* vfree */
153265963Spendry 	{ &vop_truncate_desc, union_truncate },		/* truncate */
153365963Spendry 	{ &vop_update_desc, union_update },		/* update */
153465963Spendry 	{ &vop_bwrite_desc, union_bwrite },		/* bwrite */
153565963Spendry #endif
153665935Spendry 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
153765935Spendry };
153865935Spendry struct vnodeopv_desc union_vnodeop_opv_desc =
153965935Spendry 	{ &union_vnodeop_p, union_vnodeop_entries };
1540