]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/nullfs/null_subr.c
xnu-344.12.2.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.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 VREF'd. When the
83 * alias is removed the lower vnode is vrele'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 VREF'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 VREF 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 * We need vget for the VXLOCK
129 * stuff, but we don't want to lock
130 * the lower node.
131 */
132 if (vget(vp, 0, p)) {
133 printf ("null_node_find: vget failed.\n");
134 goto loop;
135 };
136 return (vp);
137 }
138 }
139
140 return NULL;
141 }
142
143
144 /*
145 * Make a new null_node node.
146 * Vp is the alias vnode, lofsvp is the lower vnode.
147 * Maintain a reference to (lowervp).
148 */
149 static int
150 null_node_alloc(mp, lowervp, vpp)
151 struct mount *mp;
152 struct vnode *lowervp;
153 struct vnode **vpp;
154 {
155 struct null_node_hashhead *hd;
156 struct null_node *xp;
157 struct vnode *othervp, *vp;
158 int error;
159
160 MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
161 if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp)) {
162 FREE(xp, M_TEMP);
163 return (error);
164 }
165 vp = *vpp;
166
167 vp->v_type = lowervp->v_type;
168 xp->null_vnode = vp;
169 vp->v_data = xp;
170 xp->null_lowervp = lowervp;
171 /*
172 * Before we insert our new node onto the hash chains,
173 * check to see if someone else has beaten us to it.
174 */
175 if (othervp = null_node_find(lowervp)) {
176 FREE(xp, M_TEMP);
177 vp->v_type = VBAD; /* node is discarded */
178 vp->v_usecount = 0; /* XXX */
179 vp->v_data = 0; /* prevent access to freed data */
180 *vpp = othervp;
181 return 0;
182 };
183 if (vp->v_type == VREG)
184 ubc_info_init(vp);
185 VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */
186 hd = NULL_NHASH(lowervp);
187 LIST_INSERT_HEAD(hd, xp, null_hash);
188 return 0;
189 }
190
191
192 /*
193 * Try to find an existing null_node vnode refering
194 * to it, otherwise make a new null_node vnode which
195 * contains a reference to the lower vnode.
196 */
197 int
198 null_node_create(mp, lowervp, newvpp)
199 struct mount *mp;
200 struct vnode *lowervp;
201 struct vnode **newvpp;
202 {
203 struct vnode *aliasvp;
204
205 if (aliasvp = null_node_find(mp, lowervp)) {
206 /*
207 * null_node_find has taken another reference
208 * to the alias vnode.
209 */
210 #ifdef NULLFS_DIAGNOSTIC
211 vprint("null_node_create: exists", NULLTOV(ap));
212 #endif
213 /* VREF(aliasvp); --- done in null_node_find */
214 } else {
215 int error;
216
217 /*
218 * Get new vnode.
219 */
220 #ifdef NULLFS_DIAGNOSTIC
221 printf("null_node_create: create new alias vnode\n");
222 #endif
223
224 /*
225 * Make new vnode reference the null_node.
226 */
227 if (error = null_node_alloc(mp, lowervp, &aliasvp))
228 return error;
229
230 /*
231 * aliasvp is already VREF'd by getnewvnode()
232 */
233 }
234
235 vrele(lowervp);
236
237 #if DIAGNOSTIC
238 if (lowervp->v_usecount < 1) {
239 /* Should never happen... */
240 vprint ("null_node_create: alias ", aliasvp);
241 vprint ("null_node_create: lower ", lowervp);
242 panic ("null_node_create: lower has 0 usecount.");
243 };
244 #endif
245
246 #ifdef NULLFS_DIAGNOSTIC
247 vprint("null_node_create: alias", aliasvp);
248 vprint("null_node_create: lower", lowervp);
249 #endif
250
251 *newvpp = aliasvp;
252 return (0);
253 }
254 #ifdef NULLFS_DIAGNOSTIC
255 struct vnode *
256 null_checkvp(vp, fil, lno)
257 struct vnode *vp;
258 char *fil;
259 int lno;
260 {
261 struct null_node *a = VTONULL(vp);
262 #ifdef notyet
263 /*
264 * Can't do this check because vop_reclaim runs
265 * with a funny vop vector.
266 */
267 if (vp->v_op != null_vnodeop_p) {
268 printf ("null_checkvp: on non-null-node\n");
269 while (null_checkvp_barrier) /*WAIT*/ ;
270 panic("null_checkvp");
271 };
272 #endif
273 if (a->null_lowervp == NULL) {
274 /* Should never happen */
275 int i; u_long *p;
276 printf("vp = %x, ZERO ptr\n", vp);
277 for (p = (u_long *) a, i = 0; i < 8; i++)
278 printf(" %x", p[i]);
279 printf("\n");
280 /* wait for debugger */
281 while (null_checkvp_barrier) /*WAIT*/ ;
282 panic("null_checkvp");
283 }
284 if (a->null_lowervp->v_usecount < 1) {
285 int i; u_long *p;
286 printf("vp = %x, unref'ed lowervp\n", vp);
287 for (p = (u_long *) a, i = 0; i < 8; i++)
288 printf(" %x", p[i]);
289 printf("\n");
290 /* wait for debugger */
291 while (null_checkvp_barrier) /*WAIT*/ ;
292 panic ("null with unref'ed lowervp");
293 };
294 #ifdef notyet
295 printf("null %x/%d -> %x/%d [%s, %d]\n",
296 NULLTOV(a), NULLTOV(a)->v_usecount,
297 a->null_lowervp, a->null_lowervp->v_usecount,
298 fil, lno);
299 #endif
300 return a->null_lowervp;
301 }
302 #endif