xref: /freebsd/sys/kern/vfs_init.c (revision 0640d357f29fb1c0daaaffadd0416c5981413afd)
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.37 1998/10/25 17:44:52 phk 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 static void	vfs_op_init __P((void));
53 
54 static void vfsinit __P((void *));
55 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
56 
57 MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
58 
59 /*
60  * Sigh, such primitive tools are these...
61  */
62 #if 0
63 #define DODEBUG(A) A
64 #else
65 #define DODEBUG(A)
66 #endif
67 
68 extern struct vnodeop_desc *vfs_op_descs[];
69 				/* and the operations they perform */
70 
71 /*
72  * XXX this bloat just exands the sysctl__vfs linker set a little so that
73  * we can attach sysctls for VFS modules without expanding the linker set.
74  * Currently (1998/09/06), only one VFS uses sysctls, so 2 extra linker
75  * set slots are more than sufficient.
76  */
77 extern struct linker_set sysctl__vfs;
78 static int mod_xx;
79 SYSCTL_INT(_vfs, OID_AUTO, mod0, CTLFLAG_RD, &mod_xx, 0, "");
80 SYSCTL_INT(_vfs, OID_AUTO, mod1, CTLFLAG_RD, &mod_xx, 0, "");
81 
82 /*
83  * Zone for namei
84  */
85 struct vm_zone *namei_zone;
86 
87 /*
88  * vfs_init.c
89  *
90  * Allocate and fill in operations vectors.
91  *
92  * An undocumented feature of this approach to defining operations is that
93  * there can be multiple entries in vfs_opv_descs for the same operations
94  * vector. This allows third parties to extend the set of operations
95  * supported by another layer in a binary compatibile way. For example,
96  * assume that NFS needed to be modified to support Ficus. NFS has an entry
97  * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
98  * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
99  * listing those new operations Ficus adds to NFS, all without modifying the
100  * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
101  * that is a(whole)nother story.) This is a feature.
102  *
103  * Without an explicit reserve area, however, you must replace vnode_if.c
104  * and vnode_if.h when you do this, or you will be derefrencing of the
105  * end of vfs_op_descs[].  This is a flaw in the use of a structure
106  * pointer array rather than an agregate to define vfs_op_descs.  So
107  * it's not a very dynamic "feature".
108  */
109 void
110 vfs_opv_init(struct vnodeopv_desc *opv)
111 {
112 	int j;
113 	vop_t ***opv_desc_vector_p;
114 	vop_t **opv_desc_vector;
115 	struct vnodeopv_entry_desc *opve_descp;
116 	int default_vector;
117 
118 	default_vector = VOFFSET(vop_default);
119 	/*
120 	 * Allocate the dynamic vectors and fill them in.
121 	 */
122 	opv_desc_vector_p = opv->opv_desc_vector_p;
123 	/*
124 	 * Allocate and init the vector, if it needs it.
125 	 * Also handle backwards compatibility.
126 	 */
127 	if (*opv_desc_vector_p == NULL) {
128 		/* XXX - shouldn't be M_VNODE */
129 		MALLOC(*opv_desc_vector_p, vop_t **,
130 		       vfs_opv_numops * sizeof(vop_t *), M_VNODE, M_WAITOK);
131 		bzero(*opv_desc_vector_p,
132 		      vfs_opv_numops * sizeof(vop_t *));
133 		DODEBUG(printf("vector at %x allocated\n",
134 		    opv_desc_vector_p));
135 	}
136 	opv_desc_vector = *opv_desc_vector_p;
137 	for (j = 0; opv->opv_desc_ops[j].opve_op; j++) {
138 		opve_descp = &(opv->opv_desc_ops[j]);
139 
140 		/*
141 		 * Sanity check:  is this operation listed
142 		 * in the list of operations?  We check this
143 		 * by seeing if its offest is zero.  Since
144 		 * the default routine should always be listed
145 		 * first, it should be the only one with a zero
146 		 * offset.  Any other operation with a zero
147 		 * offset is probably not listed in
148 		 * vfs_op_descs, and so is probably an error.
149 		 *
150 		 * A panic here means the layer programmer
151 		 * has committed the all-too common bug
152 		 * of adding a new operation to the layer's
153 		 * list of vnode operations but
154 		 * not adding the operation to the system-wide
155 		 * list of supported operations.
156 		 */
157 		if (opve_descp->opve_op->vdesc_offset == 0 &&
158 		    opve_descp->opve_op->vdesc_offset != default_vector) {
159 			printf("operation %s not listed in vfs_op_descs[].\n",
160 			    opve_descp->opve_op->vdesc_name);
161 			panic ("vfs_opv_init: bad operation");
162 		}
163 		/*
164 		 * Fill in this entry.
165 		 */
166 		opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
167 				opve_descp->opve_impl;
168 	}
169 	/*
170 	 * Finally, go back and replace unfilled routines with their default.
171 	 */
172 	opv_desc_vector = *(opv->opv_desc_vector_p);
173 	if (opv_desc_vector[default_vector] == NULL)
174 		panic("vfs_opv_init: operation vector without a default.");
175 	for (j = 0; j < vfs_opv_numops; j++)
176 		if (opv_desc_vector[j] == NULL)
177 			opv_desc_vector[j] = opv_desc_vector[default_vector];
178 }
179 
180 /*
181  * Initialize known vnode operations vectors.
182  */
183 static void
184 vfs_op_init()
185 {
186 	int i;
187 
188 	DODEBUG(printf("Vnode_interface_init.\n"));
189 	DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops));
190 	/*
191 	 * assign each op to its offset
192 	 *
193 	 * XXX This should not be needed, but is because the per
194 	 * XXX FS ops tables are not sorted according to the
195 	 * XXX vnodeop_desc's offset in vfs_op_descs.  This
196 	 * XXX is the same reason we have to take the hit for
197 	 * XXX the static inline function calls instead of using
198 	 * XXX simple macro references.
199 	 */
200 	for (i = 0; i < vfs_opv_numops; i++)
201 		vfs_op_descs[i]->vdesc_offset = i;
202 }
203 
204 /*
205  * Routines having to do with the management of the vnode table.
206  */
207 extern struct vnodeops dead_vnodeops;
208 extern struct vnodeops spec_vnodeops;
209 struct vattr va_null;
210 
211 /*
212  * Initialize the vnode structures and initialize each file system type.
213  */
214 /* ARGSUSED*/
215 static void
216 vfsinit(dummy)
217 	void *dummy;
218 {
219 
220 	namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2);
221 
222 	/*
223 	 * Initialize the vnode table
224 	 */
225 	vntblinit();
226 	/*
227 	 * Initialize the vnode name cache
228 	 */
229 	nchinit();
230 	/*
231 	 * Build vnode operation vectors.
232 	 */
233 	vfs_op_init();
234 	/*
235 	 * Initialize each file system type.
236 	 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
237 	 */
238 	vattr_null(&va_null);
239 	maxvfsconf = VFS_GENERIC + 1;
240 }
241 
242 int
243 vfs_register(vfc)
244 	struct vfsconf *vfc;
245 {
246 	struct linker_set *l;
247 	struct sysctl_oid **oidpp;
248 	struct vfsconf *vfsp;
249 	int i, exists;
250 
251 	vfsp = NULL;
252 	l = &sysctl__vfs;
253 	if (vfsconf)
254 		for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
255 			if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
256 				return EEXIST;
257 
258 	vfc->vfc_typenum = maxvfsconf++;
259 	if (vfc->vfc_vfsops->vfs_oid != NULL) {
260 		/*
261 		 * Attach the oid to the "vfs" node of the sysctl tree if
262 		 * it isn't already there (it will be there for statically
263 		 * configured vfs's).
264 		 */
265 		exists = 0;
266 		for (i = l->ls_length,
267 		    oidpp = (struct sysctl_oid **)l->ls_items;
268 		    i-- != 0; oidpp++)
269 			if (*oidpp == vfc->vfc_vfsops->vfs_oid) {
270 				exists = 1;
271 				break;
272 			}
273 		if (exists == 0)
274 			for (i = l->ls_length,
275 			    oidpp = (struct sysctl_oid **)l->ls_items;
276 			    i-- != 0; oidpp++) {
277 				if (*oidpp == NULL ||
278 				    *oidpp == &sysctl___vfs_mod0 ||
279 				    *oidpp == &sysctl___vfs_mod1) {
280 					*oidpp = vfc->vfc_vfsops->vfs_oid;
281 					break;
282 				}
283 			}
284 
285 		vfc->vfc_vfsops->vfs_oid->oid_number = vfc->vfc_typenum;
286 		sysctl_order_all();
287 	}
288 	if (vfsp)
289 		vfsp->vfc_next = vfc;
290 	else
291 		vfsconf = vfc;
292 	vfc->vfc_next = NULL;
293 
294 	/*
295 	 * Call init function for this VFS...
296 	 */
297 	(*(vfc->vfc_vfsops->vfs_init))(vfc);
298 
299 	return 0;
300 }
301 
302 
303 /*
304  * To be called at SI_SUB_VFS, SECOND, for each VFS before any are registered.
305  */
306 void
307 vfs_mod_opv_init(handle)
308 	void *handle;
309 {
310 	struct vnodeopv_desc *opv;
311 
312 	opv = (struct vnodeopv_desc *)handle;
313 	*(opv->opv_desc_vector_p) = NULL;
314 
315 	/* XXX there is a memory leak on unload here */
316 	vfs_opv_init(opv);
317 }
318 
319 int
320 vfs_unregister(vfc)
321 	struct vfsconf *vfc;
322 {
323 	struct linker_set *l;
324 	struct sysctl_oid **oidpp;
325 	struct vfsconf *vfsp, *prev_vfsp;
326 	int error, i, maxtypenum;
327 
328 	i = vfc->vfc_typenum;
329 
330 	prev_vfsp = NULL;
331 	for (vfsp = vfsconf; vfsp;
332 			prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
333 		if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
334 			break;
335 	}
336 	if (vfsp == NULL)
337 		return EINVAL;
338 	if (vfsp->vfc_refcount)
339 		return EBUSY;
340 	if (vfc->vfc_vfsops->vfs_uninit != NULL) {
341 		error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
342 		if (error)
343 			return (error);
344 	}
345 	if (prev_vfsp)
346 		prev_vfsp->vfc_next = vfsp->vfc_next;
347 	else
348 		vfsconf = vfsp->vfc_next;
349 	if (vfsp->vfc_vfsops->vfs_oid != NULL) {
350 		l = &sysctl__vfs;
351 		for (i = l->ls_length,
352 		    oidpp = (struct sysctl_oid **)l->ls_items;
353 		    i--; oidpp++) {
354 			if (*oidpp == vfsp->vfc_vfsops->vfs_oid) {
355 				*oidpp = NULL;
356 				sysctl_order_all();
357 				break;
358 			}
359 		}
360 	}
361 	maxtypenum = VFS_GENERIC;
362 	for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
363 		if (maxtypenum < vfsp->vfc_typenum)
364 			maxtypenum = vfsp->vfc_typenum;
365 	maxvfsconf = maxtypenum + 1;
366 	return 0;
367 }
368