vfs_init.c revision 40637
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.35 1998/10/16 03:55:00 peter 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	l = &sysctl__vfs;
282	if (vfsconf)
283		for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
284			if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
285				return EEXIST;
286
287	vfc->vfc_typenum = maxvfsconf++;
288	if (vfc->vfc_vfsops->vfs_oid != NULL) {
289		/*
290		 * Attach the oid to the "vfs" node of the sysctl tree if
291		 * it isn't already there (it will be there for statically
292		 * configured vfs's).
293		 */
294		exists = 0;
295		for (i = l->ls_length,
296		    oidpp = (struct sysctl_oid **)l->ls_items;
297		    i-- != 0; oidpp++)
298			if (*oidpp == vfc->vfc_vfsops->vfs_oid) {
299				exists = 1;
300				break;
301			}
302		if (exists == 0)
303			for (i = l->ls_length,
304			    oidpp = (struct sysctl_oid **)l->ls_items;
305			    i-- != 0; oidpp++) {
306				if (*oidpp == NULL ||
307				    *oidpp == &sysctl___vfs_mod0 ||
308				    *oidpp == &sysctl___vfs_mod1) {
309					*oidpp = vfc->vfc_vfsops->vfs_oid;
310					break;
311				}
312			}
313
314		vfc->vfc_vfsops->vfs_oid->oid_number = vfc->vfc_typenum;
315		sysctl_order_all();
316	}
317	if (vfsp)
318		vfsp->vfc_next = vfc;
319	else
320		vfsconf = vfc;
321	vfc->vfc_next = NULL;
322
323	/*
324	 * Call init function for this VFS...
325	 */
326	(*(vfc->vfc_vfsops->vfs_init))(vfc);
327
328	return 0;
329}
330
331
332/*
333 * To be called at SI_SUB_VFS, SECOND, for each VFS before any are registered.
334 */
335void
336vfs_mod_opv_init(handle)
337	void *handle;
338{
339	int i;
340	struct vnodeopv_desc *opv;
341
342	opv = (struct vnodeopv_desc *)handle;
343	*(opv->opv_desc_vector_p) = NULL;
344	vfs_opv_init(opv);
345}
346
347int
348vfs_unregister(vfc)
349	struct vfsconf *vfc;
350{
351	struct linker_set *l;
352	struct sysctl_oid **oidpp;
353	struct vfsconf *vfsp, *prev_vfsp;
354	int error, i, maxtypenum;
355
356	i = vfc->vfc_typenum;
357
358	prev_vfsp = NULL;
359	for (vfsp = vfsconf; vfsp;
360			prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
361		if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
362			break;
363	}
364	if (vfsp == NULL)
365		return EINVAL;
366	if (vfsp->vfc_refcount)
367		return EBUSY;
368	if (vfc->vfc_vfsops->vfs_uninit != NULL) {
369		error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
370		if (error)
371			return (error);
372	}
373	if (prev_vfsp)
374		prev_vfsp->vfc_next = vfsp->vfc_next;
375	else
376		vfsconf = vfsp->vfc_next;
377	if (vfsp->vfc_vfsops->vfs_oid != NULL) {
378		l = &sysctl__vfs;
379		for (i = l->ls_length,
380		    oidpp = (struct sysctl_oid **)l->ls_items;
381		    i--; oidpp++) {
382			if (*oidpp == vfsp->vfc_vfsops->vfs_oid) {
383				*oidpp = NULL;
384				sysctl_order_all();
385				break;
386			}
387		}
388	}
389	maxtypenum = VFS_GENERIC;
390	for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
391		if (maxtypenum < vfsp->vfc_typenum)
392			maxtypenum = vfsp->vfc_typenum;
393	maxvfsconf = maxtypenum + 1;
394	return 0;
395}
396