xref: /freebsd/sys/kern/vfs_init.c (revision 2ad872c5794e4c26fdf6ed219ad3f09ca0d5304a)
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  * $Id: vfs_init.c,v 1.40 1998/11/15 15:18:30 bde Exp $
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 }
462