proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / vfs / nullfs / null_subr.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software donated to Berkeley by
6 * Jan-Simon Pendry.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)null_subr.c 8.7 (Berkeley) 5/14/95
37 *
38 * $FreeBSD: src/sys/miscfs/nullfs/null_subr.c,v 1.21.2.4 2001/06/26 04:20:09 bp Exp $
dadab5e9 39 * $DragonFly: src/sys/vfs/nullfs/Attic/null_subr.c,v 1.3 2003/06/25 03:55:59 dillon Exp $
984263bc
MD
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/kernel.h>
45#include <sys/proc.h>
46#include <sys/vnode.h>
47#include <sys/mount.h>
48#include <sys/malloc.h>
49#include <miscfs/nullfs/null.h>
50
51#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
52#define NNULLNODECACHE 16
53
54/*
55 * Null layer cache:
56 * Each cache entry holds a reference to the lower vnode
57 * along with a pointer to the alias vnode. When an
58 * entry is added the lower vnode is VREF'd. When the
59 * alias is removed the lower vnode is vrele'd.
60 */
61
62#define NULL_NHASH(vp) \
63 (&null_node_hashtbl[(((uintptr_t)vp)>>LOG2_SIZEVNODE) & null_node_hash])
64
65static LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
66static u_long null_node_hash;
67struct lock null_hashlock;
68
69static MALLOC_DEFINE(M_NULLFSHASH, "NULLFS hash", "NULLFS hash table");
70MALLOC_DEFINE(M_NULLFSNODE, "NULLFS node", "NULLFS vnode private part");
71
72static int null_node_alloc(struct mount *mp, struct vnode *lowervp,
73 struct vnode **vpp);
74static struct vnode *
75 null_node_find(struct mount *mp, struct vnode *lowervp);
76
77/*
78 * Initialise cache headers
79 */
80int
81nullfs_init(vfsp)
82 struct vfsconf *vfsp;
83{
84
85 NULLFSDEBUG("nullfs_init\n"); /* printed during system boot */
86 null_node_hashtbl = hashinit(NNULLNODECACHE, M_NULLFSHASH, &null_node_hash);
87 lockinit(&null_hashlock, PVFS, "nullhs", 0, 0);
88 return (0);
89}
90
91int
92nullfs_uninit(vfsp)
93 struct vfsconf *vfsp;
94{
95
96 if (null_node_hashtbl) {
97 free(null_node_hashtbl, M_NULLFSHASH);
98 }
99 return (0);
100}
101
102/*
103 * Return a VREF'ed alias for lower vnode if already exists, else 0.
104 * Lower vnode should be locked on entry and will be left locked on exit.
105 */
106static struct vnode *
107null_node_find(mp, lowervp)
108 struct mount *mp;
109 struct vnode *lowervp;
110{
dadab5e9 111 struct thread *td = curthread; /* XXX */
984263bc
MD
112 struct null_node_hashhead *hd;
113 struct null_node *a;
114 struct vnode *vp;
115
116 /*
117 * Find hash base, and then search the (two-way) linked
118 * list looking for a null_node structure which is referencing
119 * the lower vnode. If found, the increment the null_node
120 * reference count (but NOT the lower vnode's VREF counter).
121 */
122 hd = NULL_NHASH(lowervp);
123loop:
dadab5e9 124 lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, td);
984263bc
MD
125 LIST_FOREACH(a, hd, null_hash) {
126 if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
127 vp = NULLTOV(a);
dadab5e9 128 lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
984263bc
MD
129 /*
130 * We need vget for the VXLOCK
131 * stuff, but we don't want to lock
132 * the lower node.
133 */
dadab5e9 134 if (vget(vp, LK_EXCLUSIVE | LK_CANRECURSE, td)) {
984263bc
MD
135 printf ("null_node_find: vget failed.\n");
136 goto loop;
137 }
dadab5e9 138 VOP_UNLOCK(lowervp, 0, td);
984263bc
MD
139 return (vp);
140 }
141 }
dadab5e9 142 lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
984263bc
MD
143
144 return NULLVP;
145}
146
147
148/*
149 * Make a new null_node node.
150 * Vp is the alias vnode, lofsvp is the lower vnode.
151 * Maintain a reference to (lowervp).
152 */
153static int
154null_node_alloc(mp, lowervp, vpp)
155 struct mount *mp;
156 struct vnode *lowervp;
157 struct vnode **vpp;
158{
dadab5e9 159 struct thread *td = curthread; /* XXX */
984263bc
MD
160 struct null_node_hashhead *hd;
161 struct null_node *xp;
162 struct vnode *othervp, *vp;
163 int error;
164
165 /*
166 * Do the MALLOC before the getnewvnode since doing so afterward
167 * might cause a bogus v_data pointer to get dereferenced
168 * elsewhere if MALLOC should block.
169 */
170 MALLOC(xp, struct null_node *, sizeof(struct null_node),
171 M_NULLFSNODE, M_WAITOK);
172
173 error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp);
174 if (error) {
175 FREE(xp, M_NULLFSNODE);
176 return (error);
177 }
178 vp = *vpp;
179
180 vp->v_type = lowervp->v_type;
181 lockinit(&xp->null_lock, PINOD, "nullnode", 0, LK_CANRECURSE);
182 xp->null_vnode = vp;
183 vp->v_data = xp;
184 xp->null_lowervp = lowervp;
185 /*
186 * Before we insert our new node onto the hash chains,
187 * check to see if someone else has beaten us to it.
188 * (We could have slept in MALLOC.)
189 */
190 othervp = null_node_find(mp, lowervp);
191 if (othervp) {
192 vp->v_data = NULL;
193 FREE(xp, M_NULLFSNODE);
194 vp->v_type = VBAD; /* node is discarded */
195 vrele(vp);
196 *vpp = othervp;
197 return 0;
198 }
199
200 /*
201 * From NetBSD:
202 * Now lock the new node. We rely on the fact that we were passed
203 * a locked vnode. If the lower node is exporting a struct lock
204 * (v_vnlock != NULL) then we just set the upper v_vnlock to the
205 * lower one, and both are now locked. If the lower node is exporting
206 * NULL, then we copy that up and manually lock the new vnode.
207 */
208
dadab5e9 209 lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, td);
984263bc 210 vp->v_vnlock = lowervp->v_vnlock;
dadab5e9 211 error = VOP_LOCK(vp, LK_EXCLUSIVE | LK_THISLAYER, td);
984263bc
MD
212 if (error)
213 panic("null_node_alloc: can't lock new vnode\n");
214
215 VREF(lowervp);
216 hd = NULL_NHASH(lowervp);
217 LIST_INSERT_HEAD(hd, xp, null_hash);
dadab5e9 218 lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
984263bc
MD
219 return 0;
220}
221
222
223/*
224 * Try to find an existing null_node vnode refering to the given underlying
225 * vnode (which should be locked). If no vnode found, create a new null_node
226 * vnode which contains a reference to the lower vnode.
227 */
228int
229null_node_create(mp, lowervp, newvpp)
230 struct mount *mp;
231 struct vnode *lowervp;
232 struct vnode **newvpp;
233{
234 struct vnode *aliasvp;
235
236 aliasvp = null_node_find(mp, lowervp);
237 if (aliasvp) {
238 /*
239 * null_node_find has taken another reference
240 * to the alias vnode.
241 */
242 vrele(lowervp);
243#ifdef NULLFS_DEBUG
244 vprint("null_node_create: exists", aliasvp);
245#endif
246 } else {
247 int error;
248
249 /*
250 * Get new vnode.
251 */
252 NULLFSDEBUG("null_node_create: create new alias vnode\n");
253
254 /*
255 * Make new vnode reference the null_node.
256 */
257 error = null_node_alloc(mp, lowervp, &aliasvp);
258 if (error)
259 return error;
260
261 /*
262 * aliasvp is already VREF'd by getnewvnode()
263 */
264 }
265
266#ifdef DIAGNOSTIC
267 if (lowervp->v_usecount < 1) {
268 /* Should never happen... */
269 vprint ("null_node_create: alias ", aliasvp);
270 vprint ("null_node_create: lower ", lowervp);
271 panic ("null_node_create: lower has 0 usecount.");
272 };
273#endif
274
275#ifdef NULLFS_DEBUG
276 vprint("null_node_create: alias", aliasvp);
277 vprint("null_node_create: lower", lowervp);
278#endif
279
280 *newvpp = aliasvp;
281 return (0);
282}
283
284#ifdef DIAGNOSTIC
285#include "opt_ddb.h"
286
287#ifdef DDB
288#define null_checkvp_barrier 1
289#else
290#define null_checkvp_barrier 0
291#endif
292
293struct vnode *
294null_checkvp(vp, fil, lno)
295 struct vnode *vp;
296 char *fil;
297 int lno;
298{
299 struct null_node *a = VTONULL(vp);
300#ifdef notyet
301 /*
302 * Can't do this check because vop_reclaim runs
303 * with a funny vop vector.
304 */
305 if (vp->v_op != null_vnodeop_p) {
306 printf ("null_checkvp: on non-null-node\n");
307 while (null_checkvp_barrier) /*WAIT*/ ;
308 panic("null_checkvp");
309 };
310#endif
311 if (a->null_lowervp == NULLVP) {
312 /* Should never happen */
313 int i; u_long *p;
314 printf("vp = %p, ZERO ptr\n", (void *)vp);
315 for (p = (u_long *) a, i = 0; i < 8; i++)
316 printf(" %lx", p[i]);
317 printf("\n");
318 /* wait for debugger */
319 while (null_checkvp_barrier) /*WAIT*/ ;
320 panic("null_checkvp");
321 }
322 if (a->null_lowervp->v_usecount < 1) {
323 int i; u_long *p;
324 printf("vp = %p, unref'ed lowervp\n", (void *)vp);
325 for (p = (u_long *) a, i = 0; i < 8; i++)
326 printf(" %lx", p[i]);
327 printf("\n");
328 /* wait for debugger */
329 while (null_checkvp_barrier) /*WAIT*/ ;
330 panic ("null with unref'ed lowervp");
331 };
332#ifdef notyet
333 printf("null %x/%d -> %x/%d [%s, %d]\n",
334 NULLTOV(a), NULLTOV(a)->v_usecount,
335 a->null_lowervp, a->null_lowervp->v_usecount,
336 fil, lno);
337#endif
338 return a->null_lowervp;
339}
340#endif