vfs_init.c revision 40880
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
52static void	vfs_op_init __P((void));
53
54static void vfsinit __P((void *));
55SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
56
57MALLOC_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
68extern 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 */
77extern struct linker_set sysctl__vfs;
78static int mod_xx;
79SYSCTL_INT(_vfs, OID_AUTO, mod0, CTLFLAG_RD, &mod_xx, 0, "");
80SYSCTL_INT(_vfs, OID_AUTO, mod1, CTLFLAG_RD, &mod_xx, 0, "");
81
82/*
83 * Zone for namei
84 */
85struct 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 */
109void
110vfs_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 */
183static void
184vfs_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 */
207extern struct vnodeops dead_vnodeops;
208extern struct vnodeops spec_vnodeops;
209struct vattr va_null;
210
211/*
212 * Initialize the vnode structures and initialize each file system type.
213 */
214/* ARGSUSED*/
215static void
216vfsinit(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
242int
243vfs_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 */
306void
307vfs_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
319int
320vfs_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