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