]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/nullfs/null_subr.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / miscfs / nullfs / null_subr.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1992, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software donated to Berkeley by
28 * Jan-Simon Pendry.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)null_subr.c 8.7 (Berkeley) 5/14/95
59 *
60 * null_subr.c 8.4 (Berkeley) 1/21/94
61 */
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/proc.h>
66 #include <sys/time.h>
67 #include <sys/types.h>
68 #include <sys/vnode.h>
69 #include <sys/mount_internal.h>
70 #include <sys/namei.h>
71 #include <sys/malloc.h>
72 #include <sys/ubc.h>
73 #include <miscfs/nullfs/null.h>
74
75 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
76 #define NNULLNODECACHE 16
77
78 /*
79 * Null layer cache:
80 * Each cache entry holds a reference to the lower vnode
81 * along with a pointer to the alias vnode. When an
82 * entry is added the lower vnode is vnode_get'd. When the
83 * alias is removed the lower vnode is vnode_put'd.
84 */
85
86 #define NULL_NHASH(vp) \
87 (&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash])
88 LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
89 u_long null_node_hash;
90
91 /*
92 * Initialise cache headers
93 */
94 nullfs_init()
95 {
96
97 #ifdef NULLFS_DIAGNOSTIC
98 printf("nullfs_init\n"); /* printed during system boot */
99 #endif
100 null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash);
101 }
102
103 /*
104 * Return a vnode_get'ed alias for lower vnode if already exists, else 0.
105 */
106 static struct vnode *
107 null_node_find(mp, lowervp)
108 struct mount *mp;
109 struct vnode *lowervp;
110 {
111 struct proc *p = curproc; /* XXX */
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 vnode_get counter).
121 */
122 hd = NULL_NHASH(lowervp);
123 loop:
124 for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) {
125 if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
126 vp = NULLTOV(a);
127
128 if (vnode_get(vp)) {
129 printf ("null_node_find: vget failed.\n");
130 goto loop;
131 };
132 return (vp);
133 }
134 }
135
136 return NULL;
137 }
138
139
140 /*
141 * Make a new null_node node.
142 * Vp is the alias vnode, lofsvp is the lower vnode.
143 * Maintain a reference to (lowervp).
144 */
145 static int
146 null_node_alloc(mp, lowervp, vpp)
147 struct mount *mp;
148 struct vnode *lowervp;
149 struct vnode **vpp;
150 {
151 struct null_node_hashhead *hd;
152 struct null_node *xp;
153 struct vnode *othervp, *vp;
154 int error;
155
156 MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
157 if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp)) {
158 FREE(xp, M_TEMP);
159 return (error);
160 }
161 vp = *vpp;
162
163 vp->v_type = lowervp->v_type;
164 xp->null_vnode = vp;
165 vp->v_data = xp;
166 xp->null_lowervp = lowervp;
167 /*
168 * Before we insert our new node onto the hash chains,
169 * check to see if someone else has beaten us to it.
170 */
171 if (othervp = null_node_find(lowervp)) {
172 FREE(xp, M_TEMP);
173 vp->v_type = VBAD; /* node is discarded */
174 vp->v_usecount = 0; /* XXX */
175 vp->v_data = 0; /* prevent access to freed data */
176 *vpp = othervp;
177 return 0;
178 };
179 if (vp->v_type == VREG)
180 ubc_info_init(vp);
181 vnode_get(lowervp); /* Extra vnode_get will be vnode_put'd in null_node_create */
182 hd = NULL_NHASH(lowervp);
183 LIST_INSERT_HEAD(hd, xp, null_hash);
184 return 0;
185 }
186
187
188 /*
189 * Try to find an existing null_node vnode refering
190 * to it, otherwise make a new null_node vnode which
191 * contains a reference to the lower vnode.
192 */
193 int
194 null_node_create(mp, lowervp, newvpp)
195 struct mount *mp;
196 struct vnode *lowervp;
197 struct vnode **newvpp;
198 {
199 struct vnode *aliasvp;
200
201 if (aliasvp = null_node_find(mp, lowervp)) {
202 /*
203 * null_node_find has taken another reference
204 * to the alias vnode.
205 */
206 #ifdef NULLFS_DIAGNOSTIC
207 vprint("null_node_create: exists", NULLTOV(ap));
208 #endif
209 /* vnode_get(aliasvp); --- done in null_node_find */
210 } else {
211 int error;
212
213 /*
214 * Get new vnode.
215 */
216 #ifdef NULLFS_DIAGNOSTIC
217 printf("null_node_create: create new alias vnode\n");
218 #endif
219
220 /*
221 * Make new vnode reference the null_node.
222 */
223 if (error = null_node_alloc(mp, lowervp, &aliasvp))
224 return error;
225
226 /*
227 * aliasvp is already vnode_get'd by getnewvnode()
228 */
229 }
230
231 vnode_put(lowervp);
232
233 #if DIAGNOSTIC
234 if (lowervp->v_usecount < 1) {
235 /* Should never happen... */
236 vprint ("null_node_create: alias ", aliasvp);
237 vprint ("null_node_create: lower ", lowervp);
238 panic ("null_node_create: lower has 0 usecount.");
239 };
240 #endif
241
242 #ifdef NULLFS_DIAGNOSTIC
243 vprint("null_node_create: alias", aliasvp);
244 vprint("null_node_create: lower", lowervp);
245 #endif
246
247 *newvpp = aliasvp;
248 return (0);
249 }
250 #ifdef NULLFS_DIAGNOSTIC
251 struct vnode *
252 null_checkvp(vp, fil, lno)
253 struct vnode *vp;
254 char *fil;
255 int lno;
256 {
257 struct null_node *a = VTONULL(vp);
258 #ifdef notyet
259 /*
260 * Can't do this check because vnop_reclaim runs
261 * with a funny vop vector.
262 */
263 if (vp->v_op != null_vnodeop_p) {
264 printf ("null_checkvp: on non-null-node\n");
265 while (null_checkvp_barrier) /*WAIT*/ ;
266 panic("null_checkvp");
267 };
268 #endif
269 if (a->null_lowervp == NULL) {
270 /* Should never happen */
271 int i; u_long *p;
272 printf("vp = %x, ZERO ptr\n", vp);
273 for (p = (u_long *) a, i = 0; i < 8; i++)
274 printf(" %x", p[i]);
275 printf("\n");
276 /* wait for debugger */
277 while (null_checkvp_barrier) /*WAIT*/ ;
278 panic("null_checkvp");
279 }
280 if (a->null_lowervp->v_usecount < 1) {
281 int i; u_long *p;
282 printf("vp = %x, unref'ed lowervp\n", vp);
283 for (p = (u_long *) a, i = 0; i < 8; i++)
284 printf(" %x", p[i]);
285 printf("\n");
286 /* wait for debugger */
287 while (null_checkvp_barrier) /*WAIT*/ ;
288 panic ("null with unref'ed lowervp");
289 };
290 #ifdef notyet
291 printf("null %x/%d -> %x/%d [%s, %d]\n",
292 NULLTOV(a), NULLTOV(a)->v_usecount,
293 a->null_lowervp, a->null_lowervp->v_usecount,
294 fil, lno);
295 #endif
296 return a->null_lowervp;
297 }
298 #endif