xref: /csrg-svn/sys/miscfs/union/union_subr.c (revision 66060)
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*66060Spendry  *	@(#)union_subr.c	8.3 (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>
2366053Spendry #include <sys/queue.h>
2466055Spendry #include <miscfs/union/union.h>
2565934Spendry 
2665992Spendry #ifdef DIAGNOSTIC
2765992Spendry #include <sys/proc.h>
2865992Spendry #endif
2965992Spendry 
3066053Spendry /* must be power of two, otherwise change UNION_HASH() */
3166053Spendry #define NHASH 32
3265934Spendry 
3366053Spendry /* unsigned int ... */
3466053Spendry #define UNION_HASH(u, l) \
3566053Spendry 	(((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1))
3666053Spendry 
3766053Spendry static LIST_HEAD(unhead, union_node) unhead[NHASH];
3866053Spendry static int unvplock[NHASH];
3966053Spendry 
4065934Spendry int
4165934Spendry union_init()
4265934Spendry {
4366053Spendry 	int i;
4465934Spendry 
4566053Spendry 	for (i = 0; i < NHASH; i++)
4666053Spendry 		LIST_INIT(&unhead[i]);
4766053Spendry 	bzero((caddr_t) unvplock, sizeof(unvplock));
4865934Spendry }
4965934Spendry 
5066053Spendry static int
5166053Spendry union_list_lock(ix)
5266053Spendry 	int ix;
5366053Spendry {
5466053Spendry 
5566053Spendry 	if (unvplock[ix] & UN_LOCKED) {
5666053Spendry 		unvplock[ix] |= UN_WANT;
5766053Spendry 		sleep((caddr_t) &unvplock[ix], PINOD);
5866053Spendry 		return (1);
5966053Spendry 	}
6066053Spendry 
6166053Spendry 	unvplock[ix] |= UN_LOCKED;
6266053Spendry 
6366053Spendry 	return (0);
6466053Spendry }
6566053Spendry 
6666051Spendry static void
6766053Spendry union_list_unlock(ix)
6866053Spendry 	int ix;
6966053Spendry {
7066053Spendry 
7166053Spendry 	unvplock[ix] &= ~UN_LOCKED;
7266053Spendry 
7366053Spendry 	if (unvplock[ix] & UN_WANT) {
7466053Spendry 		unvplock[ix] &= ~UN_WANT;
7566053Spendry 		wakeup((caddr_t) &unvplock[ix]);
7666053Spendry 	}
7766053Spendry }
7866053Spendry 
7966053Spendry void
8066053Spendry union_updatevp(un, uppervp, lowervp)
8166051Spendry 	struct union_node *un;
8266053Spendry 	struct vnode *uppervp;
8366053Spendry 	struct vnode *lowervp;
8466051Spendry {
8566053Spendry 	int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
8666053Spendry 	int nhash = UNION_HASH(uppervp, lowervp);
8766051Spendry 
8866053Spendry 	if (ohash != nhash) {
8966053Spendry 		/*
9066053Spendry 		 * Ensure locking is ordered from lower to higher
9166053Spendry 		 * to avoid deadlocks.
9266053Spendry 		 */
9366053Spendry 		if (nhash < ohash) {
9466053Spendry 			int t = ohash;
9566053Spendry 			ohash = nhash;
9666053Spendry 			nhash = t;
9766051Spendry 		}
9866053Spendry 
9966053Spendry 		while (union_list_lock(ohash))
10066053Spendry 			continue;
10166053Spendry 
10266053Spendry 		while (union_list_lock(nhash))
10366053Spendry 			continue;
10466053Spendry 
10566053Spendry 		LIST_REMOVE(un, un_cache);
10666053Spendry 		union_list_unlock(ohash);
10766053Spendry 	} else {
10866053Spendry 		while (union_list_lock(nhash))
10966053Spendry 			continue;
11066051Spendry 	}
11166053Spendry 
11266053Spendry 	if (un->un_lowervp != lowervp) {
11366053Spendry 		if (un->un_lowervp) {
11466053Spendry 			vrele(un->un_lowervp);
11566053Spendry 			if (un->un_path) {
11666053Spendry 				free(un->un_path, M_TEMP);
11766053Spendry 				un->un_path = 0;
11866053Spendry 			}
11966053Spendry 			if (un->un_dirvp) {
12066053Spendry 				vrele(un->un_dirvp);
12166053Spendry 				un->un_dirvp = NULLVP;
12266053Spendry 			}
12366053Spendry 		}
12466053Spendry 		un->un_lowervp = lowervp;
12566053Spendry 	}
12666053Spendry 
12766053Spendry 	if (un->un_uppervp != uppervp) {
12866053Spendry 		if (un->un_uppervp)
12966053Spendry 			vrele(un->un_uppervp);
13066053Spendry 
13166053Spendry 		un->un_uppervp = uppervp;
13266053Spendry 	}
13366053Spendry 
13466053Spendry 	if (ohash != nhash)
13566053Spendry 		LIST_INSERT_HEAD(&unhead[nhash], un, un_cache);
13666053Spendry 
13766053Spendry 	union_list_unlock(nhash);
13866051Spendry }
13966051Spendry 
14066053Spendry void
14166053Spendry union_newlower(un, lowervp)
14266053Spendry 	struct union_node *un;
14366053Spendry 	struct vnode *lowervp;
14466053Spendry {
14566053Spendry 
14666053Spendry 	union_updatevp(un, un->un_uppervp, lowervp);
14766053Spendry }
14866053Spendry 
14966053Spendry void
15066053Spendry union_newupper(un, uppervp)
15166053Spendry 	struct union_node *un;
15266053Spendry 	struct vnode *uppervp;
15366053Spendry {
15466053Spendry 
15566053Spendry 	union_updatevp(un, uppervp, un->un_lowervp);
15666053Spendry }
15766053Spendry 
15865934Spendry /*
15965934Spendry  * allocate a union_node/vnode pair.  the vnode is
16065965Spendry  * referenced and locked.  the new vnode is returned
16165965Spendry  * via (vpp).  (mp) is the mountpoint of the union filesystem,
16265965Spendry  * (dvp) is the parent directory where the upper layer object
16365965Spendry  * should exist (but doesn't) and (cnp) is the componentname
16465965Spendry  * information which is partially copied to allow the upper
16565965Spendry  * layer object to be created at a later time.  (uppervp)
16665965Spendry  * and (lowervp) reference the upper and lower layer objects
16765965Spendry  * being mapped.  either, but not both, can be nil.
16866051Spendry  * if supplied, (uppervp) is locked.
16965997Spendry  * the reference is either maintained in the new union_node
17065997Spendry  * object which is allocated, or they are vrele'd.
17165934Spendry  *
17265934Spendry  * all union_nodes are maintained on a singly-linked
17365934Spendry  * list.  new nodes are only allocated when they cannot
17465934Spendry  * be found on this list.  entries on the list are
17565934Spendry  * removed when the vfs reclaim entry is called.
17665934Spendry  *
17765934Spendry  * a single lock is kept for the entire list.  this is
17865934Spendry  * needed because the getnewvnode() function can block
17965934Spendry  * waiting for a vnode to become free, in which case there
18065934Spendry  * may be more than one process trying to get the same
18165934Spendry  * vnode.  this lock is only taken if we are going to
18265934Spendry  * call getnewvnode, since the kernel itself is single-threaded.
18365934Spendry  *
18465934Spendry  * if an entry is found on the list, then call vget() to
18565934Spendry  * take a reference.  this is done because there may be
18665934Spendry  * zero references to it and so it needs to removed from
18765934Spendry  * the vnode free list.
18865934Spendry  */
18965934Spendry int
19065992Spendry union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
19165934Spendry 	struct vnode **vpp;
19265934Spendry 	struct mount *mp;
19365992Spendry 	struct vnode *undvp;
19465934Spendry 	struct vnode *dvp;		/* may be null */
19565934Spendry 	struct componentname *cnp;	/* may be null */
19665934Spendry 	struct vnode *uppervp;		/* may be null */
19765934Spendry 	struct vnode *lowervp;		/* may be null */
19865934Spendry {
19965934Spendry 	int error;
20065934Spendry 	struct union_node *un;
20165934Spendry 	struct union_node **pp;
20266053Spendry 	struct vnode *xlowervp = NULLVP;
20366053Spendry 	int hash;
20466053Spendry 	int try;
20565934Spendry 
20666053Spendry 	if (uppervp == NULLVP && lowervp == NULLVP)
20765965Spendry 		panic("union: unidentifiable allocation");
20865965Spendry 
20965965Spendry 	if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) {
21065965Spendry 		xlowervp = lowervp;
21166053Spendry 		lowervp = NULLVP;
21265965Spendry 	}
21365965Spendry 
21465934Spendry loop:
21566053Spendry 	for (try = 0; try < 3; try++) {
21666053Spendry 		switch (try) {
21766053Spendry 		case 0:
21866053Spendry 			if (lowervp == NULLVP)
21966053Spendry 				continue;
22066053Spendry 			hash = UNION_HASH(uppervp, lowervp);
22166051Spendry 			break;
22266053Spendry 
22366053Spendry 		case 1:
22466053Spendry 			if (uppervp == NULLVP)
22566053Spendry 				continue;
22666053Spendry 			hash = UNION_HASH(uppervp, NULLVP);
22766053Spendry 			break;
22866053Spendry 
22966053Spendry 		case 2:
23066053Spendry 			if (lowervp == NULLVP)
23166053Spendry 				continue;
23266053Spendry 			hash = UNION_HASH(NULLVP, lowervp);
23366053Spendry 			break;
23466051Spendry 		}
23566053Spendry 
23666053Spendry 		while (union_list_lock(hash))
23766053Spendry 			continue;
23866053Spendry 
23966053Spendry 		for (un = unhead[hash].lh_first; un != 0;
24066053Spendry 					un = un->un_cache.le_next) {
24166053Spendry 			if ((un->un_lowervp == lowervp ||
24266053Spendry 			     un->un_lowervp == NULLVP) &&
24366053Spendry 			    (un->un_uppervp == uppervp ||
24466053Spendry 			     un->un_uppervp == NULLVP) &&
24566053Spendry 			    (UNIONTOV(un)->v_mount == mp)) {
24666053Spendry 				if (vget(UNIONTOV(un), 0)) {
24766053Spendry 					union_list_unlock(hash);
24866053Spendry 					goto loop;
24966053Spendry 				}
25066053Spendry 				break;
25166053Spendry 			}
25266053Spendry 		}
25366053Spendry 
25466053Spendry 		union_list_unlock(hash);
25566053Spendry 
25666053Spendry 		if (un)
25766053Spendry 			break;
25866051Spendry 	}
25966027Spendry 
26066051Spendry 	if (un) {
26166051Spendry 		/*
26266051Spendry 		 * Obtain a lock on the union_node.
26366051Spendry 		 * uppervp is locked, though un->un_uppervp
26466051Spendry 		 * may not be.  this doesn't break the locking
26566051Spendry 		 * hierarchy since in the case that un->un_uppervp
26666051Spendry 		 * is not yet locked it will be vrele'd and replaced
26766051Spendry 		 * with uppervp.
26866051Spendry 		 */
26966051Spendry 
27066051Spendry 		if ((dvp != NULLVP) && (uppervp == dvp)) {
27166027Spendry 			/*
27266051Spendry 			 * Access ``.'', so (un) will already
27366051Spendry 			 * be locked.  Since this process has
27466051Spendry 			 * the lock on (uppervp) no other
27566051Spendry 			 * process can hold the lock on (un).
27666027Spendry 			 */
27766051Spendry #ifdef DIAGNOSTIC
27866051Spendry 			if ((un->un_flags & UN_LOCKED) == 0)
27966051Spendry 				panic("union: . not locked");
28066051Spendry 			else if (curproc && un->un_pid != curproc->p_pid &&
28166051Spendry 				    un->un_pid > -1 && curproc->p_pid > -1)
28266051Spendry 				panic("union: allocvp not lock owner");
28366051Spendry #endif
28466051Spendry 		} else {
28566051Spendry 			if (un->un_flags & UN_LOCKED) {
28666051Spendry 				vrele(UNIONTOV(un));
28766051Spendry 				un->un_flags |= UN_WANT;
28866051Spendry 				sleep((caddr_t) &un->un_flags, PINOD);
28966051Spendry 				goto loop;
29065992Spendry 			}
29166051Spendry 			un->un_flags |= UN_LOCKED;
29266027Spendry 
29366051Spendry #ifdef DIAGNOSTIC
29466051Spendry 			if (curproc)
29566051Spendry 				un->un_pid = curproc->p_pid;
29666051Spendry 			else
29766051Spendry 				un->un_pid = -1;
29866051Spendry #endif
29966051Spendry 		}
30066051Spendry 
30166051Spendry 		/*
30266051Spendry 		 * At this point, the union_node is locked,
30366051Spendry 		 * un->un_uppervp may not be locked, and uppervp
30466051Spendry 		 * is locked or nil.
30566051Spendry 		 */
30666051Spendry 
30766051Spendry 		/*
30866051Spendry 		 * Save information about the upper layer.
30966051Spendry 		 */
31066051Spendry 		if (uppervp != un->un_uppervp) {
31166053Spendry 			union_newupper(un, uppervp);
31266051Spendry 		} else if (uppervp) {
31366051Spendry 			vrele(uppervp);
31466051Spendry 		}
31566051Spendry 
31666051Spendry 		if (un->un_uppervp) {
31766051Spendry 			un->un_flags |= UN_ULOCK;
31866051Spendry 			un->un_flags &= ~UN_KLOCK;
31966051Spendry 		}
32066051Spendry 
32166051Spendry 		/*
32266051Spendry 		 * Save information about the lower layer.
32366051Spendry 		 * This needs to keep track of pathname
32466051Spendry 		 * and directory information which union_vn_create
32566051Spendry 		 * might need.
32666051Spendry 		 */
32766051Spendry 		if (lowervp != un->un_lowervp) {
32866053Spendry 			union_newlower(un, lowervp);
32966051Spendry 			if (cnp && (lowervp != NULLVP) &&
33066051Spendry 			    (lowervp->v_type == VREG)) {
33166051Spendry 				un->un_hash = cnp->cn_hash;
33266051Spendry 				un->un_path = malloc(cnp->cn_namelen+1,
33366051Spendry 						M_TEMP, M_WAITOK);
33466051Spendry 				bcopy(cnp->cn_nameptr, un->un_path,
33566051Spendry 						cnp->cn_namelen);
33666051Spendry 				un->un_path[cnp->cn_namelen] = '\0';
33766051Spendry 				VREF(dvp);
33866051Spendry 				un->un_dirvp = dvp;
33966051Spendry 			}
34066051Spendry 		} else if (lowervp) {
34166051Spendry 			vrele(lowervp);
34265934Spendry 		}
34366051Spendry 		*vpp = UNIONTOV(un);
34466051Spendry 		return (0);
34565934Spendry 	}
34665934Spendry 
34765934Spendry 	/*
34865934Spendry 	 * otherwise lock the vp list while we call getnewvnode
34965934Spendry 	 * since that can block.
35065934Spendry 	 */
35166053Spendry 	hash = UNION_HASH(uppervp, lowervp);
35266053Spendry 
35366053Spendry 	if (union_list_lock(hash))
35465934Spendry 		goto loop;
35565934Spendry 
35665934Spendry 	error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp);
35766051Spendry 	if (error) {
35866051Spendry 		if (uppervp) {
35966051Spendry 			if (dvp == uppervp)
36066051Spendry 				vrele(uppervp);
36166051Spendry 			else
36266051Spendry 				vput(uppervp);
36366051Spendry 		}
36466051Spendry 		if (lowervp)
36566051Spendry 			vrele(lowervp);
36666051Spendry 
36765934Spendry 		goto out;
36866051Spendry 	}
36965934Spendry 
37065934Spendry 	MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),
37165934Spendry 		M_TEMP, M_WAITOK);
37265934Spendry 
37365965Spendry 	if (uppervp)
37465965Spendry 		(*vpp)->v_type = uppervp->v_type;
37565965Spendry 	else
37665965Spendry 		(*vpp)->v_type = lowervp->v_type;
37765934Spendry 	un = VTOUNION(*vpp);
37865992Spendry 	un->un_vnode = *vpp;
37965934Spendry 	un->un_uppervp = uppervp;
38065934Spendry 	un->un_lowervp = lowervp;
38166028Spendry 	un->un_openl = 0;
38266051Spendry 	un->un_flags = UN_LOCKED;
38366051Spendry 	if (un->un_uppervp)
38466051Spendry 		un->un_flags |= UN_ULOCK;
38566051Spendry #ifdef DIAGNOSTIC
38666051Spendry 	if (curproc)
38766051Spendry 		un->un_pid = curproc->p_pid;
38866051Spendry 	else
38966051Spendry 		un->un_pid = -1;
39066051Spendry #endif
39166027Spendry 	if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) {
39266027Spendry 		un->un_hash = cnp->cn_hash;
39365934Spendry 		un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
39465934Spendry 		bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
39565934Spendry 		un->un_path[cnp->cn_namelen] = '\0';
39665965Spendry 		VREF(dvp);
39765965Spendry 		un->un_dirvp = dvp;
39865934Spendry 	} else {
39966027Spendry 		un->un_hash = 0;
40065934Spendry 		un->un_path = 0;
40165965Spendry 		un->un_dirvp = 0;
40265934Spendry 	}
40365934Spendry 
40466053Spendry 	LIST_INSERT_HEAD(&unhead[hash], un, un_cache);
40565934Spendry 
40665965Spendry 	if (xlowervp)
40765965Spendry 		vrele(xlowervp);
40865965Spendry 
40965934Spendry out:
41066053Spendry 	union_list_unlock(hash);
41165934Spendry 
41265934Spendry 	return (error);
41365934Spendry }
41465934Spendry 
41565934Spendry int
41665934Spendry union_freevp(vp)
41765934Spendry 	struct vnode *vp;
41865934Spendry {
41965934Spendry 	struct union_node *un = VTOUNION(vp);
42065934Spendry 
42166053Spendry 	LIST_REMOVE(un, un_cache);
42265934Spendry 
42366053Spendry 	if (un->un_uppervp)
42466053Spendry 		vrele(un->un_uppervp);
42566053Spendry 	if (un->un_lowervp)
42666053Spendry 		vrele(un->un_lowervp);
42766053Spendry 	if (un->un_dirvp)
42866053Spendry 		vrele(un->un_dirvp);
42966053Spendry 	if (un->un_path)
43066053Spendry 		free(un->un_path, M_TEMP);
43166053Spendry 
43265934Spendry 	FREE(vp->v_data, M_TEMP);
43365934Spendry 	vp->v_data = 0;
43466053Spendry 
43565934Spendry 	return (0);
43665934Spendry }
43765994Spendry 
43865994Spendry /*
43965994Spendry  * copyfile.  copy the vnode (fvp) to the vnode (tvp)
44065994Spendry  * using a sequence of reads and writes.  both (fvp)
44165994Spendry  * and (tvp) are locked on entry and exit.
44265994Spendry  */
44365994Spendry int
44465994Spendry union_copyfile(p, cred, fvp, tvp)
44565994Spendry 	struct proc *p;
44665994Spendry 	struct ucred *cred;
44765994Spendry 	struct vnode *fvp;
44865994Spendry 	struct vnode *tvp;
44965994Spendry {
45065994Spendry 	char *buf;
45165994Spendry 	struct uio uio;
45265994Spendry 	struct iovec iov;
45365994Spendry 	int error = 0;
45465994Spendry 
45565994Spendry 	/*
45665994Spendry 	 * strategy:
45765994Spendry 	 * allocate a buffer of size MAXBSIZE.
45865994Spendry 	 * loop doing reads and writes, keeping track
45965994Spendry 	 * of the current uio offset.
46065994Spendry 	 * give up at the first sign of trouble.
46165994Spendry 	 */
46265994Spendry 
46365994Spendry 	uio.uio_procp = p;
46465994Spendry 	uio.uio_segflg = UIO_SYSSPACE;
46565994Spendry 	uio.uio_offset = 0;
46665994Spendry 
46765994Spendry 	VOP_UNLOCK(fvp);				/* XXX */
46865994Spendry 	LEASE_CHECK(fvp, p, cred, LEASE_READ);
46965994Spendry 	VOP_LOCK(fvp);					/* XXX */
47065994Spendry 	VOP_UNLOCK(tvp);				/* XXX */
47165994Spendry 	LEASE_CHECK(tvp, p, cred, LEASE_WRITE);
47265994Spendry 	VOP_LOCK(tvp);					/* XXX */
47365994Spendry 
47465994Spendry 	buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
47565994Spendry 
47665994Spendry 	/* ugly loop follows... */
47765994Spendry 	do {
47865994Spendry 		off_t offset = uio.uio_offset;
47965994Spendry 
48065994Spendry 		uio.uio_iov = &iov;
48165994Spendry 		uio.uio_iovcnt = 1;
48265994Spendry 		iov.iov_base = buf;
48365994Spendry 		iov.iov_len = MAXBSIZE;
48465994Spendry 		uio.uio_resid = iov.iov_len;
48565994Spendry 		uio.uio_rw = UIO_READ;
48665994Spendry 		error = VOP_READ(fvp, &uio, 0, cred);
48765994Spendry 
48865994Spendry 		if (error == 0) {
48965994Spendry 			uio.uio_iov = &iov;
49065994Spendry 			uio.uio_iovcnt = 1;
49165994Spendry 			iov.iov_base = buf;
49265994Spendry 			iov.iov_len = MAXBSIZE - uio.uio_resid;
49365994Spendry 			uio.uio_offset = offset;
49465994Spendry 			uio.uio_rw = UIO_WRITE;
49565994Spendry 			uio.uio_resid = iov.iov_len;
49665994Spendry 
49765994Spendry 			if (uio.uio_resid == 0)
49865994Spendry 				break;
49965994Spendry 
50065994Spendry 			do {
50165994Spendry 				error = VOP_WRITE(tvp, &uio, 0, cred);
50265994Spendry 			} while ((uio.uio_resid > 0) && (error == 0));
50365994Spendry 		}
50465994Spendry 
50565994Spendry 	} while (error == 0);
50665994Spendry 
50765994Spendry 	free(buf, M_TEMP);
50865994Spendry 	return (error);
50965994Spendry }
51065994Spendry 
51165994Spendry /*
51265997Spendry  * Create a shadow directory in the upper layer.
51365997Spendry  * The new vnode is returned locked.
51465997Spendry  *
51565997Spendry  * (um) points to the union mount structure for access to the
51665997Spendry  * the mounting process's credentials.
51765997Spendry  * (dvp) is the directory in which to create the shadow directory.
51865997Spendry  * it is unlocked on entry and exit.
51965997Spendry  * (cnp) is the componentname to be created.
52065997Spendry  * (vpp) is the returned newly created shadow directory, which
52165997Spendry  * is returned locked.
52265997Spendry  */
52365997Spendry int
52465997Spendry union_mkshadow(um, dvp, cnp, vpp)
52565997Spendry 	struct union_mount *um;
52665997Spendry 	struct vnode *dvp;
52765997Spendry 	struct componentname *cnp;
52865997Spendry 	struct vnode **vpp;
52965997Spendry {
53065997Spendry 	int error;
53165997Spendry 	struct vattr va;
53265997Spendry 	struct proc *p = cnp->cn_proc;
53365997Spendry 	struct componentname cn;
53465997Spendry 
53565997Spendry 	/*
53665997Spendry 	 * policy: when creating the shadow directory in the
53766034Spendry 	 * upper layer, create it owned by the user who did
53866034Spendry 	 * the mount, group from parent directory, and mode
53966034Spendry 	 * 777 modified by umask (ie mostly identical to the
54066034Spendry 	 * mkdir syscall).  (jsp, kb)
54165997Spendry 	 */
54265997Spendry 
54365997Spendry 	/*
54465997Spendry 	 * A new componentname structure must be faked up because
54565997Spendry 	 * there is no way to know where the upper level cnp came
54665997Spendry 	 * from or what it is being used for.  This must duplicate
54765997Spendry 	 * some of the work done by NDINIT, some of the work done
54865997Spendry 	 * by namei, some of the work done by lookup and some of
54965997Spendry 	 * the work done by VOP_LOOKUP when given a CREATE flag.
55065997Spendry 	 * Conclusion: Horrible.
55165997Spendry 	 *
55265997Spendry 	 * The pathname buffer will be FREEed by VOP_MKDIR.
55365997Spendry 	 */
55465997Spendry 	cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK);
55566027Spendry 	bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen);
55666027Spendry 	cn.cn_pnbuf[cnp->cn_namelen] = '\0';
55765997Spendry 
55865997Spendry 	cn.cn_nameiop = CREATE;
559*66060Spendry 	cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
56065997Spendry 	cn.cn_proc = cnp->cn_proc;
56166034Spendry 	cn.cn_cred = um->um_cred;
56265997Spendry 	cn.cn_nameptr = cn.cn_pnbuf;
56365997Spendry 	cn.cn_namelen = cnp->cn_namelen;
56465997Spendry 	cn.cn_hash = cnp->cn_hash;
56565997Spendry 	cn.cn_consume = cnp->cn_consume;
56665997Spendry 
56766027Spendry 	VREF(dvp);
56865997Spendry 	if (error = relookup(dvp, vpp, &cn))
56965997Spendry 		return (error);
57066027Spendry 	vrele(dvp);
57165997Spendry 
57265997Spendry 	if (*vpp) {
57365997Spendry 		VOP_ABORTOP(dvp, &cn);
57465997Spendry 		VOP_UNLOCK(dvp);
57565997Spendry 		vrele(*vpp);
57665997Spendry 		*vpp = NULLVP;
57765997Spendry 		return (EEXIST);
57865997Spendry 	}
57965997Spendry 
58065997Spendry 	VATTR_NULL(&va);
58165997Spendry 	va.va_type = VDIR;
58266034Spendry 	va.va_mode = um->um_cmode;
58365997Spendry 
58465997Spendry 	/* LEASE_CHECK: dvp is locked */
58565997Spendry 	LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE);
58665997Spendry 
58765997Spendry 	error = VOP_MKDIR(dvp, vpp, &cn, &va);
58865997Spendry 	return (error);
58965997Spendry }
59065997Spendry 
59165997Spendry /*
59265994Spendry  * union_vn_create: creates and opens a new shadow file
59365994Spendry  * on the upper union layer.  this function is similar
59465994Spendry  * in spirit to calling vn_open but it avoids calling namei().
59565994Spendry  * the problem with calling namei is that a) it locks too many
59665994Spendry  * things, and b) it doesn't start at the "right" directory,
59765994Spendry  * whereas relookup is told where to start.
59865994Spendry  */
59965994Spendry int
60065997Spendry union_vn_create(vpp, un, p)
60165994Spendry 	struct vnode **vpp;
60265994Spendry 	struct union_node *un;
60365994Spendry 	struct proc *p;
60465994Spendry {
60565994Spendry 	struct vnode *vp;
60665994Spendry 	struct ucred *cred = p->p_ucred;
60765994Spendry 	struct vattr vat;
60865994Spendry 	struct vattr *vap = &vat;
60965994Spendry 	int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL);
61065994Spendry 	int error;
61166027Spendry 	int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask;
61265994Spendry 	char *cp;
61365994Spendry 	struct componentname cn;
61465994Spendry 
61565994Spendry 	*vpp = NULLVP;
61665994Spendry 
61766034Spendry 	/*
61866034Spendry 	 * Build a new componentname structure (for the same
61966034Spendry 	 * reasons outlines in union_mkshadow).
62066034Spendry 	 * The difference here is that the file is owned by
62166034Spendry 	 * the current user, rather than by the person who
62266034Spendry 	 * did the mount, since the current user needs to be
62366034Spendry 	 * able to write the file (that's why it is being
62466034Spendry 	 * copied in the first place).
62566034Spendry 	 */
62665994Spendry 	cn.cn_namelen = strlen(un->un_path);
62765994Spendry 	cn.cn_pnbuf = (caddr_t) malloc(cn.cn_namelen, M_NAMEI, M_WAITOK);
62865994Spendry 	bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1);
62965994Spendry 	cn.cn_nameiop = CREATE;
630*66060Spendry 	cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
63165994Spendry 	cn.cn_proc = p;
63265994Spendry 	cn.cn_cred = p->p_ucred;
63365994Spendry 	cn.cn_nameptr = cn.cn_pnbuf;
63466027Spendry 	cn.cn_hash = un->un_hash;
63565994Spendry 	cn.cn_consume = 0;
63665994Spendry 
63766027Spendry 	VREF(un->un_dirvp);
63865994Spendry 	if (error = relookup(un->un_dirvp, &vp, &cn))
63965994Spendry 		return (error);
64066027Spendry 	vrele(un->un_dirvp);
64166027Spendry 
642*66060Spendry 	if (vp) {
64365994Spendry 		VOP_ABORTOP(un->un_dirvp, &cn);
64465994Spendry 		if (un->un_dirvp == vp)
64565994Spendry 			vrele(un->un_dirvp);
64665994Spendry 		else
647*66060Spendry 			vput(un->un_dirvp);
648*66060Spendry 		vrele(vp);
649*66060Spendry 		return (EEXIST);
65065994Spendry 	}
65165994Spendry 
652*66060Spendry 	/*
653*66060Spendry 	 * Good - there was no race to create the file
654*66060Spendry 	 * so go ahead and create it.  The permissions
655*66060Spendry 	 * on the file will be 0666 modified by the
656*66060Spendry 	 * current user's umask.  Access to the file, while
657*66060Spendry 	 * it is unioned, will require access to the top *and*
658*66060Spendry 	 * bottom files.  Access when not unioned will simply
659*66060Spendry 	 * require access to the top-level file.
660*66060Spendry 	 * TODO: confirm choice of access permissions.
661*66060Spendry 	 */
66265994Spendry 	VATTR_NULL(vap);
663*66060Spendry 	vap->va_type = VREG;
664*66060Spendry 	vap->va_mode = cmode;
665*66060Spendry 	LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE);
666*66060Spendry 	if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap))
667*66060Spendry 		return (error);
66865994Spendry 
669*66060Spendry 	if (error = VOP_OPEN(vp, fmode, cred, p)) {
670*66060Spendry 		vput(vp);
671*66060Spendry 		return (error);
672*66060Spendry 	}
67365994Spendry 
67465994Spendry 	vp->v_writecount++;
67565994Spendry 	*vpp = vp;
67665994Spendry 	return (0);
67765994Spendry }
67866027Spendry 
67966027Spendry int
68066028Spendry union_vn_close(vp, fmode, cred, p)
68166027Spendry 	struct vnode *vp;
68266027Spendry 	int fmode;
68366028Spendry 	struct ucred *cred;
68466028Spendry 	struct proc *p;
68566027Spendry {
68666027Spendry 	if (fmode & FWRITE)
68766027Spendry 		--vp->v_writecount;
68866027Spendry 	return (VOP_CLOSE(vp, fmode));
68966027Spendry }
69066027Spendry 
69166027Spendry void
69266027Spendry union_removed_upper(un)
69366027Spendry 	struct union_node *un;
69466027Spendry {
69566051Spendry 	if (un->un_flags & UN_ULOCK) {
69666051Spendry 		un->un_flags &= ~UN_ULOCK;
69766053Spendry 		VOP_UNLOCK(un->un_uppervp);
69866051Spendry 	}
69966053Spendry 
70066053Spendry 	union_newupper(un, NULLVP);
70166027Spendry }
70266028Spendry 
70366028Spendry struct vnode *
70466028Spendry union_lowervp(vp)
70566028Spendry 	struct vnode *vp;
70666028Spendry {
70766028Spendry 	struct union_node *un = VTOUNION(vp);
70866028Spendry 
70966028Spendry 	if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) {
71066028Spendry 		if (vget(un->un_lowervp, 0))
71166028Spendry 			return (NULLVP);
71266028Spendry 	}
71366028Spendry 
71466028Spendry 	return (un->un_lowervp);
71566028Spendry }
716