xref: /csrg-svn/sys/miscfs/union/union_subr.c (revision 65934)
1*65934Spendry /*
2*65934Spendry  * Copyright (c) 1994 Jan-Simon Pendry
3*65934Spendry  * Copyright (c) 1994
4*65934Spendry  *	The Regents of the University of California.  All rights reserved.
5*65934Spendry  *
6*65934Spendry  * This code is derived from software contributed to Berkeley by
7*65934Spendry  * Jan-Simon Pendry.
8*65934Spendry  *
9*65934Spendry  * %sccs.include.redist.c%
10*65934Spendry  *
11*65934Spendry  *	@(#)union_subr.c	1.1 (Berkeley) 01/28/94
12*65934Spendry  */
13*65934Spendry 
14*65934Spendry #include <sys/param.h>
15*65934Spendry #include <sys/systm.h>
16*65934Spendry #include <sys/time.h>
17*65934Spendry #include <sys/kernel.h>
18*65934Spendry #include <sys/vnode.h>
19*65934Spendry #include <sys/namei.h>
20*65934Spendry #include <sys/malloc.h>
21*65934Spendry #include "union.h" /*<miscfs/union/union.h>*/
22*65934Spendry 
23*65934Spendry static struct union_node *unhead;
24*65934Spendry static int unvplock;
25*65934Spendry 
26*65934Spendry int
27*65934Spendry union_init()
28*65934Spendry {
29*65934Spendry 
30*65934Spendry 	unhead = 0;
31*65934Spendry 	unvplock = 0;
32*65934Spendry }
33*65934Spendry 
34*65934Spendry /*
35*65934Spendry  * allocate a union_node/vnode pair.  the vnode is
36*65934Spendry  * referenced and locked.
37*65934Spendry  *
38*65934Spendry  * all union_nodes are maintained on a singly-linked
39*65934Spendry  * list.  new nodes are only allocated when they cannot
40*65934Spendry  * be found on this list.  entries on the list are
41*65934Spendry  * removed when the vfs reclaim entry is called.
42*65934Spendry  *
43*65934Spendry  * a single lock is kept for the entire list.  this is
44*65934Spendry  * needed because the getnewvnode() function can block
45*65934Spendry  * waiting for a vnode to become free, in which case there
46*65934Spendry  * may be more than one process trying to get the same
47*65934Spendry  * vnode.  this lock is only taken if we are going to
48*65934Spendry  * call getnewvnode, since the kernel itself is single-threaded.
49*65934Spendry  *
50*65934Spendry  * if an entry is found on the list, then call vget() to
51*65934Spendry  * take a reference.  this is done because there may be
52*65934Spendry  * zero references to it and so it needs to removed from
53*65934Spendry  * the vnode free list.
54*65934Spendry  */
55*65934Spendry int
56*65934Spendry union_allocvp(vpp, mp, dvp, cnp, uppervp, lowervp)
57*65934Spendry 	struct vnode **vpp;
58*65934Spendry 	struct mount *mp;
59*65934Spendry 	struct vnode *dvp;		/* may be null */
60*65934Spendry 	struct componentname *cnp;	/* may be null */
61*65934Spendry 	struct vnode *uppervp;		/* may be null */
62*65934Spendry 	struct vnode *lowervp;		/* may be null */
63*65934Spendry {
64*65934Spendry 	int error;
65*65934Spendry 	struct union_node *un;
66*65934Spendry 	struct union_node **pp;
67*65934Spendry 
68*65934Spendry loop:
69*65934Spendry 	for (un = unhead; un != 0; un = un->un_next) {
70*65934Spendry 		if ((un->un_lowervp == lowervp ||
71*65934Spendry 		     un->un_lowervp == 0) &&
72*65934Spendry 		    (un->un_uppervp == uppervp ||
73*65934Spendry 		     un->un_uppervp == 0) &&
74*65934Spendry 		    (UNIONTOV(un)->v_mount == mp)) {
75*65934Spendry 			if (vget(un->un_vnode, 1))
76*65934Spendry 				goto loop;
77*65934Spendry 			un->un_lowervp = lowervp;
78*65934Spendry 			un->un_uppervp = uppervp;
79*65934Spendry 			*vpp = un->un_vnode;
80*65934Spendry 			return (0);
81*65934Spendry 		}
82*65934Spendry 	}
83*65934Spendry 
84*65934Spendry 	/*
85*65934Spendry 	 * otherwise lock the vp list while we call getnewvnode
86*65934Spendry 	 * since that can block.
87*65934Spendry 	 */
88*65934Spendry 	if (unvplock & UN_LOCKED) {
89*65934Spendry 		unvplock |= UN_WANT;
90*65934Spendry 		sleep((caddr_t) &unvplock, PINOD);
91*65934Spendry 		goto loop;
92*65934Spendry 	}
93*65934Spendry 	unvplock |= UN_LOCKED;
94*65934Spendry 
95*65934Spendry 	error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp);
96*65934Spendry 	if (error)
97*65934Spendry 		goto out;
98*65934Spendry 
99*65934Spendry 	MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),
100*65934Spendry 		M_TEMP, M_WAITOK);
101*65934Spendry 
102*65934Spendry 	un = VTOUNION(*vpp);
103*65934Spendry 	un->un_next = 0;
104*65934Spendry 	un->un_dirvp = dvp;
105*65934Spendry 	un->un_uppervp = uppervp;
106*65934Spendry 	un->un_lowervp = lowervp;
107*65934Spendry 	un->un_vnode = *vpp;
108*65934Spendry 	un->un_flags = 0;
109*65934Spendry 	if (cnp) {
110*65934Spendry 		un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);
111*65934Spendry 		bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);
112*65934Spendry 		un->un_path[cnp->cn_namelen] = '\0';
113*65934Spendry 	} else {
114*65934Spendry 		un->un_path = 0;
115*65934Spendry 	}
116*65934Spendry 
117*65934Spendry #ifdef DIAGNOSTIC
118*65934Spendry 	un->un_pid = 0;
119*65934Spendry #endif
120*65934Spendry 
121*65934Spendry 	/* add to union vnode list */
122*65934Spendry 	for (pp = &unhead; *pp; pp = &(*pp)->un_next)
123*65934Spendry 		continue;
124*65934Spendry 	*pp = un;
125*65934Spendry 
126*65934Spendry out:
127*65934Spendry 	unvplock &= ~UN_LOCKED;
128*65934Spendry 
129*65934Spendry 	if (unvplock & UN_WANT) {
130*65934Spendry 		unvplock &= ~UN_WANT;
131*65934Spendry 		wakeup((caddr_t) &unvplock);
132*65934Spendry 	}
133*65934Spendry 
134*65934Spendry 	if (un)
135*65934Spendry 		VOP_LOCK(UNIONTOV(un));
136*65934Spendry 
137*65934Spendry 	return (error);
138*65934Spendry }
139*65934Spendry 
140*65934Spendry int
141*65934Spendry union_freevp(vp)
142*65934Spendry 	struct vnode *vp;
143*65934Spendry {
144*65934Spendry 	struct union_node **unpp;
145*65934Spendry 	struct union_node *un = VTOUNION(vp);
146*65934Spendry 
147*65934Spendry 	for (unpp = &unhead; *unpp != 0; unpp = &(*unpp)->un_next) {
148*65934Spendry 		if (*unpp == un) {
149*65934Spendry 			*unpp = un->un_next;
150*65934Spendry 			break;
151*65934Spendry 		}
152*65934Spendry 	}
153*65934Spendry 
154*65934Spendry 	if (un->un_path)
155*65934Spendry 		FREE(un->un_path, M_TEMP);
156*65934Spendry 
157*65934Spendry 	FREE(vp->v_data, M_TEMP);
158*65934Spendry 	vp->v_data = 0;
159*65934Spendry 	return (0);
160*65934Spendry }
161