xref: /csrg-svn/sys/miscfs/union/union_subr.c (revision 66051)
165934Spendry /*
265934Spendry  * Copyright (c) 1994 Jan-Simon Pendry
365934Spendry  * Copyright (c) 1994
465934Spendry  *	The Regents of the University of California.  All rights reserved.
565934Spendry  *
665934Spendry  * This code is derived from software contributed to Berkeley by
765934Spendry  * Jan-Simon Pendry.
865934Spendry  *
965934Spendry  * %sccs.include.redist.c%
1065934Spendry  *
11*66051Spendry  *	@(#)union_subr.c	2.1 (Berkeley) 02/10/94
1265934Spendry  */
1365934Spendry 
1465934Spendry #include <sys/param.h>
1565934Spendry #include <sys/systm.h>
1665934Spendry #include <sys/time.h>
1765934Spendry #include <sys/kernel.h>
1865934Spendry #include <sys/vnode.h>
1965934Spendry #include <sys/namei.h>
2065934Spendry #include <sys/malloc.h>
2165994Spendry #include <sys/file.h>
2265997Spendry #include <sys/filedesc.h>
2365934Spendry #include "union.h" /*<miscfs/union/union.h>*/
2465934Spendry 
2565992Spendry #ifdef DIAGNOSTIC
2665992Spendry #include <sys/proc.h>
2765992Spendry #endif
2865992Spendry 
2965934Spendry static struct union_node *unhead;
3065934Spendry static int unvplock;
3165934Spendry 
3265934Spendry int
3365934Spendry union_init()
3465934Spendry {
3565934Spendry 
3665934Spendry 	unhead = 0;
3765934Spendry 	unvplock = 0;
3865934Spendry }
3965934Spendry 
40*66051Spendry static void
41*66051Spendry union_remlist(un)
42*66051Spendry 	struct union_node *un;
43*66051Spendry {
44*66051Spendry 	struct union_node **unpp;
45*66051Spendry 
46*66051Spendry 	for (unpp = &unhead; *unpp != 0; unpp = &(*unpp)->un_next) {
47*66051Spendry 		if (*unpp == un) {
48*66051Spendry 			*unpp = un->un_next;
49*66051Spendry 			break;
50*66051Spendry 		}
51*66051Spendry 	}
52*66051Spendry }
53*66051Spendry 
5465934Spendry /*
5565934Spendry  * allocate a union_node/vnode pair.  the vnode is
5665965Spendry  * referenced and locked.  the new vnode is returned
5765965Spendry  * via (vpp).  (mp) is the mountpoint of the union filesystem,
5865965Spendry  * (dvp) is the parent directory where the upper layer object
5965965Spendry  * should exist (but doesn't) and (cnp) is the componentname
6065965Spendry  * information which is partially copied to allow the upper
6165965Spendry  * layer object to be created at a later time.  (uppervp)
6265965Spendry  * and (lowervp) reference the upper and lower layer objects
6365965Spendry  * being mapped.  either, but not both, can be nil.
64*66051Spendry  * if supplied, (uppervp) is locked.
6565997Spendry  * the reference is either maintained in the new union_node
6665997Spendry  * object which is allocated, or they are vrele'd.
6765934Spendry  *
6865934Spendry  * all union_nodes are maintained on a singly-linked
6965934Spendry  * list.  new nodes are only allocated when they cannot
7065934Spendry  * be found on this list.  entries on the list are
7165934Spendry  * removed when the vfs reclaim entry is called.
7265934Spendry  *
7365934Spendry  * a single lock is kept for the entire list.  this is
7465934Spendry  * needed because the getnewvnode() function can block
7565934Spendry  * waiting for a vnode to become free, in which case there
7665934Spendry  * may be more than one process trying to get the same
7765934Spendry  * vnode.  this lock is only taken if we are going to
7865934Spendry  * call getnewvnode, since the kernel itself is single-threaded.
7965934Spendry  *
8065934Spendry  * if an entry is found on the list, then call vget() to
8165934Spendry  * take a reference.  this is done because there may be
8265934Spendry  * zero references to it and so it needs to removed from
8365934Spendry  * the vnode free list.
8465934Spendry  */
8565934Spendry int
8665992Spendry union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
8765934Spendry 	struct vnode **vpp;
8865934Spendry 	struct mount *mp;
8965992Spendry 	struct vnode *undvp;
9065934Spendry 	struct vnode *dvp;		/* may be null */
9165934Spendry 	struct componentname *cnp;	/* may be null */
9265934Spendry 	struct vnode *uppervp;		/* may be null */
9365934Spendry 	struct vnode *lowervp;		/* may be null */
9465934Spendry {
9565934Spendry 	int error;
9665934Spendry 	struct union_node *un;
9765934Spendry 	struct union_node **pp;
9865965Spendry 	struct vnode *xlowervp = 0;
9965934Spendry 
10065965Spendry 	if (uppervp == 0 && lowervp == 0)
10165965Spendry 		panic("union: unidentifiable allocation");
10265965Spendry 
10365965Spendry 	if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) {
10465965Spendry 		xlowervp = lowervp;
10565965Spendry 		lowervp = 0;
10665965Spendry 	}
10765965Spendry 
10865934Spendry loop:
10965934Spendry 	for (un = unhead; un != 0; un = un->un_next) {
11065934Spendry 		if ((un->un_lowervp == lowervp ||
11165934Spendry 		     un->un_lowervp == 0) &&
11265934Spendry 		    (un->un_uppervp == uppervp ||
11365934Spendry 		     un->un_uppervp == 0) &&
11465934Spendry 		    (UNIONTOV(un)->v_mount == mp)) {
11565992Spendry 			if (vget(UNIONTOV(un), 0))
11665934Spendry 				goto loop;
117*66051Spendry 			break;
118*66051Spendry 		}
119*66051Spendry 	}
12066027Spendry 
121*66051Spendry 	if (un) {
122*66051Spendry 		/*
123*66051Spendry 		 * Obtain a lock on the union_node.
124*66051Spendry 		 * uppervp is locked, though un->un_uppervp
125*66051Spendry 		 * may not be.  this doesn't break the locking
126*66051Spendry 		 * hierarchy since in the case that un->un_uppervp
127*66051Spendry 		 * is not yet locked it will be vrele'd and replaced
128*66051Spendry 		 * with uppervp.
129*66051Spendry 		 */
130*66051Spendry 
131*66051Spendry 		if ((dvp != NULLVP) && (uppervp == dvp)) {
13266027Spendry 			/*
133*66051Spendry 			 * Access ``.'', so (un) will already
134*66051Spendry 			 * be locked.  Since this process has
135*66051Spendry 			 * the lock on (uppervp) no other
136*66051Spendry 			 * process can hold the lock on (un).
13766027Spendry 			 */
138*66051Spendry #ifdef DIAGNOSTIC
139*66051Spendry 			if ((un->un_flags & UN_LOCKED) == 0)
140*66051Spendry 				panic("union: . not locked");
141*66051Spendry 			else if (curproc && un->un_pid != curproc->p_pid &&
142*66051Spendry 				    un->un_pid > -1 && curproc->p_pid > -1)
143*66051Spendry 				panic("union: allocvp not lock owner");
144*66051Spendry #endif
145*66051Spendry 		} else {
146*66051Spendry 			if (un->un_flags & UN_LOCKED) {
147*66051Spendry 				vrele(UNIONTOV(un));
148*66051Spendry 				un->un_flags |= UN_WANT;
149*66051Spendry 				sleep((caddr_t) &un->un_flags, PINOD);
150*66051Spendry 				goto loop;
15165992Spendry 			}
152*66051Spendry 			un->un_flags |= UN_LOCKED;
15366027Spendry 
154*66051Spendry #ifdef DIAGNOSTIC
155*66051Spendry 			if (curproc)
156*66051Spendry 				un->un_pid = curproc->p_pid;
157*66051Spendry 			else
158*66051Spendry 				un->un_pid = -1;
159*66051Spendry #endif
160*66051Spendry 		}
161*66051Spendry 
162*66051Spendry 		/*
163*66051Spendry 		 * At this point, the union_node is locked,
164*66051Spendry 		 * un->un_uppervp may not be locked, and uppervp
165*66051Spendry 		 * is locked or nil.
166*66051Spendry 		 */
167*66051Spendry 
168*66051Spendry 		/*
169*66051Spendry 		 * Save information about the upper layer.
170*66051Spendry 		 */
171*66051Spendry 		if (uppervp != un->un_uppervp) {
172*66051Spendry 			if (un->un_uppervp)
173*66051Spendry 				vrele(un->un_uppervp);
174*66051Spendry 			un->un_uppervp = uppervp;
175*66051Spendry 		} else if (uppervp) {
176*66051Spendry 			vrele(uppervp);
177*66051Spendry 		}
178*66051Spendry 
179*66051Spendry 		if (un->un_uppervp) {
180*66051Spendry 			un->un_flags |= UN_ULOCK;
181*66051Spendry 			un->un_flags &= ~UN_KLOCK;
182*66051Spendry 		}
183*66051Spendry 
184*66051Spendry 		/*
185*66051Spendry 		 * Save information about the lower layer.
186*66051Spendry 		 * This needs to keep track of pathname
187*66051Spendry 		 * and directory information which union_vn_create
188*66051Spendry 		 * might need.
189*66051Spendry 		 */
190*66051Spendry 		if (lowervp != un->un_lowervp) {
191*66051Spendry 			if (un->un_lowervp) {
192*66051Spendry 				vrele(un->un_lowervp);
193*66051Spendry 				free(un->un_path, M_TEMP);
194*66051Spendry 				vrele(un->un_dirvp);
19565992Spendry 			}
196*66051Spendry 			un->un_lowervp = lowervp;
197*66051Spendry 			if (cnp && (lowervp != NULLVP) &&
198*66051Spendry 			    (lowervp->v_type == VREG)) {
199*66051Spendry 				un->un_hash = cnp->cn_hash;
200*66051Spendry 				un->un_path = malloc(cnp->cn_namelen+1,
201*66051Spendry 						M_TEMP, M_WAITOK);
202*66051Spendry 				bcopy(cnp->cn_nameptr, un->un_path,
203*66051Spendry 						cnp->cn_namelen);
204*66051Spendry 				un->un_path[cnp->cn_namelen] = '\0';
205*66051Spendry 				VREF(dvp);
206*66051Spendry 				un->un_dirvp = dvp;
207*66051Spendry 			}
208*66051Spendry 		} else if (lowervp) {
209*66051Spendry 			vrele(lowervp);
21065934Spendry 		}
211*66051Spendry 		*vpp = UNIONTOV(un);
212*66051Spendry 		return (0);
21365934Spendry 	}
21465934Spendry 
21565934Spendry 	/*
21665934Spendry 	 * otherwise lock the vp list while we call getnewvnode
21765934Spendry 	 * since that can block.
21865934Spendry 	 */
21965934Spendry 	if (unvplock & UN_LOCKED) {
22065934Spendry 		unvplock |= UN_WANT;
22165934Spendry 		sleep((caddr_t) &unvplock, PINOD);
22265934Spendry 		goto loop;
22365934Spendry 	}
22465934Spendry 	unvplock |= UN_LOCKED;
22565934Spendry 
22665934Spendry 	error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp);
227*66051Spendry 	if (error) {
228*66051Spendry 		if (uppervp) {
229*66051Spendry 			if (dvp == uppervp)
230*66051Spendry 				vrele(uppervp);
231*66051Spendry 			else
232*66051Spendry 				vput(uppervp);
233*66051Spendry 		}
234*66051Spendry 		if (lowervp)
235*66051Spendry 			vrele(lowervp);
236*66051Spendry 
23765934Spendry 		goto out;
238*66051Spendry 	}
23965934Spendry 
24065934Spendry 	MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),
24165934Spendry 		M_TEMP, M_WAITOK);
24265934Spendry 
24365965Spendry 	if (uppervp)
24465965Spendry 		(*vpp)->v_type = uppervp->v_type;
24565965Spendry 	else
24665965Spendry 		(*vpp)->v_type = lowervp->v_type;
24765934Spendry 	un = VTOUNION(*vpp);
24865992Spendry 	un->un_vnode = *vpp;
24965934Spendry 	un->un_next = 0;
25065934Spendry 	un->un_uppervp = uppervp;
25165934Spendry 	un->un_lowervp = lowervp;
25266028Spendry 	un->un_openl = 0;
253*66051Spendry 	un->un_flags = UN_LOCKED;
254*66051Spendry 	if (un->un_uppervp)
255*66051Spendry 		un->un_flags |= UN_ULOCK;
256*66051Spendry #ifdef DIAGNOSTIC
257*66051Spendry 	if (curproc)
258*66051Spendry 		un->un_pid = curproc->p_pid;
259*66051Spendry 	else
260*66051Spendry 		un->un_pid = -1;
261*66051Spendry #endif
26266027Spendry 	if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) {
26366027Spendry 		un->un_hash = cnp->cn_hash;
26465934Spendry 		un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
26565934Spendry 		bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
26665934Spendry 		un->un_path[cnp->cn_namelen] = '\0';
26765965Spendry 		VREF(dvp);
26865965Spendry 		un->un_dirvp = dvp;
26965934Spendry 	} else {
27066027Spendry 		un->un_hash = 0;
27165934Spendry 		un->un_path = 0;
27265965Spendry 		un->un_dirvp = 0;
27365934Spendry 	}
27465934Spendry 
27565934Spendry 	/* add to union vnode list */
27665934Spendry 	for (pp = &unhead; *pp; pp = &(*pp)->un_next)
27765934Spendry 		continue;
27865934Spendry 	*pp = un;
27965934Spendry 
28065965Spendry 	if (xlowervp)
28165965Spendry 		vrele(xlowervp);
28265965Spendry 
28365934Spendry out:
28465934Spendry 	unvplock &= ~UN_LOCKED;
28565934Spendry 
28665934Spendry 	if (unvplock & UN_WANT) {
28765934Spendry 		unvplock &= ~UN_WANT;
28865934Spendry 		wakeup((caddr_t) &unvplock);
28965934Spendry 	}
29065934Spendry 
29165934Spendry 	return (error);
29265934Spendry }
29365934Spendry 
29465934Spendry int
29565934Spendry union_freevp(vp)
29665934Spendry 	struct vnode *vp;
29765934Spendry {
29865934Spendry 	struct union_node *un = VTOUNION(vp);
29965934Spendry 
300*66051Spendry 	union_remlist(un);
30165934Spendry 
30265934Spendry 	FREE(vp->v_data, M_TEMP);
30365934Spendry 	vp->v_data = 0;
30465934Spendry 	return (0);
30565934Spendry }
30665994Spendry 
30765994Spendry /*
30865994Spendry  * copyfile.  copy the vnode (fvp) to the vnode (tvp)
30965994Spendry  * using a sequence of reads and writes.  both (fvp)
31065994Spendry  * and (tvp) are locked on entry and exit.
31165994Spendry  */
31265994Spendry int
31365994Spendry union_copyfile(p, cred, fvp, tvp)
31465994Spendry 	struct proc *p;
31565994Spendry 	struct ucred *cred;
31665994Spendry 	struct vnode *fvp;
31765994Spendry 	struct vnode *tvp;
31865994Spendry {
31965994Spendry 	char *buf;
32065994Spendry 	struct uio uio;
32165994Spendry 	struct iovec iov;
32265994Spendry 	int error = 0;
32365994Spendry 
32465994Spendry 	/*
32565994Spendry 	 * strategy:
32665994Spendry 	 * allocate a buffer of size MAXBSIZE.
32765994Spendry 	 * loop doing reads and writes, keeping track
32865994Spendry 	 * of the current uio offset.
32965994Spendry 	 * give up at the first sign of trouble.
33065994Spendry 	 */
33165994Spendry 
33265994Spendry 	uio.uio_procp = p;
33365994Spendry 	uio.uio_segflg = UIO_SYSSPACE;
33465994Spendry 	uio.uio_offset = 0;
33565994Spendry 
33665994Spendry 	VOP_UNLOCK(fvp);				/* XXX */
33765994Spendry 	LEASE_CHECK(fvp, p, cred, LEASE_READ);
33865994Spendry 	VOP_LOCK(fvp);					/* XXX */
33965994Spendry 	VOP_UNLOCK(tvp);				/* XXX */
34065994Spendry 	LEASE_CHECK(tvp, p, cred, LEASE_WRITE);
34165994Spendry 	VOP_LOCK(tvp);					/* XXX */
34265994Spendry 
34365994Spendry 	buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
34465994Spendry 
34565994Spendry 	/* ugly loop follows... */
34665994Spendry 	do {
34765994Spendry 		off_t offset = uio.uio_offset;
34865994Spendry 
34965994Spendry 		uio.uio_iov = &iov;
35065994Spendry 		uio.uio_iovcnt = 1;
35165994Spendry 		iov.iov_base = buf;
35265994Spendry 		iov.iov_len = MAXBSIZE;
35365994Spendry 		uio.uio_resid = iov.iov_len;
35465994Spendry 		uio.uio_rw = UIO_READ;
35565994Spendry 		error = VOP_READ(fvp, &uio, 0, cred);
35665994Spendry 
35765994Spendry 		if (error == 0) {
35865994Spendry 			uio.uio_iov = &iov;
35965994Spendry 			uio.uio_iovcnt = 1;
36065994Spendry 			iov.iov_base = buf;
36165994Spendry 			iov.iov_len = MAXBSIZE - uio.uio_resid;
36265994Spendry 			uio.uio_offset = offset;
36365994Spendry 			uio.uio_rw = UIO_WRITE;
36465994Spendry 			uio.uio_resid = iov.iov_len;
36565994Spendry 
36665994Spendry 			if (uio.uio_resid == 0)
36765994Spendry 				break;
36865994Spendry 
36965994Spendry 			do {
37065994Spendry 				error = VOP_WRITE(tvp, &uio, 0, cred);
37165994Spendry 			} while ((uio.uio_resid > 0) && (error == 0));
37265994Spendry 		}
37365994Spendry 
37465994Spendry 	} while (error == 0);
37565994Spendry 
37665994Spendry 	free(buf, M_TEMP);
37765994Spendry 	return (error);
37865994Spendry }
37965994Spendry 
38065994Spendry /*
38165997Spendry  * Create a shadow directory in the upper layer.
38265997Spendry  * The new vnode is returned locked.
38365997Spendry  *
38465997Spendry  * (um) points to the union mount structure for access to the
38565997Spendry  * the mounting process's credentials.
38665997Spendry  * (dvp) is the directory in which to create the shadow directory.
38765997Spendry  * it is unlocked on entry and exit.
38865997Spendry  * (cnp) is the componentname to be created.
38965997Spendry  * (vpp) is the returned newly created shadow directory, which
39065997Spendry  * is returned locked.
39165997Spendry  */
39265997Spendry int
39365997Spendry union_mkshadow(um, dvp, cnp, vpp)
39465997Spendry 	struct union_mount *um;
39565997Spendry 	struct vnode *dvp;
39665997Spendry 	struct componentname *cnp;
39765997Spendry 	struct vnode **vpp;
39865997Spendry {
39965997Spendry 	int error;
40065997Spendry 	struct vattr va;
40165997Spendry 	struct proc *p = cnp->cn_proc;
40265997Spendry 	struct componentname cn;
40365997Spendry 
40465997Spendry 	/*
40565997Spendry 	 * policy: when creating the shadow directory in the
40666034Spendry 	 * upper layer, create it owned by the user who did
40766034Spendry 	 * the mount, group from parent directory, and mode
40866034Spendry 	 * 777 modified by umask (ie mostly identical to the
40966034Spendry 	 * mkdir syscall).  (jsp, kb)
41065997Spendry 	 */
41165997Spendry 
41265997Spendry 	/*
41365997Spendry 	 * A new componentname structure must be faked up because
41465997Spendry 	 * there is no way to know where the upper level cnp came
41565997Spendry 	 * from or what it is being used for.  This must duplicate
41665997Spendry 	 * some of the work done by NDINIT, some of the work done
41765997Spendry 	 * by namei, some of the work done by lookup and some of
41865997Spendry 	 * the work done by VOP_LOOKUP when given a CREATE flag.
41965997Spendry 	 * Conclusion: Horrible.
42065997Spendry 	 *
42165997Spendry 	 * The pathname buffer will be FREEed by VOP_MKDIR.
42265997Spendry 	 */
42365997Spendry 	cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK);
42466027Spendry 	bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen);
42566027Spendry 	cn.cn_pnbuf[cnp->cn_namelen] = '\0';
42665997Spendry 
42765997Spendry 	cn.cn_nameiop = CREATE;
42865997Spendry 	cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|ISLASTCN);
42965997Spendry 	cn.cn_proc = cnp->cn_proc;
43066034Spendry 	cn.cn_cred = um->um_cred;
43165997Spendry 	cn.cn_nameptr = cn.cn_pnbuf;
43265997Spendry 	cn.cn_namelen = cnp->cn_namelen;
43365997Spendry 	cn.cn_hash = cnp->cn_hash;
43465997Spendry 	cn.cn_consume = cnp->cn_consume;
43565997Spendry 
43666027Spendry 	VREF(dvp);
43765997Spendry 	if (error = relookup(dvp, vpp, &cn))
43865997Spendry 		return (error);
43966027Spendry 	vrele(dvp);
44065997Spendry 
44165997Spendry 	if (*vpp) {
44265997Spendry 		VOP_ABORTOP(dvp, &cn);
44365997Spendry 		VOP_UNLOCK(dvp);
44465997Spendry 		vrele(*vpp);
44565997Spendry 		*vpp = NULLVP;
44665997Spendry 		return (EEXIST);
44765997Spendry 	}
44865997Spendry 
44965997Spendry 	VATTR_NULL(&va);
45065997Spendry 	va.va_type = VDIR;
45166034Spendry 	va.va_mode = um->um_cmode;
45265997Spendry 
45365997Spendry 	/* LEASE_CHECK: dvp is locked */
45465997Spendry 	LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE);
45565997Spendry 
45665997Spendry 	VREF(dvp);
45765997Spendry 	error = VOP_MKDIR(dvp, vpp, &cn, &va);
45865997Spendry 	return (error);
45965997Spendry }
46065997Spendry 
46165997Spendry /*
46265994Spendry  * union_vn_create: creates and opens a new shadow file
46365994Spendry  * on the upper union layer.  this function is similar
46465994Spendry  * in spirit to calling vn_open but it avoids calling namei().
46565994Spendry  * the problem with calling namei is that a) it locks too many
46665994Spendry  * things, and b) it doesn't start at the "right" directory,
46765994Spendry  * whereas relookup is told where to start.
46865994Spendry  */
46965994Spendry int
47065997Spendry union_vn_create(vpp, un, p)
47165994Spendry 	struct vnode **vpp;
47265994Spendry 	struct union_node *un;
47365994Spendry 	struct proc *p;
47465994Spendry {
47565994Spendry 	struct vnode *vp;
47665994Spendry 	struct ucred *cred = p->p_ucred;
47765994Spendry 	struct vattr vat;
47865994Spendry 	struct vattr *vap = &vat;
47965994Spendry 	int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL);
48065994Spendry 	int error;
48166027Spendry 	int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask;
48265994Spendry 	char *cp;
48365994Spendry 	struct componentname cn;
48465994Spendry 
48565994Spendry 	*vpp = NULLVP;
48665994Spendry 
48766034Spendry 	/*
48866034Spendry 	 * Build a new componentname structure (for the same
48966034Spendry 	 * reasons outlines in union_mkshadow).
49066034Spendry 	 * The difference here is that the file is owned by
49166034Spendry 	 * the current user, rather than by the person who
49266034Spendry 	 * did the mount, since the current user needs to be
49366034Spendry 	 * able to write the file (that's why it is being
49466034Spendry 	 * copied in the first place).
49566034Spendry 	 */
49665994Spendry 	cn.cn_namelen = strlen(un->un_path);
49765994Spendry 	cn.cn_pnbuf = (caddr_t) malloc(cn.cn_namelen, M_NAMEI, M_WAITOK);
49865994Spendry 	bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1);
49965994Spendry 	cn.cn_nameiop = CREATE;
50065994Spendry 	cn.cn_flags = (LOCKLEAF|LOCKPARENT|HASBUF|SAVENAME|ISLASTCN);
50165994Spendry 	cn.cn_proc = p;
50265994Spendry 	cn.cn_cred = p->p_ucred;
50365994Spendry 	cn.cn_nameptr = cn.cn_pnbuf;
50466027Spendry 	cn.cn_hash = un->un_hash;
50565994Spendry 	cn.cn_consume = 0;
50665994Spendry 
50766027Spendry 	VREF(un->un_dirvp);
50865994Spendry 	if (error = relookup(un->un_dirvp, &vp, &cn))
50965994Spendry 		return (error);
51066027Spendry 	vrele(un->un_dirvp);
51166027Spendry 
51265994Spendry 	if (vp == NULLVP) {
51366034Spendry 		/*
51466034Spendry 		 * Good - there was no race to create the file
51566034Spendry 		 * so go ahead and create it.  The permissions
51666034Spendry 		 * on the file will be 0666 modified by the
51766034Spendry 		 * current user's umask.  Access to the file, while
51866034Spendry 		 * it is unioned, will require access to the top *and*
51966034Spendry 		 * bottom files.  Access when not unioned will simply
52066034Spendry 		 * require access to the top-level file.
52166034Spendry 		 * TODO: confirm choice of access permissions.
52266034Spendry 		 */
52365994Spendry 		VATTR_NULL(vap);
52465994Spendry 		vap->va_type = VREG;
52565994Spendry 		vap->va_mode = cmode;
52665994Spendry 		LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE);
52765994Spendry 		if (error = VOP_CREATE(un->un_dirvp, &vp,
52865994Spendry 		    &cn, vap))
52965994Spendry 			return (error);
53065994Spendry 	} else {
53165994Spendry 		VOP_ABORTOP(un->un_dirvp, &cn);
53265994Spendry 		if (un->un_dirvp == vp)
53365994Spendry 			vrele(un->un_dirvp);
53465994Spendry 		else
53565994Spendry 			vput(vp);
53665994Spendry 		error = EEXIST;
53765994Spendry 		goto bad;
53865994Spendry 	}
53965994Spendry 
54065994Spendry 	if (vp->v_type != VREG) {
54165994Spendry 		error = EOPNOTSUPP;
54265994Spendry 		goto bad;
54365994Spendry 	}
54465994Spendry 
54565994Spendry 	VOP_UNLOCK(vp);				/* XXX */
54665994Spendry 	LEASE_CHECK(vp, p, cred, LEASE_WRITE);
54765994Spendry 	VOP_LOCK(vp);				/* XXX */
54865994Spendry 	VATTR_NULL(vap);
54965994Spendry 	vap->va_size = 0;
55065994Spendry 	if (error = VOP_SETATTR(vp, vap, cred, p))
55165994Spendry 		goto bad;
55265994Spendry 
55365994Spendry 	if (error = VOP_OPEN(vp, fmode, cred, p))
55465994Spendry 		goto bad;
55565994Spendry 
55665994Spendry 	vp->v_writecount++;
55765994Spendry 	*vpp = vp;
55865994Spendry 	return (0);
55965994Spendry bad:
56065994Spendry 	vput(vp);
56165994Spendry 	return (error);
56265994Spendry }
56366027Spendry 
56466027Spendry int
56566028Spendry union_vn_close(vp, fmode, cred, p)
56666027Spendry 	struct vnode *vp;
56766027Spendry 	int fmode;
56866028Spendry 	struct ucred *cred;
56966028Spendry 	struct proc *p;
57066027Spendry {
57166027Spendry 	if (fmode & FWRITE)
57266027Spendry 		--vp->v_writecount;
57366027Spendry 	return (VOP_CLOSE(vp, fmode));
57466027Spendry }
57566027Spendry 
57666027Spendry void
57766027Spendry union_removed_upper(un)
57866027Spendry 	struct union_node *un;
57966027Spendry {
580*66051Spendry 	if (un->un_flags & UN_ULOCK) {
581*66051Spendry 		un->un_flags &= ~UN_ULOCK;
582*66051Spendry 		vput(un->un_uppervp);
583*66051Spendry 	} else {
584*66051Spendry 		vrele(un->un_uppervp);
585*66051Spendry 	}
58666027Spendry 	un->un_uppervp = NULLVP;
58766027Spendry }
58866028Spendry 
58966028Spendry struct vnode *
59066028Spendry union_lowervp(vp)
59166028Spendry 	struct vnode *vp;
59266028Spendry {
59366028Spendry 	struct union_node *un = VTOUNION(vp);
59466028Spendry 
59566028Spendry 	if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) {
59666028Spendry 		if (vget(un->un_lowervp, 0))
59766028Spendry 			return (NULLVP);
59866028Spendry 	}
59966028Spendry 
60066028Spendry 	return (un->un_lowervp);
60166028Spendry }
602