FreeBSD/Linux Kernel Cross Reference
sys/kern/vfs_init.c
1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed
6 * to Berkeley by John Heidemann of the UCLA Ficus project.
7 *
8 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
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. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94
39 * $FreeBSD$
40 */
41
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/mount.h>
47 #include <sys/sysctl.h>
48 #include <sys/vnode.h>
49 #include <sys/malloc.h>
50 #include <vm/vm_zone.h>
51
52
53 MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
54
55 /*
56 * XXX this bloat just exands the sysctl__vfs linker set a little so that
57 * we can attach sysctls for VFS modules without expanding the linker set.
58 * Currently (1998/09/06), only one VFS uses sysctls, so 2 extra linker
59 * set slots are more than sufficient.
60 */
61 extern struct linker_set sysctl__vfs;
62 static int mod_xx;
63 SYSCTL_INT(_vfs, OID_AUTO, mod0, CTLFLAG_RD, &mod_xx, 0, "");
64 SYSCTL_INT(_vfs, OID_AUTO, mod1, CTLFLAG_RD, &mod_xx, 0, "");
65
66 /*
67 * Zone for namei
68 */
69 struct vm_zone *namei_zone;
70
71 /*
72 * vfs_init.c
73 *
74 * Allocate and fill in operations vectors.
75 *
76 * An undocumented feature of this approach to defining operations is that
77 * there can be multiple entries in vfs_opv_descs for the same operations
78 * vector. This allows third parties to extend the set of operations
79 * supported by another layer in a binary compatibile way. For example,
80 * assume that NFS needed to be modified to support Ficus. NFS has an entry
81 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
82 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
83 * listing those new operations Ficus adds to NFS, all without modifying the
84 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
85 * that is a(whole)nother story.) This is a feature.
86 */
87
88 /* Table of known vnodeop vectors (list of VFS vnode vectors) */
89 static struct vnodeopv_desc **vnodeopv_descs;
90 static int vnodeopv_num;
91
92 /* Table of known descs (list of vnode op handlers "vop_access_desc") */
93 static struct vnodeop_desc **vfs_op_descs;
94 static int *vfs_op_desc_refs; /* reference counts */
95 static int num_op_descs;
96 static int vfs_opv_numops;
97
98 static void
99 vfs_opv_recalc(void)
100 {
101 int i, j;
102 vop_t ***opv_desc_vector_p;
103 vop_t **opv_desc_vector;
104 struct vnodeopv_entry_desc *opve_descp;
105 struct vnodeopv_desc *opv;
106
107 if (vfs_op_descs == NULL)
108 panic("vfs_opv_recalc called with null vfs_op_descs");
109
110 /*
111 * Run through and make sure all known descs have an offset
112 *
113 * vop_default_desc is hardwired at offset 1, and offset 0
114 * is a panic sanity check.
115 */
116 vfs_opv_numops = 0;
117 for (i = 0; i < num_op_descs; i++)
118 if (vfs_opv_numops < (vfs_op_descs[i]->vdesc_offset + 1))
119 vfs_opv_numops = vfs_op_descs[i]->vdesc_offset + 1;
120 for (i = 0; i < num_op_descs; i++)
121 if (vfs_op_descs[i]->vdesc_offset == 0)
122 vfs_op_descs[i]->vdesc_offset = vfs_opv_numops++;
123 /*
124 * Allocate and fill in the vectors
125 */
126 for (i = 0; i < vnodeopv_num; i++) {
127 opv = vnodeopv_descs[i];
128 opv_desc_vector_p = opv->opv_desc_vector_p;
129 if (*opv_desc_vector_p)
130 FREE(*opv_desc_vector_p, M_VNODE);
131 MALLOC(*opv_desc_vector_p, vop_t **,
132 vfs_opv_numops * sizeof(vop_t *), M_VNODE, M_WAITOK);
133 if (*opv_desc_vector_p == NULL)
134 panic("no memory for vop_t ** vector");
135 bzero(*opv_desc_vector_p, vfs_opv_numops * sizeof(vop_t *));
136
137 /* Fill in, with slot 0 being panic */
138 opv_desc_vector = *opv_desc_vector_p;
139 opv_desc_vector[0] = (vop_t *)vop_panic;
140 for (j = 0; opv->opv_desc_ops[j].opve_op; j++) {
141 opve_descp = &(opv->opv_desc_ops[j]);
142 opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
143 opve_descp->opve_impl;
144 }
145
146 /* Replace unfilled routines with their default (slot 1). */
147 opv_desc_vector = *(opv->opv_desc_vector_p);
148 if (opv_desc_vector[1] == NULL)
149 panic("vfs_opv_recalc: vector without a default.");
150 for (j = 0; j < vfs_opv_numops; j++)
151 if (opv_desc_vector[j] == NULL)
152 opv_desc_vector[j] = opv_desc_vector[1];
153 }
154 }
155
156 void
157 vfs_add_vnodeops(void *data)
158 {
159 struct vnodeopv_desc *opv;
160 struct vnodeopv_desc **newopv;
161 struct vnodeop_desc **newop;
162 int *newref;
163 vop_t **opv_desc_vector;
164 struct vnodeop_desc *desc;
165 int i, j;
166
167 opv = (struct vnodeopv_desc *)data;
168 MALLOC(newopv, struct vnodeopv_desc **,
169 (vnodeopv_num + 1) * sizeof(*newopv), M_VNODE, M_WAITOK);
170 if (newopv == NULL)
171 panic("vfs_add_vnodeops: no memory");
172 if (vnodeopv_descs) {
173 bcopy(vnodeopv_descs, newopv, vnodeopv_num * sizeof(*newopv));
174 FREE(vnodeopv_descs, M_VNODE);
175 }
176 newopv[vnodeopv_num] = opv;
177 vnodeopv_descs = newopv;
178 vnodeopv_num++;
179
180 /* See if we have turned up a new vnode op desc */
181 opv_desc_vector = *(opv->opv_desc_vector_p);
182 for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) {
183 for (j = 0; j < num_op_descs; j++) {
184 if (desc == vfs_op_descs[j]) {
185 /* found it, increase reference count */
186 vfs_op_desc_refs[j]++;
187 break;
188 }
189 }
190 if (j == num_op_descs) {
191 /* not found, new entry */
192 MALLOC(newop, struct vnodeop_desc **,
193 (num_op_descs + 1) * sizeof(*newop),
194 M_VNODE, M_WAITOK);
195 if (newop == NULL)
196 panic("vfs_add_vnodeops: no memory for desc");
197 /* new reference count (for unload) */
198 MALLOC(newref, int *,
199 (num_op_descs + 1) * sizeof(*newref),
200 M_VNODE, M_WAITOK);
201 if (newref == NULL)
202 panic("vfs_add_vnodeops: no memory for refs");
203 if (vfs_op_descs) {
204 bcopy(vfs_op_descs, newop,
205 num_op_descs * sizeof(*newop));
206 FREE(vfs_op_descs, M_VNODE);
207 }
208 if (vfs_op_desc_refs) {
209 bcopy(vfs_op_desc_refs, newref,
210 num_op_descs * sizeof(*newref));
211 FREE(vfs_op_desc_refs, M_VNODE);
212 }
213 newop[num_op_descs] = desc;
214 newref[num_op_descs] = 1;
215 vfs_op_descs = newop;
216 vfs_op_desc_refs = newref;
217 num_op_descs++;
218 }
219 }
220 vfs_opv_recalc();
221 }
222
223 void
224 vfs_rm_vnodeops(void *data)
225 {
226 struct vnodeopv_desc *opv;
227 struct vnodeopv_desc **newopv;
228 struct vnodeop_desc **newop;
229 int *newref;
230 vop_t **opv_desc_vector;
231 struct vnodeop_desc *desc;
232 int i, j, k;
233
234 opv = (struct vnodeopv_desc *)data;
235 /* Lower ref counts on descs in the table and release if zero */
236 opv_desc_vector = *(opv->opv_desc_vector_p);
237 for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) {
238 for (j = 0; j < num_op_descs; j++) {
239 if (desc == vfs_op_descs[j]) {
240 /* found it, decrease reference count */
241 vfs_op_desc_refs[j]--;
242 break;
243 }
244 }
245 for (j = 0; j < num_op_descs; j++) {
246 if (vfs_op_desc_refs[j] > 0)
247 continue;
248 if (vfs_op_desc_refs[j] < 0)
249 panic("vfs_remove_vnodeops: negative refcnt");
250 MALLOC(newop, struct vnodeop_desc **,
251 (num_op_descs - 1) * sizeof(*newop),
252 M_VNODE, M_WAITOK);
253 if (newop == NULL)
254 panic("vfs_remove_vnodeops: no memory for desc");
255 /* new reference count (for unload) */
256 MALLOC(newref, int *,
257 (num_op_descs - 1) * sizeof(*newref),
258 M_VNODE, M_WAITOK);
259 if (newref == NULL)
260 panic("vfs_remove_vnodeops: no memory for refs");
261 for (k = j; k < (num_op_descs - 1); k++) {
262 vfs_op_descs[k] = vfs_op_descs[k + 1];
263 vfs_op_desc_refs[k] = vfs_op_desc_refs[k + 1];
264 }
265 bcopy(vfs_op_descs, newop,
266 (num_op_descs - 1) * sizeof(*newop));
267 bcopy(vfs_op_desc_refs, newref,
268 (num_op_descs - 1) * sizeof(*newref));
269 FREE(vfs_op_descs, M_VNODE);
270 FREE(vfs_op_desc_refs, M_VNODE);
271 vfs_op_descs = newop;
272 vfs_op_desc_refs = newref;
273 num_op_descs--;
274 }
275 }
276
277 for (i = 0; i < vnodeopv_num; i++) {
278 if (vnodeopv_descs[i] == opv) {
279 for (j = i; j < (vnodeopv_num - 1); j++)
280 vnodeopv_descs[j] = vnodeopv_descs[j + 1];
281 break;
282 }
283 }
284 if (i == vnodeopv_num)
285 panic("vfs_remove_vnodeops: opv not found");
286 MALLOC(newopv, struct vnodeopv_desc **,
287 (vnodeopv_num - 1) * sizeof(*newopv), M_VNODE, M_WAITOK);
288 if (newopv == NULL)
289 panic("vfs_remove_vnodeops: no memory");
290 bcopy(vnodeopv_descs, newopv, (vnodeopv_num - 1) * sizeof(*newopv));
291 FREE(vnodeopv_descs, M_VNODE);
292 vnodeopv_descs = newopv;
293 vnodeopv_num--;
294
295 vfs_opv_recalc();
296 }
297
298 /*
299 * Routines having to do with the management of the vnode table.
300 */
301 struct vattr va_null;
302
303 /*
304 * Initialize the vnode structures and initialize each file system type.
305 */
306 /* ARGSUSED*/
307 static void
308 vfsinit(void *dummy)
309 {
310
311 namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2);
312
313 /*
314 * Initialize the vnode table
315 */
316 vntblinit();
317 /*
318 * Initialize the vnode name cache
319 */
320 nchinit();
321 /*
322 * Initialize each file system type.
323 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
324 */
325 vattr_null(&va_null);
326 maxvfsconf = VFS_GENERIC + 1;
327 }
328 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
329
330 int
331 vfs_register(struct vfsconf *vfc)
332 {
333 struct linker_set *l;
334 struct sysctl_oid **oidpp;
335 struct vfsconf *vfsp;
336 int i, exists;
337
338 vfsp = NULL;
339 l = &sysctl__vfs;
340 if (vfsconf)
341 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
342 if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
343 return EEXIST;
344
345 vfc->vfc_typenum = maxvfsconf++;
346 if (vfc->vfc_vfsops->vfs_oid != NULL) {
347 /*
348 * Attach the oid to the "vfs" node of the sysctl tree if
349 * it isn't already there (it will be there for statically
350 * configured vfs's).
351 */
352 exists = 0;
353 for (i = l->ls_length,
354 oidpp = (struct sysctl_oid **)l->ls_items;
355 i-- != 0; oidpp++)
356 if (*oidpp == vfc->vfc_vfsops->vfs_oid) {
357 exists = 1;
358 break;
359 }
360 if (exists == 0)
361 for (i = l->ls_length,
362 oidpp = (struct sysctl_oid **)l->ls_items;
363 i-- != 0; oidpp++) {
364 if (*oidpp == NULL ||
365 *oidpp == &sysctl___vfs_mod0 ||
366 *oidpp == &sysctl___vfs_mod1) {
367 *oidpp = vfc->vfc_vfsops->vfs_oid;
368 break;
369 }
370 }
371
372 vfc->vfc_vfsops->vfs_oid->oid_number = vfc->vfc_typenum;
373 sysctl_order_all();
374 }
375 if (vfsp)
376 vfsp->vfc_next = vfc;
377 else
378 vfsconf = vfc;
379 vfc->vfc_next = NULL;
380
381 /*
382 * Call init function for this VFS...
383 */
384 (*(vfc->vfc_vfsops->vfs_init))(vfc);
385
386 return 0;
387 }
388
389
390 int
391 vfs_unregister(struct vfsconf *vfc)
392 {
393 struct linker_set *l;
394 struct sysctl_oid **oidpp;
395 struct vfsconf *vfsp, *prev_vfsp;
396 int error, i, maxtypenum;
397
398 i = vfc->vfc_typenum;
399
400 prev_vfsp = NULL;
401 for (vfsp = vfsconf; vfsp;
402 prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
403 if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
404 break;
405 }
406 if (vfsp == NULL)
407 return EINVAL;
408 if (vfsp->vfc_refcount)
409 return EBUSY;
410 if (vfc->vfc_vfsops->vfs_uninit != NULL) {
411 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
412 if (error)
413 return (error);
414 }
415 if (prev_vfsp)
416 prev_vfsp->vfc_next = vfsp->vfc_next;
417 else
418 vfsconf = vfsp->vfc_next;
419 if (vfsp->vfc_vfsops->vfs_oid != NULL) {
420 l = &sysctl__vfs;
421 for (i = l->ls_length,
422 oidpp = (struct sysctl_oid **)l->ls_items;
423 i--; oidpp++) {
424 if (*oidpp == vfsp->vfc_vfsops->vfs_oid) {
425 *oidpp = NULL;
426 sysctl_order_all();
427 break;
428 }
429 }
430 }
431 maxtypenum = VFS_GENERIC;
432 for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
433 if (maxtypenum < vfsp->vfc_typenum)
434 maxtypenum = vfsp->vfc_typenum;
435 maxvfsconf = maxtypenum + 1;
436 return 0;
437 }
438
439 int
440 vfs_modevent(module_t mod, int type, void *data)
441 {
442 struct vfsconf *vfc;
443 int error = 0;
444
445 vfc = (struct vfsconf *)data;
446
447 switch (type) {
448 case MOD_LOAD:
449 if (vfc)
450 error = vfs_register(vfc);
451 break;
452
453 case MOD_UNLOAD:
454 if (vfc)
455 error = vfs_unregister(vfc);
456 break;
457 default: /* including MOD_SHUTDOWN */
458 break;
459 }
460 return (error);
461 }
Cache object: 209baadab63d796c28d4f98113e3d491
|