xref: /csrg-svn/sys/miscfs/union/union_subr.c (revision 69585)
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*69585Spendry  *	@(#)union_subr.c	8.20 (Berkeley) 05/20/95
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>
2467065Spendry #include <sys/mount.h>
2567784Spendry #include <sys/stat.h>
2667107Spendry #include <vm/vm.h>		/* for vnode_pager_setsize */
2766055Spendry #include <miscfs/union/union.h>
2865934Spendry 
2965992Spendry #ifdef DIAGNOSTIC
3065992Spendry #include <sys/proc.h>
3165992Spendry #endif
3265992Spendry 
3366053Spendry /* must be power of two, otherwise change UNION_HASH() */
3466053Spendry #define NHASH 32
3565934Spendry 
3666053Spendry /* unsigned int ... */
3766053Spendry #define UNION_HASH(u, l) \
3866053Spendry 	(((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1))
3966053Spendry 
LIST_HEAD(unhead,union_node)4066053Spendry static LIST_HEAD(unhead, union_node) unhead[NHASH];
4166053Spendry static int unvplock[NHASH];
4266053Spendry 
4365934Spendry int
4465934Spendry union_init()
4565934Spendry {
4666053Spendry 	int i;
4765934Spendry 
4866053Spendry 	for (i = 0; i < NHASH; i++)
4966053Spendry 		LIST_INIT(&unhead[i]);
5066053Spendry 	bzero((caddr_t) unvplock, sizeof(unvplock));
5165934Spendry }
5265934Spendry 
5366053Spendry static int
union_list_lock(ix)5466053Spendry union_list_lock(ix)
5566053Spendry 	int ix;
5666053Spendry {
5766053Spendry 
5866053Spendry 	if (unvplock[ix] & UN_LOCKED) {
5966053Spendry 		unvplock[ix] |= UN_WANT;
6066053Spendry 		sleep((caddr_t) &unvplock[ix], PINOD);
6166053Spendry 		return (1);
6266053Spendry 	}
6366053Spendry 
6466053Spendry 	unvplock[ix] |= UN_LOCKED;
6566053Spendry 
6666053Spendry 	return (0);
6766053Spendry }
6866053Spendry 
6966051Spendry static void
union_list_unlock(ix)7066053Spendry union_list_unlock(ix)
7166053Spendry 	int ix;
7266053Spendry {
7366053Spendry 
7466053Spendry 	unvplock[ix] &= ~UN_LOCKED;
7566053Spendry 
7666053Spendry 	if (unvplock[ix] & UN_WANT) {
7766053Spendry 		unvplock[ix] &= ~UN_WANT;
7866053Spendry 		wakeup((caddr_t) &unvplock[ix]);
7966053Spendry 	}
8066053Spendry }
8166053Spendry 
8266053Spendry void
union_updatevp(un,uppervp,lowervp)8366053Spendry union_updatevp(un, uppervp, lowervp)
8466051Spendry 	struct union_node *un;
8566053Spendry 	struct vnode *uppervp;
8666053Spendry 	struct vnode *lowervp;
8766051Spendry {
8866053Spendry 	int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
8966053Spendry 	int nhash = UNION_HASH(uppervp, lowervp);
9067072Spendry 	int docache = (lowervp != NULLVP || uppervp != NULLVP);
9169390Spendry 	int lhash, hhash, uhash;
9266051Spendry 
9367072Spendry 	/*
9467072Spendry 	 * Ensure locking is ordered from lower to higher
9567072Spendry 	 * to avoid deadlocks.
9667072Spendry 	 */
9767072Spendry 	if (nhash < ohash) {
9869390Spendry 		lhash = nhash;
9969390Spendry 		uhash = ohash;
10069390Spendry 	} else {
10169390Spendry 		lhash = ohash;
10269390Spendry 		uhash = nhash;
10367072Spendry 	}
10466053Spendry 
10569390Spendry 	if (lhash != uhash)
10669390Spendry 		while (union_list_lock(lhash))
10766053Spendry 			continue;
10866053Spendry 
10969390Spendry 	while (union_list_lock(uhash))
11067072Spendry 		continue;
11166053Spendry 
11267072Spendry 	if (ohash != nhash || !docache) {
11367072Spendry 		if (un->un_flags & UN_CACHED) {
11467401Spendry 			un->un_flags &= ~UN_CACHED;
11567072Spendry 			LIST_REMOVE(un, un_cache);
11667072Spendry 		}
11766051Spendry 	}
11866053Spendry 
11967072Spendry 	if (ohash != nhash)
12067072Spendry 		union_list_unlock(ohash);
12167072Spendry 
12266053Spendry 	if (un->un_lowervp != lowervp) {
12366053Spendry 		if (un->un_lowervp) {
12466053Spendry 			vrele(un->un_lowervp);
12566053Spendry 			if (un->un_path) {
12666053Spendry 				free(un->un_path, M_TEMP);
12766053Spendry 				un->un_path = 0;
12866053Spendry 			}
12966053Spendry 			if (un->un_dirvp) {
13066053Spendry 				vrele(un->un_dirvp);
13166053Spendry 				un->un_dirvp = NULLVP;
13266053Spendry 			}
13366053Spendry 		}
13466053Spendry 		un->un_lowervp = lowervp;
13567107Spendry 		un->un_lowersz = VNOVAL;
13666053Spendry 	}
13766053Spendry 
13866053Spendry 	if (un->un_uppervp != uppervp) {
13966053Spendry 		if (un->un_uppervp)
14066053Spendry 			vrele(un->un_uppervp);
14166053Spendry 
14266053Spendry 		un->un_uppervp = uppervp;
14367107Spendry 		un->un_uppersz = VNOVAL;
14466053Spendry 	}
14566053Spendry 
14667072Spendry 	if (docache && (ohash != nhash)) {
14766053Spendry 		LIST_INSERT_HEAD(&unhead[nhash], un, un_cache);
14867072Spendry 		un->un_flags |= UN_CACHED;
14967072Spendry 	}
15066053Spendry 
15166053Spendry 	union_list_unlock(nhash);
15266051Spendry }
15366051Spendry 
15466053Spendry void
union_newlower(un,lowervp)15566053Spendry union_newlower(un, lowervp)
15666053Spendry 	struct union_node *un;
15766053Spendry 	struct vnode *lowervp;
15866053Spendry {
15966053Spendry 
16066053Spendry 	union_updatevp(un, un->un_uppervp, lowervp);
16166053Spendry }
16266053Spendry 
16366053Spendry void
union_newupper(un,uppervp)16466053Spendry union_newupper(un, uppervp)
16566053Spendry 	struct union_node *un;
16666053Spendry 	struct vnode *uppervp;
16766053Spendry {
16866053Spendry 
16966053Spendry 	union_updatevp(un, uppervp, un->un_lowervp);
17066053Spendry }
17166053Spendry 
17265934Spendry /*
17367107Spendry  * Keep track of size changes in the underlying vnodes.
17467107Spendry  * If the size changes, then callback to the vm layer
17567107Spendry  * giving priority to the upper layer size.
17667107Spendry  */
17767107Spendry void
union_newsize(vp,uppersz,lowersz)17867107Spendry union_newsize(vp, uppersz, lowersz)
17967107Spendry 	struct vnode *vp;
18067107Spendry 	off_t uppersz, lowersz;
18167107Spendry {
18267107Spendry 	struct union_node *un;
18367107Spendry 	off_t sz;
18467107Spendry 
18567107Spendry 	/* only interested in regular files */
18667107Spendry 	if (vp->v_type != VREG)
18767107Spendry 		return;
18867107Spendry 
18967107Spendry 	un = VTOUNION(vp);
19067107Spendry 	sz = VNOVAL;
19167107Spendry 
19267107Spendry 	if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) {
19367107Spendry 		un->un_uppersz = uppersz;
19467107Spendry 		if (sz == VNOVAL)
19567107Spendry 			sz = un->un_uppersz;
19667107Spendry 	}
19767107Spendry 
19867107Spendry 	if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) {
19967107Spendry 		un->un_lowersz = lowersz;
20067107Spendry 		if (sz == VNOVAL)
20167107Spendry 			sz = un->un_lowersz;
20267107Spendry 	}
20367107Spendry 
20467107Spendry 	if (sz != VNOVAL) {
20567107Spendry #ifdef UNION_DIAGNOSTIC
20667107Spendry 		printf("union: %s size now %ld\n",
20767107Spendry 			uppersz != VNOVAL ? "upper" : "lower", (long) sz);
20867107Spendry #endif
20967107Spendry 		vnode_pager_setsize(vp, sz);
21067107Spendry 	}
21167107Spendry }
21267107Spendry 
21367107Spendry /*
21465934Spendry  * allocate a union_node/vnode pair.  the vnode is
21565965Spendry  * referenced and locked.  the new vnode is returned
21665965Spendry  * via (vpp).  (mp) is the mountpoint of the union filesystem,
21765965Spendry  * (dvp) is the parent directory where the upper layer object
21865965Spendry  * should exist (but doesn't) and (cnp) is the componentname
21965965Spendry  * information which is partially copied to allow the upper
22065965Spendry  * layer object to be created at a later time.  (uppervp)
22165965Spendry  * and (lowervp) reference the upper and lower layer objects
22265965Spendry  * being mapped.  either, but not both, can be nil.
22366051Spendry  * if supplied, (uppervp) is locked.
22465997Spendry  * the reference is either maintained in the new union_node
22565997Spendry  * object which is allocated, or they are vrele'd.
22665934Spendry  *
22765934Spendry  * all union_nodes are maintained on a singly-linked
22865934Spendry  * list.  new nodes are only allocated when they cannot
22965934Spendry  * be found on this list.  entries on the list are
23065934Spendry  * removed when the vfs reclaim entry is called.
23165934Spendry  *
23265934Spendry  * a single lock is kept for the entire list.  this is
23365934Spendry  * needed because the getnewvnode() function can block
23465934Spendry  * waiting for a vnode to become free, in which case there
23565934Spendry  * may be more than one process trying to get the same
23665934Spendry  * vnode.  this lock is only taken if we are going to
23765934Spendry  * call getnewvnode, since the kernel itself is single-threaded.
23865934Spendry  *
23965934Spendry  * if an entry is found on the list, then call vget() to
24065934Spendry  * take a reference.  this is done because there may be
24165934Spendry  * zero references to it and so it needs to removed from
24265934Spendry  * the vnode free list.
24365934Spendry  */
24465934Spendry int
union_allocvp(vpp,mp,undvp,dvp,cnp,uppervp,lowervp,docache)24568078Spendry union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp, docache)
24665934Spendry 	struct vnode **vpp;
24765934Spendry 	struct mount *mp;
24867415Spendry 	struct vnode *undvp;		/* parent union vnode */
24965934Spendry 	struct vnode *dvp;		/* may be null */
25065934Spendry 	struct componentname *cnp;	/* may be null */
25165934Spendry 	struct vnode *uppervp;		/* may be null */
25265934Spendry 	struct vnode *lowervp;		/* may be null */
25368078Spendry 	int docache;
25465934Spendry {
25565934Spendry 	int error;
25665934Spendry 	struct union_node *un;
25765934Spendry 	struct union_node **pp;
25866053Spendry 	struct vnode *xlowervp = NULLVP;
25967065Spendry 	struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
26066053Spendry 	int hash;
26167065Spendry 	int vflag;
26266053Spendry 	int try;
26365934Spendry 
26466053Spendry 	if (uppervp == NULLVP && lowervp == NULLVP)
26565965Spendry 		panic("union: unidentifiable allocation");
26665965Spendry 
26765965Spendry 	if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) {
26865965Spendry 		xlowervp = lowervp;
26966053Spendry 		lowervp = NULLVP;
27065965Spendry 	}
27165965Spendry 
27267065Spendry 	/* detect the root vnode (and aliases) */
27367065Spendry 	vflag = 0;
27467065Spendry 	if ((uppervp == um->um_uppervp) &&
27567065Spendry 	    ((lowervp == NULLVP) || lowervp == um->um_lowervp)) {
27667065Spendry 		if (lowervp == NULLVP) {
27767065Spendry 			lowervp = um->um_lowervp;
27867167Spendry 			if (lowervp != NULLVP)
27967167Spendry 				VREF(lowervp);
28067065Spendry 		}
28167065Spendry 		vflag = VROOT;
28267065Spendry 	}
28367065Spendry 
28465934Spendry loop:
28568078Spendry 	if (!docache) {
28668078Spendry 		un = 0;
28768078Spendry 	} else for (try = 0; try < 3; try++) {
28866053Spendry 		switch (try) {
28966053Spendry 		case 0:
29066053Spendry 			if (lowervp == NULLVP)
29166053Spendry 				continue;
29266053Spendry 			hash = UNION_HASH(uppervp, lowervp);
29366051Spendry 			break;
29466053Spendry 
29566053Spendry 		case 1:
29666053Spendry 			if (uppervp == NULLVP)
29766053Spendry 				continue;
29866053Spendry 			hash = UNION_HASH(uppervp, NULLVP);
29966053Spendry 			break;
30066053Spendry 
30166053Spendry 		case 2:
30266053Spendry 			if (lowervp == NULLVP)
30366053Spendry 				continue;
30466053Spendry 			hash = UNION_HASH(NULLVP, lowervp);
30566053Spendry 			break;
30666051Spendry 		}
30766053Spendry 
30866053Spendry 		while (union_list_lock(hash))
30966053Spendry 			continue;
31066053Spendry 
31166053Spendry 		for (un = unhead[hash].lh_first; un != 0;
31266053Spendry 					un = un->un_cache.le_next) {
31366053Spendry 			if ((un->un_lowervp == lowervp ||
31466053Spendry 			     un->un_lowervp == NULLVP) &&
31566053Spendry 			    (un->un_uppervp == uppervp ||
31666053Spendry 			     un->un_uppervp == NULLVP) &&
31766053Spendry 			    (UNIONTOV(un)->v_mount == mp)) {
31869447Smckusick 				if (vget(UNIONTOV(un), 0,
31969447Smckusick 				    cnp ? cnp->cn_proc : NULL)) {
32066053Spendry 					union_list_unlock(hash);
32166053Spendry 					goto loop;
32266053Spendry 				}
32366053Spendry 				break;
32466053Spendry 			}
32566053Spendry 		}
32666053Spendry 
32766053Spendry 		union_list_unlock(hash);
32866053Spendry 
32966053Spendry 		if (un)
33066053Spendry 			break;
33166051Spendry 	}
33266027Spendry 
33366051Spendry 	if (un) {
33466051Spendry 		/*
33566051Spendry 		 * Obtain a lock on the union_node.
33666051Spendry 		 * uppervp is locked, though un->un_uppervp
33766051Spendry 		 * may not be.  this doesn't break the locking
33866051Spendry 		 * hierarchy since in the case that un->un_uppervp
33966051Spendry 		 * is not yet locked it will be vrele'd and replaced
34066051Spendry 		 * with uppervp.
34166051Spendry 		 */
34266051Spendry 
34366051Spendry 		if ((dvp != NULLVP) && (uppervp == dvp)) {
34466027Spendry 			/*
34566051Spendry 			 * Access ``.'', so (un) will already
34666051Spendry 			 * be locked.  Since this process has
34766051Spendry 			 * the lock on (uppervp) no other
34866051Spendry 			 * process can hold the lock on (un).
34966027Spendry 			 */
35066051Spendry #ifdef DIAGNOSTIC
35166051Spendry 			if ((un->un_flags & UN_LOCKED) == 0)
35266051Spendry 				panic("union: . not locked");
35366051Spendry 			else if (curproc && un->un_pid != curproc->p_pid &&
35466051Spendry 				    un->un_pid > -1 && curproc->p_pid > -1)
35566051Spendry 				panic("union: allocvp not lock owner");
35666051Spendry #endif
35766051Spendry 		} else {
35866051Spendry 			if (un->un_flags & UN_LOCKED) {
35966051Spendry 				vrele(UNIONTOV(un));
36066051Spendry 				un->un_flags |= UN_WANT;
36166051Spendry 				sleep((caddr_t) &un->un_flags, PINOD);
36266051Spendry 				goto loop;
36365992Spendry 			}
36466051Spendry 			un->un_flags |= UN_LOCKED;
36566027Spendry 
36666051Spendry #ifdef DIAGNOSTIC
36766051Spendry 			if (curproc)
36866051Spendry 				un->un_pid = curproc->p_pid;
36966051Spendry 			else
37066051Spendry 				un->un_pid = -1;
37166051Spendry #endif
37266051Spendry 		}
37366051Spendry 
37466051Spendry 		/*
37566051Spendry 		 * At this point, the union_node is locked,
37666051Spendry 		 * un->un_uppervp may not be locked, and uppervp
37766051Spendry 		 * is locked or nil.
37866051Spendry 		 */
37966051Spendry 
38066051Spendry 		/*
38166051Spendry 		 * Save information about the upper layer.
38266051Spendry 		 */
38366051Spendry 		if (uppervp != un->un_uppervp) {
38466053Spendry 			union_newupper(un, uppervp);
38566051Spendry 		} else if (uppervp) {
38666051Spendry 			vrele(uppervp);
38766051Spendry 		}
38866051Spendry 
38966051Spendry 		if (un->un_uppervp) {
39066051Spendry 			un->un_flags |= UN_ULOCK;
39166051Spendry 			un->un_flags &= ~UN_KLOCK;
39266051Spendry 		}
39366051Spendry 
39466051Spendry 		/*
39566051Spendry 		 * Save information about the lower layer.
39666051Spendry 		 * This needs to keep track of pathname
39766051Spendry 		 * and directory information which union_vn_create
39866051Spendry 		 * might need.
39966051Spendry 		 */
40066051Spendry 		if (lowervp != un->un_lowervp) {
40166053Spendry 			union_newlower(un, lowervp);
40267575Spendry 			if (cnp && (lowervp != NULLVP)) {
40366051Spendry 				un->un_hash = cnp->cn_hash;
40466051Spendry 				un->un_path = malloc(cnp->cn_namelen+1,
40566051Spendry 						M_TEMP, M_WAITOK);
40666051Spendry 				bcopy(cnp->cn_nameptr, un->un_path,
40766051Spendry 						cnp->cn_namelen);
40866051Spendry 				un->un_path[cnp->cn_namelen] = '\0';
40966051Spendry 				VREF(dvp);
41066051Spendry 				un->un_dirvp = dvp;
41166051Spendry 			}
41266051Spendry 		} else if (lowervp) {
41366051Spendry 			vrele(lowervp);
41465934Spendry 		}
41566051Spendry 		*vpp = UNIONTOV(un);
41666051Spendry 		return (0);
41765934Spendry 	}
41865934Spendry 
41968078Spendry 	if (docache) {
42068078Spendry 		/*
42168078Spendry 		 * otherwise lock the vp list while we call getnewvnode
42268078Spendry 		 * since that can block.
42368078Spendry 		 */
42468078Spendry 		hash = UNION_HASH(uppervp, lowervp);
42566053Spendry 
42668078Spendry 		if (union_list_lock(hash))
42768078Spendry 			goto loop;
42868078Spendry 	}
42965934Spendry 
43065934Spendry 	error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp);
43166051Spendry 	if (error) {
43266051Spendry 		if (uppervp) {
43366051Spendry 			if (dvp == uppervp)
43466051Spendry 				vrele(uppervp);
43566051Spendry 			else
43666051Spendry 				vput(uppervp);
43766051Spendry 		}
43866051Spendry 		if (lowervp)
43966051Spendry 			vrele(lowervp);
44066051Spendry 
44165934Spendry 		goto out;
44266051Spendry 	}
44365934Spendry 
44465934Spendry 	MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),
44565934Spendry 		M_TEMP, M_WAITOK);
44665934Spendry 
44767065Spendry 	(*vpp)->v_flag |= vflag;
44865965Spendry 	if (uppervp)
44965965Spendry 		(*vpp)->v_type = uppervp->v_type;
45065965Spendry 	else
45165965Spendry 		(*vpp)->v_type = lowervp->v_type;
45265934Spendry 	un = VTOUNION(*vpp);
45365992Spendry 	un->un_vnode = *vpp;
45465934Spendry 	un->un_uppervp = uppervp;
45567107Spendry 	un->un_uppersz = VNOVAL;
45665934Spendry 	un->un_lowervp = lowervp;
45767107Spendry 	un->un_lowersz = VNOVAL;
45867415Spendry 	un->un_pvp = undvp;
45967415Spendry 	if (undvp != NULLVP)
46067415Spendry 		VREF(undvp);
46168078Spendry 	un->un_dircache = 0;
46266028Spendry 	un->un_openl = 0;
46366051Spendry 	un->un_flags = UN_LOCKED;
46466051Spendry 	if (un->un_uppervp)
46566051Spendry 		un->un_flags |= UN_ULOCK;
46666051Spendry #ifdef DIAGNOSTIC
46766051Spendry 	if (curproc)
46866051Spendry 		un->un_pid = curproc->p_pid;
46966051Spendry 	else
47066051Spendry 		un->un_pid = -1;
47166051Spendry #endif
47267575Spendry 	if (cnp && (lowervp != NULLVP)) {
47366027Spendry 		un->un_hash = cnp->cn_hash;
47465934Spendry 		un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
47565934Spendry 		bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
47665934Spendry 		un->un_path[cnp->cn_namelen] = '\0';
47765965Spendry 		VREF(dvp);
47865965Spendry 		un->un_dirvp = dvp;
47965934Spendry 	} else {
48066027Spendry 		un->un_hash = 0;
48165934Spendry 		un->un_path = 0;
48265965Spendry 		un->un_dirvp = 0;
48365934Spendry 	}
48465934Spendry 
48568078Spendry 	if (docache) {
48668078Spendry 		LIST_INSERT_HEAD(&unhead[hash], un, un_cache);
48768078Spendry 		un->un_flags |= UN_CACHED;
48868078Spendry 	}
48965934Spendry 
49065965Spendry 	if (xlowervp)
49165965Spendry 		vrele(xlowervp);
49265965Spendry 
49365934Spendry out:
49468078Spendry 	if (docache)
49568078Spendry 		union_list_unlock(hash);
49665934Spendry 
49765934Spendry 	return (error);
49865934Spendry }
49965934Spendry 
50065934Spendry int
union_freevp(vp)50165934Spendry union_freevp(vp)
50265934Spendry 	struct vnode *vp;
50365934Spendry {
50465934Spendry 	struct union_node *un = VTOUNION(vp);
50565934Spendry 
50667072Spendry 	if (un->un_flags & UN_CACHED) {
50767401Spendry 		un->un_flags &= ~UN_CACHED;
50867072Spendry 		LIST_REMOVE(un, un_cache);
50967072Spendry 	}
51065934Spendry 
51167415Spendry 	if (un->un_pvp != NULLVP)
51267415Spendry 		vrele(un->un_pvp);
51367072Spendry 	if (un->un_uppervp != NULLVP)
51466053Spendry 		vrele(un->un_uppervp);
51567072Spendry 	if (un->un_lowervp != NULLVP)
51666053Spendry 		vrele(un->un_lowervp);
51767072Spendry 	if (un->un_dirvp != NULLVP)
51866053Spendry 		vrele(un->un_dirvp);
51966053Spendry 	if (un->un_path)
52066053Spendry 		free(un->un_path, M_TEMP);
52166053Spendry 
52265934Spendry 	FREE(vp->v_data, M_TEMP);
52365934Spendry 	vp->v_data = 0;
52466053Spendry 
52565934Spendry 	return (0);
52665934Spendry }
52765994Spendry 
52865994Spendry /*
52965994Spendry  * copyfile.  copy the vnode (fvp) to the vnode (tvp)
53065994Spendry  * using a sequence of reads and writes.  both (fvp)
53165994Spendry  * and (tvp) are locked on entry and exit.
53265994Spendry  */
53365994Spendry int
union_copyfile(fvp,tvp,cred,p)53467166Spendry union_copyfile(fvp, tvp, cred, p)
53565994Spendry 	struct vnode *fvp;
53665994Spendry 	struct vnode *tvp;
53767166Spendry 	struct ucred *cred;
53867166Spendry 	struct proc *p;
53965994Spendry {
54065994Spendry 	char *buf;
54165994Spendry 	struct uio uio;
54265994Spendry 	struct iovec iov;
54365994Spendry 	int error = 0;
54465994Spendry 
54565994Spendry 	/*
54665994Spendry 	 * strategy:
54765994Spendry 	 * allocate a buffer of size MAXBSIZE.
54865994Spendry 	 * loop doing reads and writes, keeping track
54965994Spendry 	 * of the current uio offset.
55065994Spendry 	 * give up at the first sign of trouble.
55165994Spendry 	 */
55265994Spendry 
55365994Spendry 	uio.uio_procp = p;
55465994Spendry 	uio.uio_segflg = UIO_SYSSPACE;
55565994Spendry 	uio.uio_offset = 0;
55665994Spendry 
55769447Smckusick 	VOP_UNLOCK(fvp, 0, p);				/* XXX */
55867750Spendry 	VOP_LEASE(fvp, p, cred, LEASE_READ);
55969447Smckusick 	vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);	/* XXX */
56069447Smckusick 	VOP_UNLOCK(tvp, 0, p);				/* XXX */
56167750Spendry 	VOP_LEASE(tvp, p, cred, LEASE_WRITE);
56269447Smckusick 	vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);	/* XXX */
56365994Spendry 
56465994Spendry 	buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
56565994Spendry 
56665994Spendry 	/* ugly loop follows... */
56765994Spendry 	do {
56865994Spendry 		off_t offset = uio.uio_offset;
56965994Spendry 
57065994Spendry 		uio.uio_iov = &iov;
57165994Spendry 		uio.uio_iovcnt = 1;
57265994Spendry 		iov.iov_base = buf;
57365994Spendry 		iov.iov_len = MAXBSIZE;
57465994Spendry 		uio.uio_resid = iov.iov_len;
57565994Spendry 		uio.uio_rw = UIO_READ;
57665994Spendry 		error = VOP_READ(fvp, &uio, 0, cred);
57765994Spendry 
57865994Spendry 		if (error == 0) {
57965994Spendry 			uio.uio_iov = &iov;
58065994Spendry 			uio.uio_iovcnt = 1;
58165994Spendry 			iov.iov_base = buf;
58265994Spendry 			iov.iov_len = MAXBSIZE - uio.uio_resid;
58365994Spendry 			uio.uio_offset = offset;
58465994Spendry 			uio.uio_rw = UIO_WRITE;
58565994Spendry 			uio.uio_resid = iov.iov_len;
58665994Spendry 
58765994Spendry 			if (uio.uio_resid == 0)
58865994Spendry 				break;
58965994Spendry 
59065994Spendry 			do {
59165994Spendry 				error = VOP_WRITE(tvp, &uio, 0, cred);
59265994Spendry 			} while ((uio.uio_resid > 0) && (error == 0));
59365994Spendry 		}
59465994Spendry 
59565994Spendry 	} while (error == 0);
59665994Spendry 
59765994Spendry 	free(buf, M_TEMP);
59865994Spendry 	return (error);
59965994Spendry }
60065994Spendry 
60165994Spendry /*
60267166Spendry  * (un) is assumed to be locked on entry and remains
60367166Spendry  * locked on exit.
60467166Spendry  */
60567166Spendry int
union_copyup(un,docopy,cred,p)60667166Spendry union_copyup(un, docopy, cred, p)
60767166Spendry 	struct union_node *un;
60867166Spendry 	int docopy;
60967166Spendry 	struct ucred *cred;
61067166Spendry 	struct proc *p;
61167166Spendry {
61267166Spendry 	int error;
61367166Spendry 	struct vnode *lvp, *uvp;
61467166Spendry 
61567166Spendry 	error = union_vn_create(&uvp, un, p);
61667166Spendry 	if (error)
61767166Spendry 		return (error);
61867166Spendry 
61967166Spendry 	/* at this point, uppervp is locked */
62067166Spendry 	union_newupper(un, uvp);
62167166Spendry 	un->un_flags |= UN_ULOCK;
62267166Spendry 
62367166Spendry 	lvp = un->un_lowervp;
62467166Spendry 
62567166Spendry 	if (docopy) {
62667166Spendry 		/*
62767166Spendry 		 * XX - should not ignore errors
62867166Spendry 		 * from VOP_CLOSE
62967166Spendry 		 */
63069447Smckusick 		vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p);
63167166Spendry 		error = VOP_OPEN(lvp, FREAD, cred, p);
63267166Spendry 		if (error == 0) {
63367166Spendry 			error = union_copyfile(lvp, uvp, cred, p);
63469447Smckusick 			VOP_UNLOCK(lvp, 0, p);
63568514Smckusick 			(void) VOP_CLOSE(lvp, FREAD, cred, p);
63667166Spendry 		}
63767166Spendry #ifdef UNION_DIAGNOSTIC
63867166Spendry 		if (error == 0)
63967166Spendry 			uprintf("union: copied up %s\n", un->un_path);
64067166Spendry #endif
64167166Spendry 
64267166Spendry 	}
64367166Spendry 	un->un_flags &= ~UN_ULOCK;
64469447Smckusick 	VOP_UNLOCK(uvp, 0, p);
64567166Spendry 	union_vn_close(uvp, FWRITE, cred, p);
64669447Smckusick 	vn_lock(uvp, LK_EXCLUSIVE | LK_RETRY, p);
64767166Spendry 	un->un_flags |= UN_ULOCK;
64867166Spendry 
64967166Spendry 	/*
65067166Spendry 	 * Subsequent IOs will go to the top layer, so
65167166Spendry 	 * call close on the lower vnode and open on the
65267166Spendry 	 * upper vnode to ensure that the filesystem keeps
65367166Spendry 	 * its references counts right.  This doesn't do
65467166Spendry 	 * the right thing with (cred) and (FREAD) though.
65567166Spendry 	 * Ignoring error returns is not right, either.
65667166Spendry 	 */
65767166Spendry 	if (error == 0) {
65867166Spendry 		int i;
65967166Spendry 
66067166Spendry 		for (i = 0; i < un->un_openl; i++) {
66168514Smckusick 			(void) VOP_CLOSE(lvp, FREAD, cred, p);
66267166Spendry 			(void) VOP_OPEN(uvp, FREAD, cred, p);
66367166Spendry 		}
66467166Spendry 		un->un_openl = 0;
66567166Spendry 	}
66667166Spendry 
66767166Spendry 	return (error);
66867166Spendry 
66967166Spendry }
67067166Spendry 
67167575Spendry static int
union_relookup(um,dvp,vpp,cnp,cn,path,pathlen)67267750Spendry union_relookup(um, dvp, vpp, cnp, cn, path, pathlen)
67367575Spendry 	struct union_mount *um;
67467575Spendry 	struct vnode *dvp;
67567575Spendry 	struct vnode **vpp;
67667575Spendry 	struct componentname *cnp;
67767575Spendry 	struct componentname *cn;
67867575Spendry 	char *path;
67967750Spendry 	int pathlen;
68067575Spendry {
68167575Spendry 	int error;
68267575Spendry 
68367575Spendry 	/*
68467575Spendry 	 * A new componentname structure must be faked up because
68567575Spendry 	 * there is no way to know where the upper level cnp came
68667575Spendry 	 * from or what it is being used for.  This must duplicate
68767575Spendry 	 * some of the work done by NDINIT, some of the work done
68867575Spendry 	 * by namei, some of the work done by lookup and some of
68967575Spendry 	 * the work done by VOP_LOOKUP when given a CREATE flag.
69067575Spendry 	 * Conclusion: Horrible.
69167575Spendry 	 *
69267575Spendry 	 * The pathname buffer will be FREEed by VOP_MKDIR.
69367575Spendry 	 */
69467750Spendry 	cn->cn_namelen = pathlen;
69567575Spendry 	cn->cn_pnbuf = malloc(cn->cn_namelen+1, M_NAMEI, M_WAITOK);
69667575Spendry 	bcopy(path, cn->cn_pnbuf, cn->cn_namelen);
69767575Spendry 	cn->cn_pnbuf[cn->cn_namelen] = '\0';
69867575Spendry 
69967575Spendry 	cn->cn_nameiop = CREATE;
70067575Spendry 	cn->cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
70167575Spendry 	cn->cn_proc = cnp->cn_proc;
70267575Spendry 	if (um->um_op == UNMNT_ABOVE)
70367575Spendry 		cn->cn_cred = cnp->cn_cred;
70467575Spendry 	else
70567575Spendry 		cn->cn_cred = um->um_cred;
70667575Spendry 	cn->cn_nameptr = cn->cn_pnbuf;
70767575Spendry 	cn->cn_hash = cnp->cn_hash;
70867575Spendry 	cn->cn_consume = cnp->cn_consume;
70967575Spendry 
71067575Spendry 	VREF(dvp);
71167575Spendry 	error = relookup(dvp, vpp, cn);
71267575Spendry 	if (!error)
71367575Spendry 		vrele(dvp);
71467575Spendry 
71567575Spendry 	return (error);
71667575Spendry }
71767575Spendry 
71867166Spendry /*
71965997Spendry  * Create a shadow directory in the upper layer.
72065997Spendry  * The new vnode is returned locked.
72165997Spendry  *
72265997Spendry  * (um) points to the union mount structure for access to the
72365997Spendry  * the mounting process's credentials.
72465997Spendry  * (dvp) is the directory in which to create the shadow directory.
72565997Spendry  * it is unlocked on entry and exit.
72665997Spendry  * (cnp) is the componentname to be created.
72765997Spendry  * (vpp) is the returned newly created shadow directory, which
72865997Spendry  * is returned locked.
72965997Spendry  */
73065997Spendry int
union_mkshadow(um,dvp,cnp,vpp)73165997Spendry union_mkshadow(um, dvp, cnp, vpp)
73265997Spendry 	struct union_mount *um;
73365997Spendry 	struct vnode *dvp;
73465997Spendry 	struct componentname *cnp;
73565997Spendry 	struct vnode **vpp;
73665997Spendry {
73765997Spendry 	int error;
73865997Spendry 	struct vattr va;
73965997Spendry 	struct proc *p = cnp->cn_proc;
74065997Spendry 	struct componentname cn;
74165997Spendry 
74267750Spendry 	error = union_relookup(um, dvp, vpp, cnp, &cn,
74367750Spendry 			cnp->cn_nameptr, cnp->cn_namelen);
74467575Spendry 	if (error)
74567575Spendry 		return (error);
74667575Spendry 
74767575Spendry 	if (*vpp) {
74867575Spendry 		VOP_ABORTOP(dvp, &cn);
74969447Smckusick 		VOP_UNLOCK(dvp, 0, p);
75067575Spendry 		vrele(*vpp);
75167575Spendry 		*vpp = NULLVP;
75267575Spendry 		return (EEXIST);
75367575Spendry 	}
75467575Spendry 
75565997Spendry 	/*
75665997Spendry 	 * policy: when creating the shadow directory in the
75766034Spendry 	 * upper layer, create it owned by the user who did
75866034Spendry 	 * the mount, group from parent directory, and mode
75966034Spendry 	 * 777 modified by umask (ie mostly identical to the
76066034Spendry 	 * mkdir syscall).  (jsp, kb)
76165997Spendry 	 */
76265997Spendry 
76367575Spendry 	VATTR_NULL(&va);
76467575Spendry 	va.va_type = VDIR;
76567575Spendry 	va.va_mode = um->um_cmode;
76665997Spendry 
76767750Spendry 	/* VOP_LEASE: dvp is locked */
76867750Spendry 	VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE);
76965997Spendry 
77067575Spendry 	error = VOP_MKDIR(dvp, vpp, &cn, &va);
77167575Spendry 	return (error);
77267575Spendry }
77367575Spendry 
77467575Spendry /*
77567575Spendry  * Create a whiteout entry in the upper layer.
77667575Spendry  *
77767575Spendry  * (um) points to the union mount structure for access to the
77867575Spendry  * the mounting process's credentials.
77967575Spendry  * (dvp) is the directory in which to create the whiteout.
78067575Spendry  * it is locked on entry and exit.
78167575Spendry  * (cnp) is the componentname to be created.
78267575Spendry  */
78367575Spendry int
union_mkwhiteout(um,dvp,cnp,path)78467575Spendry union_mkwhiteout(um, dvp, cnp, path)
78567575Spendry 	struct union_mount *um;
78667575Spendry 	struct vnode *dvp;
78767575Spendry 	struct componentname *cnp;
78867575Spendry 	char *path;
78967575Spendry {
79067575Spendry 	int error;
79167575Spendry 	struct vattr va;
79267575Spendry 	struct proc *p = cnp->cn_proc;
79368022Spendry 	struct vnode *wvp;
79467575Spendry 	struct componentname cn;
79567575Spendry 
79669447Smckusick 	VOP_UNLOCK(dvp, 0, p);
79768022Spendry 	error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path));
79867750Spendry 	if (error) {
79969447Smckusick 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
80065997Spendry 		return (error);
80167750Spendry 	}
80265997Spendry 
80368022Spendry 	if (wvp) {
80465997Spendry 		VOP_ABORTOP(dvp, &cn);
80567575Spendry 		vrele(dvp);
80668022Spendry 		vrele(wvp);
80765997Spendry 		return (EEXIST);
80865997Spendry 	}
80965997Spendry 
81067750Spendry 	/* VOP_LEASE: dvp is locked */
81167750Spendry 	VOP_LEASE(dvp, p, p->p_ucred, LEASE_WRITE);
81265997Spendry 
81367575Spendry 	error = VOP_WHITEOUT(dvp, &cn, CREATE);
81467750Spendry 	if (error)
81567575Spendry 		VOP_ABORTOP(dvp, &cn);
81667575Spendry 
81767575Spendry 	vrele(dvp);
81867575Spendry 
81965997Spendry 	return (error);
82065997Spendry }
82165997Spendry 
82265997Spendry /*
82365994Spendry  * union_vn_create: creates and opens a new shadow file
82465994Spendry  * on the upper union layer.  this function is similar
82565994Spendry  * in spirit to calling vn_open but it avoids calling namei().
82665994Spendry  * the problem with calling namei is that a) it locks too many
82765994Spendry  * things, and b) it doesn't start at the "right" directory,
82865994Spendry  * whereas relookup is told where to start.
82965994Spendry  */
83065994Spendry int
union_vn_create(vpp,un,p)83165997Spendry union_vn_create(vpp, un, p)
83265994Spendry 	struct vnode **vpp;
83365994Spendry 	struct union_node *un;
83465994Spendry 	struct proc *p;
83565994Spendry {
83665994Spendry 	struct vnode *vp;
83765994Spendry 	struct ucred *cred = p->p_ucred;
83865994Spendry 	struct vattr vat;
83965994Spendry 	struct vattr *vap = &vat;
84065994Spendry 	int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL);
84165994Spendry 	int error;
84266027Spendry 	int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask;
84365994Spendry 	char *cp;
84465994Spendry 	struct componentname cn;
84565994Spendry 
84665994Spendry 	*vpp = NULLVP;
84765994Spendry 
84866034Spendry 	/*
84966034Spendry 	 * Build a new componentname structure (for the same
85066034Spendry 	 * reasons outlines in union_mkshadow).
85166034Spendry 	 * The difference here is that the file is owned by
85266034Spendry 	 * the current user, rather than by the person who
85366034Spendry 	 * did the mount, since the current user needs to be
85466034Spendry 	 * able to write the file (that's why it is being
85566034Spendry 	 * copied in the first place).
85666034Spendry 	 */
85765994Spendry 	cn.cn_namelen = strlen(un->un_path);
85865994Spendry 	cn.cn_pnbuf = (caddr_t) malloc(cn.cn_namelen, M_NAMEI, M_WAITOK);
85965994Spendry 	bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1);
86065994Spendry 	cn.cn_nameiop = CREATE;
86166060Spendry 	cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);
86265994Spendry 	cn.cn_proc = p;
86365994Spendry 	cn.cn_cred = p->p_ucred;
86465994Spendry 	cn.cn_nameptr = cn.cn_pnbuf;
86566027Spendry 	cn.cn_hash = un->un_hash;
86665994Spendry 	cn.cn_consume = 0;
86765994Spendry 
86866027Spendry 	VREF(un->un_dirvp);
86965994Spendry 	if (error = relookup(un->un_dirvp, &vp, &cn))
87065994Spendry 		return (error);
87166027Spendry 	vrele(un->un_dirvp);
87266027Spendry 
87366060Spendry 	if (vp) {
87465994Spendry 		VOP_ABORTOP(un->un_dirvp, &cn);
87565994Spendry 		if (un->un_dirvp == vp)
87665994Spendry 			vrele(un->un_dirvp);
87765994Spendry 		else
87866060Spendry 			vput(un->un_dirvp);
87966060Spendry 		vrele(vp);
88066060Spendry 		return (EEXIST);
88165994Spendry 	}
88265994Spendry 
88366060Spendry 	/*
88466060Spendry 	 * Good - there was no race to create the file
88566060Spendry 	 * so go ahead and create it.  The permissions
88666060Spendry 	 * on the file will be 0666 modified by the
88766060Spendry 	 * current user's umask.  Access to the file, while
88866060Spendry 	 * it is unioned, will require access to the top *and*
88966060Spendry 	 * bottom files.  Access when not unioned will simply
89066060Spendry 	 * require access to the top-level file.
89166060Spendry 	 * TODO: confirm choice of access permissions.
89266060Spendry 	 */
89365994Spendry 	VATTR_NULL(vap);
89466060Spendry 	vap->va_type = VREG;
89566060Spendry 	vap->va_mode = cmode;
89667750Spendry 	VOP_LEASE(un->un_dirvp, p, cred, LEASE_WRITE);
89766060Spendry 	if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap))
89866060Spendry 		return (error);
89965994Spendry 
90066060Spendry 	if (error = VOP_OPEN(vp, fmode, cred, p)) {
90166060Spendry 		vput(vp);
90266060Spendry 		return (error);
90366060Spendry 	}
90465994Spendry 
90565994Spendry 	vp->v_writecount++;
90665994Spendry 	*vpp = vp;
90765994Spendry 	return (0);
90865994Spendry }
90966027Spendry 
91066027Spendry int
union_vn_close(vp,fmode,cred,p)91166028Spendry union_vn_close(vp, fmode, cred, p)
91266027Spendry 	struct vnode *vp;
91366027Spendry 	int fmode;
91466028Spendry 	struct ucred *cred;
91566028Spendry 	struct proc *p;
91666027Spendry {
91767575Spendry 
91866027Spendry 	if (fmode & FWRITE)
91966027Spendry 		--vp->v_writecount;
92068514Smckusick 	return (VOP_CLOSE(vp, fmode, cred, p));
92166027Spendry }
92266027Spendry 
92366027Spendry void
union_removed_upper(un)92466027Spendry union_removed_upper(un)
92566027Spendry 	struct union_node *un;
92666027Spendry {
92769447Smckusick 	struct proc *p = curproc;	/* XXX */
92867401Spendry 
92969390Spendry 	union_newupper(un, NULLVP);
93069390Spendry 	if (un->un_flags & UN_CACHED) {
93169390Spendry 		un->un_flags &= ~UN_CACHED;
93269390Spendry 		LIST_REMOVE(un, un_cache);
93369390Spendry 	}
93469390Spendry 
93566051Spendry 	if (un->un_flags & UN_ULOCK) {
93666051Spendry 		un->un_flags &= ~UN_ULOCK;
93769447Smckusick 		VOP_UNLOCK(un->un_uppervp, 0, p);
93866051Spendry 	}
93966027Spendry }
94066028Spendry 
94168078Spendry #if 0
94266028Spendry struct vnode *
94366028Spendry union_lowervp(vp)
94466028Spendry 	struct vnode *vp;
94566028Spendry {
94666028Spendry 	struct union_node *un = VTOUNION(vp);
94766028Spendry 
94867166Spendry 	if ((un->un_lowervp != NULLVP) &&
94967166Spendry 	    (vp->v_type == un->un_lowervp->v_type)) {
95067166Spendry 		if (vget(un->un_lowervp, 0) == 0)
95167166Spendry 			return (un->un_lowervp);
95266028Spendry 	}
95366028Spendry 
95467166Spendry 	return (NULLVP);
95566028Spendry }
95668078Spendry #endif
95767784Spendry 
95867784Spendry /*
95967784Spendry  * determine whether a whiteout is needed
96067784Spendry  * during a remove/rmdir operation.
96167784Spendry  */
96267784Spendry int
union_dowhiteout(un,cred,p)96367784Spendry union_dowhiteout(un, cred, p)
96467784Spendry 	struct union_node *un;
96567784Spendry 	struct ucred *cred;
96667784Spendry 	struct proc *p;
96767784Spendry {
96867784Spendry 	struct vattr va;
96967784Spendry 
97067784Spendry 	if (un->un_lowervp != NULLVP)
97167784Spendry 		return (1);
97267784Spendry 
97367784Spendry 	if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 &&
97467784Spendry 	    (va.va_flags & OPAQUE))
97567784Spendry 		return (1);
97667784Spendry 
97767784Spendry 	return (0);
97867784Spendry }
97968078Spendry 
98068078Spendry static void
union_dircache_r(vp,vppp,cntp)98168078Spendry union_dircache_r(vp, vppp, cntp)
98268078Spendry 	struct vnode *vp;
98368078Spendry 	struct vnode ***vppp;
98468078Spendry 	int *cntp;
98568078Spendry {
98668078Spendry 	struct union_node *un;
98768078Spendry 
98868078Spendry 	if (vp->v_op != union_vnodeop_p) {
98968078Spendry 		if (vppp) {
99068078Spendry 			VREF(vp);
99168078Spendry 			*(*vppp)++ = vp;
99268078Spendry 			if (--(*cntp) == 0)
99368078Spendry 				panic("union: dircache table too small");
99468078Spendry 		} else {
99568078Spendry 			(*cntp)++;
99668078Spendry 		}
99768078Spendry 
99868078Spendry 		return;
99968078Spendry 	}
100068078Spendry 
100168078Spendry 	un = VTOUNION(vp);
100268078Spendry 	if (un->un_uppervp != NULLVP)
100368078Spendry 		union_dircache_r(un->un_uppervp, vppp, cntp);
100468078Spendry 	if (un->un_lowervp != NULLVP)
100568078Spendry 		union_dircache_r(un->un_lowervp, vppp, cntp);
100668078Spendry }
100768078Spendry 
100868078Spendry struct vnode *
union_dircache(vp,p)100969447Smckusick union_dircache(vp, p)
101068078Spendry 	struct vnode *vp;
101169447Smckusick 	struct proc *p;
101268078Spendry {
101368078Spendry 	int cnt;
101468078Spendry 	struct vnode *nvp;
101568078Spendry 	struct vnode **vpp;
1016*69585Spendry 	struct vnode **dircache;
101768078Spendry 	struct union_node *un;
101868078Spendry 	int error;
101968078Spendry 
1020*69585Spendry 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1021*69585Spendry 	dircache = VTOUNION(vp)->un_dircache;
1022*69585Spendry 
1023*69585Spendry 	nvp = NULLVP;
1024*69585Spendry 
102568078Spendry 	if (dircache == 0) {
102668078Spendry 		cnt = 0;
102768078Spendry 		union_dircache_r(vp, 0, &cnt);
102868078Spendry 		cnt++;
102968078Spendry 		dircache = (struct vnode **)
103068078Spendry 				malloc(cnt * sizeof(struct vnode *),
103168078Spendry 					M_TEMP, M_WAITOK);
103268078Spendry 		vpp = dircache;
103368078Spendry 		union_dircache_r(vp, &vpp, &cnt);
103468078Spendry 		*vpp = NULLVP;
103568078Spendry 		vpp = dircache + 1;
103668078Spendry 	} else {
103768078Spendry 		vpp = dircache;
103868078Spendry 		do {
103968078Spendry 			if (*vpp++ == VTOUNION(vp)->un_uppervp)
104068078Spendry 				break;
104168078Spendry 		} while (*vpp != NULLVP);
104268078Spendry 	}
104368078Spendry 
104468078Spendry 	if (*vpp == NULLVP)
1045*69585Spendry 		goto out;
104668078Spendry 
104769447Smckusick 	vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p);
104868078Spendry 	VREF(*vpp);
104968078Spendry 	error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0);
105068078Spendry 	if (error)
1051*69585Spendry 		goto out;
1052*69585Spendry 
105368078Spendry 	VTOUNION(vp)->un_dircache = 0;
105468078Spendry 	un = VTOUNION(nvp);
105568078Spendry 	un->un_dircache = dircache;
105668078Spendry 
1057*69585Spendry out:
1058*69585Spendry 	VOP_UNLOCK(vp, 0, p);
105968078Spendry 	return (nvp);
106068078Spendry }
1061