layer_subr.c revision 1.13 1 /* $NetBSD: layer_subr.c,v 1.13 2003/06/29 18:43:32 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1999 National Aeronautics & Space Administration
5 * All rights reserved.
6 *
7 * This software was written by William Studenmund of the
8 * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the National Aeronautics & Space Administration
19 * nor the names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB-
27 * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35 /*
36 * Copyright (c) 1992, 1993
37 * The Regents of the University of California. All rights reserved.
38 *
39 * This code is derived from software donated to Berkeley by
40 * Jan-Simon Pendry.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 *
70 * from: Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp
71 * @(#)null_subr.c 8.7 (Berkeley) 5/14/95
72 */
73
74 #include <sys/cdefs.h>
75 __KERNEL_RCSID(0, "$NetBSD: layer_subr.c,v 1.13 2003/06/29 18:43:32 thorpej Exp $");
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/proc.h>
80 #include <sys/time.h>
81 #include <sys/vnode.h>
82 #include <sys/mount.h>
83 #include <sys/namei.h>
84 #include <sys/malloc.h>
85 #include <miscfs/specfs/specdev.h>
86 #include <miscfs/genfs/layer.h>
87 #include <miscfs/genfs/layer_extern.h>
88
89 #define NLAYERNODECACHE 16
90
91 /*
92 * layer cache:
93 * Each cache entry holds a reference to the lower vnode
94 * along with a pointer to the alias vnode. When an
95 * entry is added the lower vnode is VREF'd. When the
96 * alias is removed the lower vnode is vrele'd.
97 */
98
99 /*
100 * Initialise cache headers
101 */
102 void
103 layerfs_init()
104 {
105 #ifdef LAYERFS_DIAGNOSTIC
106 printf("layerfs_init\n"); /* printed during system boot */
107 #endif
108 }
109
110 /*
111 * Free global resources of layerfs.
112 */
113 void
114 layerfs_done()
115 {
116 #ifdef LAYERFS_DIAGNOSTIC
117 printf("layerfs_done\n"); /* printed on layerfs detach */
118 #endif
119 }
120
121 /*
122 * Return a locked, VREF'ed alias for lower vnode if already exists, else 0.
123 */
124 struct vnode *
125 layer_node_find(mp, lowervp)
126 struct mount *mp;
127 struct vnode *lowervp;
128 {
129 struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp);
130 struct layer_node_hashhead *hd;
131 struct layer_node *a;
132 struct vnode *vp;
133
134 /*
135 * Find hash base, and then search the (two-way) linked
136 * list looking for a layer_node structure which is referencing
137 * the lower vnode. If found, the increment the layer_node
138 * reference count (but NOT the lower vnode's VREF counter)
139 * and return the vnode locked.
140 */
141 hd = LAYER_NHASH(lmp, lowervp);
142 loop:
143 simple_lock(&lmp->layerm_hashlock);
144 for (a = hd->lh_first; a != 0; a = a->layer_hash.le_next) {
145 if (a->layer_lowervp == lowervp && LAYERTOV(a)->v_mount == mp) {
146 vp = LAYERTOV(a);
147 simple_unlock(&lmp->layerm_hashlock);
148 /*
149 * We must be careful here as the fact the lower
150 * vnode is locked will imply vp is locked unless
151 * someone has decided to start vclean'ing either
152 * vp or lowervp.
153 *
154 * So we try for an exclusive, recursive lock
155 * on the upper vnode. If it fails, vcleaning
156 * is in progress (so when we try again, we'll
157 * fail). If it succeeds, we now have double
158 * locked the bottom node. So we do an explicit
159 * VOP_UNLOCK on it to keep the counts right. Note
160 * that we will end up with the upper node and
161 * the lower node locked once.
162 */
163 if (vget(vp, LK_EXCLUSIVE | LK_CANRECURSE)) {
164 printf ("layer_node_find: vget failed.\n");
165 goto loop;
166 };
167 VOP_UNLOCK(lowervp, 0);
168 return (vp);
169 }
170 }
171
172 simple_unlock(&lmp->layerm_hashlock);
173 return NULL;
174 }
175
176
177 /*
178 * Make a new layer_node node.
179 * Vp is the alias vnode, lowervp is the lower vnode.
180 * Maintain a reference to lowervp.
181 */
182 int
183 layer_node_alloc(mp, lowervp, vpp)
184 struct mount *mp;
185 struct vnode *lowervp;
186 struct vnode **vpp;
187 {
188 struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp);
189 struct layer_node_hashhead *hd;
190 struct layer_node *xp;
191 struct vnode *vp, *nvp;
192 int error;
193 extern int (**dead_vnodeop_p) __P((void *));
194
195 if ((error = getnewvnode(lmp->layerm_tag, mp, lmp->layerm_vnodeop_p,
196 &vp)) != 0)
197 return (error);
198 vp->v_type = lowervp->v_type;
199 vp->v_flag |= VLAYER;
200
201 xp = malloc(lmp->layerm_size, M_TEMP, M_WAITOK);
202 if (vp->v_type == VBLK || vp->v_type == VCHR) {
203 MALLOC(vp->v_specinfo, struct specinfo *,
204 sizeof(struct specinfo), M_VNODE, M_WAITOK);
205 vp->v_hashchain = NULL;
206 vp->v_rdev = lowervp->v_rdev;
207 }
208
209 vp->v_data = xp;
210 xp->layer_vnode = vp;
211 xp->layer_lowervp = lowervp;
212 xp->layer_flags = 0;
213 /*
214 * Before we insert our new node onto the hash chains,
215 * check to see if someone else has beaten us to it.
216 * (We could have slept in MALLOC.)
217 */
218 if ((nvp = layer_node_find(mp, lowervp)) != NULL) {
219 *vpp = nvp;
220
221 /* free the substructures we've allocated. */
222 FREE(xp, M_TEMP);
223 if (vp->v_type == VBLK || vp->v_type == VCHR)
224 FREE(vp->v_specinfo, M_VNODE);
225
226 vp->v_type = VBAD; /* node is discarded */
227 vp->v_op = dead_vnodeop_p; /* so ops will still work */
228 vrele(vp); /* get rid of it. */
229 return (0);
230 }
231
232 simple_lock(&lmp->layerm_hashlock);
233
234 /*
235 * Now lock the new node. We rely on the fact that we were passed
236 * a locked vnode. If the lower node is exporting a struct lock
237 * (v_vnlock != NULL) then we just set the upper v_vnlock to the
238 * lower one, and both are now locked. If the lower node is exporting
239 * NULL, then we copy that up and manually lock the upper node.
240 *
241 * LAYERFS_UPPERLOCK already has the test, so we use it after copying
242 * up the v_vnlock from below.
243 */
244
245 vp->v_vnlock = lowervp->v_vnlock;
246 LAYERFS_UPPERLOCK(vp, LK_EXCLUSIVE, error);
247
248 if (error) {
249 /*
250 * How did we get a locking error? The node just came off
251 * of the free list, and we're the only routine which
252 * knows it's there...
253 */
254 vp->v_vnlock = &vp->v_lock;
255 *vpp = NULL;
256
257 /* free the substructures we've allocated. */
258 FREE(xp, M_TEMP);
259 if (vp->v_type == VBLK || vp->v_type == VCHR)
260 FREE(vp->v_specinfo, M_VNODE);
261
262 vp->v_type = VBAD; /* node is discarded */
263 vp->v_op = dead_vnodeop_p; /* so ops will still work */
264 vrele(vp); /* get rid of it. */
265 return (error);
266 }
267 /*
268 * NetBSD used to do an inlined checkalias here. We do not, as
269 * we never flag device nodes as being aliased. The lowervp
270 * node will, when appropriate, be flaged as an alias.
271 */
272
273 *vpp = vp;
274 VREF(lowervp); /* Take into account reference held in layer_node */
275 hd = LAYER_NHASH(lmp, lowervp);
276 LIST_INSERT_HEAD(hd, xp, layer_hash);
277 uvm_vnp_setsize(vp, 0);
278 simple_unlock(&lmp->layerm_hashlock);
279 return (0);
280 }
281
282
283 /*
284 * Try to find an existing layer_node vnode refering
285 * to it, otherwise make a new layer_node vnode which
286 * contains a reference to the lower vnode.
287 *
288 * >>> we assume that the lower node is already locked upon entry, so we
289 * propagate the lock state to upper node <<
290 */
291 int
292 layer_node_create(mp, lowervp, newvpp)
293 struct mount *mp;
294 struct vnode *lowervp;
295 struct vnode **newvpp;
296 {
297 struct vnode *aliasvp;
298 struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp);
299
300 if ((aliasvp = layer_node_find(mp, lowervp)) != NULL) {
301 /*
302 * layer_node_find has taken another reference
303 * to the alias vnode and moved the lock holding to
304 * aliasvp
305 */
306 #ifdef LAYERFS_DIAGNOSTIC
307 vprint("layer_node_create: exists", aliasvp);
308 #endif
309 } else {
310 int error;
311
312 /*
313 * Get new vnode.
314 */
315 #ifdef LAYERFS_DIAGNOSTIC
316 printf("layer_node_create: create new alias vnode\n");
317 #endif
318
319 /*
320 * Make new vnode reference the layer_node.
321 */
322 if ((error = (lmp->layerm_alloc)(mp, lowervp, &aliasvp)) != 0)
323 return error;
324
325 /*
326 * aliasvp is already VREF'd by getnewvnode()
327 */
328 }
329
330 /*
331 * Now that we have VREF'd the upper vnode, release the reference
332 * to the lower node. The existance of the layer_node retains one
333 * reference to the lower node.
334 */
335 vrele(lowervp);
336
337 #ifdef DIAGNOSTIC
338 if (lowervp->v_usecount < 1) {
339 /* Should never happen... */
340 vprint("layer_node_create: alias", aliasvp);
341 vprint("layer_node_create: lower", lowervp);
342 panic("layer_node_create: lower has 0 usecount.");
343 };
344 #endif
345
346 #ifdef LAYERFS_DIAGNOSTIC
347 vprint("layer_node_create: alias", aliasvp);
348 #endif
349 *newvpp = aliasvp;
350 return (0);
351 }
352
353 struct vnode *
354 layer_checkvp(vp, fil, lno)
355 struct vnode *vp;
356 char *fil;
357 int lno;
358 {
359 struct layer_node *a = VTOLAYER(vp);
360 #ifdef notyet
361 /*
362 * Can't do this check because vop_reclaim runs
363 * with a funny vop vector.
364 *
365 * WRS - no it doesnt...
366 */
367 if (vp->v_op != layer_vnodeop_p) {
368 printf ("layer_checkvp: on non-layer-node\n");
369 #ifdef notyet
370 while (layer_checkvp_barrier) /*WAIT*/ ;
371 #endif
372 panic("layer_checkvp");
373 };
374 #endif
375 if (a->layer_lowervp == NULL) {
376 /* Should never happen */
377 int i; u_long *p;
378 printf("vp = %p, ZERO ptr\n", vp);
379 for (p = (u_long *) a, i = 0; i < 8; i++)
380 printf(" %lx", p[i]);
381 printf("\n");
382 /* wait for debugger */
383 panic("layer_checkvp");
384 }
385 if (a->layer_lowervp->v_usecount < 1) {
386 int i; u_long *p;
387 printf("vp = %p, unref'ed lowervp\n", vp);
388 for (p = (u_long *) a, i = 0; i < 8; i++)
389 printf(" %lx", p[i]);
390 printf("\n");
391 /* wait for debugger */
392 panic ("layer with unref'ed lowervp");
393 };
394 #ifdef notnow
395 printf("layer %p/%d -> %p/%d [%s, %d]\n",
396 LAYERTOV(a), LAYERTOV(a)->v_usecount,
397 a->layer_lowervp, a->layer_lowervp->v_usecount,
398 fil, lno);
399 #endif
400 return a->layer_lowervp;
401 }
402