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