vfs_init.c revision 109623
1193323Sed/*
2193323Sed * Copyright (c) 1989, 1993
3193323Sed *	The Regents of the University of California.  All rights reserved.
4193323Sed *
5193323Sed * This code is derived from software contributed
6193323Sed * to Berkeley by John Heidemann of the UCLA Ficus project.
7193323Sed *
8193323Sed * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
9193323Sed *
10193323Sed * Redistribution and use in source and binary forms, with or without
11193323Sed * modification, are permitted provided that the following conditions
12193323Sed * are met:
13193323Sed * 1. Redistributions of source code must retain the above copyright
14193323Sed *    notice, this list of conditions and the following disclaimer.
15193323Sed * 2. Redistributions in binary form must reproduce the above copyright
16193323Sed *    notice, this list of conditions and the following disclaimer in the
17193323Sed *    documentation and/or other materials provided with the distribution.
18252723Sdim * 3. All advertising materials mentioning features or use of this software
19193323Sed *    must display the following acknowledgement:
20205218Srdivacky *	This product includes software developed by the University of
21205218Srdivacky *	California, Berkeley and its contributors.
22235633Sdim * 4. Neither the name of the University nor the names of its contributors
23252723Sdim *    may be used to endorse or promote products derived from this software
24252723Sdim *    without specific prior written permission.
25205407Srdivacky *
26205407Srdivacky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30224145Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36193323Sed * SUCH DAMAGE.
37193323Sed *
38193323Sed *	@(#)vfs_init.c	8.3 (Berkeley) 1/4/94
39198090Srdivacky * $FreeBSD: head/sys/kern/vfs_init.c 109623 2003-01-21 08:56:16Z alfred $
40193323Sed */
41198090Srdivacky
42198090Srdivacky
43198090Srdivacky#include <sys/param.h>
44198090Srdivacky#include <sys/systm.h>
45205218Srdivacky#include <sys/kernel.h>
46205218Srdivacky#include <sys/mount.h>
47205218Srdivacky#include <sys/sysctl.h>
48205218Srdivacky#include <sys/vnode.h>
49205218Srdivacky#include <sys/malloc.h>
50205218Srdivacky
51205218Srdivacky
52205218SrdivackyMALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
53205218Srdivacky
54205218Srdivacky/*
55205218Srdivacky * The highest defined VFS number.
56205218Srdivacky */
57205218Srdivackyint maxvfsconf = VFS_GENERIC + 1;
58205407Srdivacky
59205218Srdivacky/*
60205218Srdivacky * Single-linked list of configured VFSes.
61205218Srdivacky * New entries are added/deleted by vfs_register()/vfs_unregister()
62252723Sdim */
63218893Sdimstruct vfsconf *vfsconf;
64205218Srdivacky
65218893Sdim/*
66205218Srdivacky * vfs_init.c
67205218Srdivacky *
68205218Srdivacky * Allocate and fill in operations vectors.
69205218Srdivacky *
70205218Srdivacky * An undocumented feature of this approach to defining operations is that
71205218Srdivacky * there can be multiple entries in vfs_opv_descs for the same operations
72218893Sdim * vector. This allows third parties to extend the set of operations
73205218Srdivacky * supported by another layer in a binary compatibile way. For example,
74205218Srdivacky * assume that NFS needed to be modified to support Ficus. NFS has an entry
75205218Srdivacky * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
76205218Srdivacky * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
77218893Sdim * listing those new operations Ficus adds to NFS, all without modifying the
78205218Srdivacky * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
79205218Srdivacky * that is a(whole)nother story.) This is a feature.
80205218Srdivacky */
81218893Sdim
82205218Srdivacky/* Table of known vnodeop vectors (list of VFS vnode vectors) */
83205218Srdivackystatic const struct vnodeopv_desc **vnodeopv_descs;
84205218Srdivackystatic int vnodeopv_num;
85205218Srdivacky
86218893Sdim/* Table of known descs (list of vnode op handlers "vop_access_desc") */
87205407Srdivackystatic struct vnodeop_desc **vfs_op_descs;
88205407Srdivacky/* Reference counts for vfs_op_descs */
89205407Srdivackystatic int *vfs_op_desc_refs;
90218893Sdim/* Number of descriptions */
91205218Srdivackystatic int num_op_descs;
92205218Srdivacky/* Number of entries in each description */
93205218Srdivackystatic int vfs_opv_numops = 64;
94218893Sdim
95205218Srdivacky/* Allow this number to be tuned at boot */
96205218SrdivackyTUNABLE_INT("vfs.opv_numops", &vfs_opv_numops);
97205218SrdivackySYSCTL_INT(_vfs, OID_AUTO, opv_numops, CTLFLAG_RD, &vfs_opv_numops,
98218893Sdim	0, "Maximum number of operations in vop_t vector");
99205218Srdivacky
100205218Srdivackystatic int int_cmp(const void *a, const void *b);
101205218Srdivacky
102218893Sdimstatic int
103205218Srdivackyint_cmp(const void *a, const void *b)
104205218Srdivacky{
105218893Sdim	return(*(const int *)a - *(const int *)b);
106205218Srdivacky}
107205218Srdivacky
108245431Sdim/*
109205218Srdivacky * Recalculate the operations vector/description (those parts of it that can
110193323Sed * be recalculated, that is.)
111205218Srdivacky * Always allocate operations vector large enough to hold vfs_opv_numops
112205218Srdivacky * entries. The vector is never freed or deallocated once it is initialized,
113205218Srdivacky * so that vnodes might safely reference it through their v_op pointer without
114193323Sed * vector changing suddenly from under them.
115205218Srdivacky */
116205218Srdivackystatic void
117198090Srdivackyvfs_opv_recalc(void)
118205218Srdivacky{
119205218Srdivacky	int i, j, k;
120205218Srdivacky	int *vfs_op_offsets;
121205218Srdivacky	vop_t ***opv_desc_vector_p;
122205218Srdivacky	vop_t **opv_desc_vector;
123205218Srdivacky	struct vnodeopv_entry_desc *opve_descp;
124205218Srdivacky	const struct vnodeopv_desc *opv;
125205218Srdivacky
126205218Srdivacky	if (vfs_op_descs == NULL)
127205218Srdivacky		panic("vfs_opv_recalc called with null vfs_op_descs");
128205218Srdivacky
129205218Srdivacky	/*
130218893Sdim	 * Allocate and initialize temporary array to store
131205218Srdivacky	 * offsets. Sort it to put all uninitialized entries
132205218Srdivacky	 * first and to make holes in existing offset sequence
133206083Srdivacky	 * detectable.
134218893Sdim	 */
135218893Sdim	MALLOC(vfs_op_offsets, int *,
136218893Sdim		num_op_descs * sizeof(int), M_TEMP, 0);
137218893Sdim	if (vfs_op_offsets == NULL)
138218893Sdim		panic("vfs_opv_recalc: no memory");
139205218Srdivacky	for (i = 0; i < num_op_descs; i++)
140205218Srdivacky		vfs_op_offsets[i] = vfs_op_descs[i]->vdesc_offset;
141218893Sdim	qsort(vfs_op_offsets, num_op_descs, sizeof(int), int_cmp);
142205407Srdivacky
143205407Srdivacky	/*
144205407Srdivacky	 * Run through and make sure all known descs have an offset.
145205407Srdivacky	 * Use vfs_op_offsets to locate holes in offset sequence and
146205407Srdivacky	 * reuse them.
147205407Srdivacky	 * vop_default_desc is hardwired at offset 1, and offset 0
148205407Srdivacky	 * is a panic sanity check.
149205218Srdivacky	 */
150193323Sed	j = 1; k = 1;
151193323Sed	for (i = 0; i < num_op_descs; i++) {
152193323Sed		if (vfs_op_descs[i]->vdesc_offset != 0)
153193323Sed			continue;
154193323Sed		/*
155193323Sed		 * Look at two adjacent entries vfs_op_offsets[j - 1] and
156193323Sed		 * vfs_op_offsets[j] and see if we can fit a new offset
157193323Sed		 * number in between. If not, look at the next pair until
158193323Sed		 * hole is found or the end of the vfs_op_offsets vector is
159218893Sdim		 * reached. j has been initialized to 1 above so that
160193323Sed		 * referencing (j-1)-th element is safe and the loop will
161218893Sdim		 * never execute if num_op_descs is 1. For each new value s
162218893Sdim		 * of i the j loop pick up from where previous iteration has
163218893Sdim		 * left off. When the last hole has been consumed or if no
164218893Sdim		 * hole has been found, we will start allocating new numbers
165193323Sed		 * starting from the biggest already available offset + 1.
166218893Sdim		 */
167193323Sed		for (; j < num_op_descs; j++) {
168193323Sed			if (vfs_op_offsets[j - 1] < k && vfs_op_offsets[j] > k)
169205218Srdivacky				break;
170193323Sed			k = vfs_op_offsets[j] + 1;
171193323Sed		}
172193323Sed		vfs_op_descs[i]->vdesc_offset = k++;
173193323Sed	}
174193323Sed	FREE(vfs_op_offsets, M_TEMP);
175193323Sed
176193323Sed	/* Panic if new vops will cause vector overflow */
177193323Sed	if (k > vfs_opv_numops)
178193323Sed		panic("VFS: Ran out of vop_t vector entries. %d entries required, only %d available.\n", k, vfs_opv_numops);
179193323Sed
180193323Sed	/*
181193323Sed	 * Allocate and fill in the vectors
182193323Sed	 */
183218893Sdim	for (i = 0; i < vnodeopv_num; i++) {
184218893Sdim		opv = vnodeopv_descs[i];
185218893Sdim		opv_desc_vector_p = opv->opv_desc_vector_p;
186193323Sed		if (*opv_desc_vector_p == NULL)
187193323Sed			MALLOC(*opv_desc_vector_p, vop_t **,
188193323Sed				vfs_opv_numops * sizeof(vop_t *), M_VNODE,
189193323Sed				M_ZERO);
190245431Sdim
191245431Sdim		/* Fill in, with slot 0 being to return EOPNOTSUPP */
192193323Sed		opv_desc_vector = *opv_desc_vector_p;
193193323Sed		opv_desc_vector[0] = (vop_t *)vop_eopnotsupp;
194193323Sed		for (j = 0; opv->opv_desc_ops[j].opve_op; j++) {
195193323Sed			opve_descp = &(opv->opv_desc_ops[j]);
196193323Sed			opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
197193323Sed				opve_descp->opve_impl;
198193323Sed		}
199193323Sed
200193323Sed		/* Replace unfilled routines with their default (slot 1). */
201193323Sed		opv_desc_vector = *(opv->opv_desc_vector_p);
202193323Sed		if (opv_desc_vector[1] == NULL)
203193323Sed			panic("vfs_opv_recalc: vector without a default.");
204193323Sed		for (j = 0; j < vfs_opv_numops; j++)
205193323Sed			if (opv_desc_vector[j] == NULL)
206193323Sed				opv_desc_vector[j] = opv_desc_vector[1];
207193323Sed	}
208193323Sed}
209218893Sdim
210193323Sed/* Add a set of vnode operations (a description) to the table above. */
211218893Sdimvoid
212206083Srdivackyvfs_add_vnodeops(const void *data)
213206083Srdivacky{
214193323Sed	const struct vnodeopv_desc *opv;
215193323Sed	const struct vnodeopv_desc **newopv;
216193323Sed	struct vnodeop_desc **newop;
217193323Sed	int *newref;
218218893Sdim	vop_t **opv_desc_vector;
219193323Sed	struct vnodeop_desc *desc;
220193323Sed	int i, j;
221193323Sed
222218893Sdim	opv = (const struct vnodeopv_desc *)data;
223204642Srdivacky	MALLOC(newopv, const struct vnodeopv_desc **,
224204642Srdivacky	       (vnodeopv_num + 1) * sizeof(*newopv), M_VNODE, 0);
225205407Srdivacky	if (vnodeopv_descs) {
226206083Srdivacky		bcopy(vnodeopv_descs, newopv, vnodeopv_num * sizeof(*newopv));
227218893Sdim		FREE(vnodeopv_descs, M_VNODE);
228193323Sed	}
229193323Sed	newopv[vnodeopv_num] = opv;
230193323Sed	vnodeopv_descs = newopv;
231193323Sed	vnodeopv_num++;
232193323Sed
233193323Sed	/* See if we have turned up a new vnode op desc */
234193323Sed	opv_desc_vector = *(opv->opv_desc_vector_p);
235245431Sdim	for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) {
236193323Sed		for (j = 0; j < num_op_descs; j++) {
237193323Sed			if (desc == vfs_op_descs[j]) {
238193323Sed				/* found it, increase reference count */
239193323Sed				vfs_op_desc_refs[j]++;
240193323Sed				break;
241193323Sed			}
242193323Sed		}
243221345Sdim		if (j == num_op_descs) {
244221345Sdim			/* not found, new entry */
245221345Sdim			MALLOC(newop, struct vnodeop_desc **,
246221345Sdim			       (num_op_descs + 1) * sizeof(*newop),
247221345Sdim			       M_VNODE, 0);
248221345Sdim			/* new reference count (for unload) */
249221345Sdim			MALLOC(newref, int *,
250221345Sdim				(num_op_descs + 1) * sizeof(*newref),
251221345Sdim				M_VNODE, 0);
252221345Sdim			if (vfs_op_descs) {
253221345Sdim				bcopy(vfs_op_descs, newop,
254193323Sed					num_op_descs * sizeof(*newop));
255221345Sdim				FREE(vfs_op_descs, M_VNODE);
256221345Sdim			}
257221345Sdim			if (vfs_op_desc_refs) {
258221345Sdim				bcopy(vfs_op_desc_refs, newref,
259221345Sdim					num_op_descs * sizeof(*newref));
260221345Sdim				FREE(vfs_op_desc_refs, M_VNODE);
261221345Sdim			}
262221345Sdim			newop[num_op_descs] = desc;
263221345Sdim			newref[num_op_descs] = 1;
264221345Sdim			vfs_op_descs = newop;
265221345Sdim			vfs_op_desc_refs = newref;
266221345Sdim			num_op_descs++;
267221345Sdim		}
268221345Sdim	}
269221345Sdim	vfs_opv_recalc();
270221345Sdim}
271221345Sdim
272221345Sdim/* Remove a vnode type from the vnode description table above. */
273221345Sdimvoid
274221345Sdimvfs_rm_vnodeops(const void *data)
275221345Sdim{
276221345Sdim	const struct vnodeopv_desc *opv;
277221345Sdim	const struct vnodeopv_desc **newopv;
278221345Sdim	struct vnodeop_desc **newop;
279221345Sdim	int *newref;
280221345Sdim	vop_t **opv_desc_vector;
281221345Sdim	struct vnodeop_desc *desc;
282221345Sdim	int i, j, k;
283221345Sdim
284221345Sdim	opv = (const struct vnodeopv_desc *)data;
285221345Sdim	/* Lower ref counts on descs in the table and release if zero */
286221345Sdim	for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) {
287221345Sdim		for (j = 0; j < num_op_descs; j++) {
288221345Sdim			if (desc == vfs_op_descs[j]) {
289221345Sdim				/* found it, decrease reference count */
290221345Sdim				vfs_op_desc_refs[j]--;
291221345Sdim				break;
292221345Sdim			}
293221345Sdim		}
294221345Sdim		for (j = 0; j < num_op_descs; j++) {
295193323Sed			if (vfs_op_desc_refs[j] > 0)
296193323Sed				continue;
297193323Sed			if (vfs_op_desc_refs[j] < 0)
298193323Sed				panic("vfs_remove_vnodeops: negative refcnt");
299205407Srdivacky			/* Entry is going away - replace it with defaultop */
300205407Srdivacky			for (k = 0; k < vnodeopv_num; k++) {
301205407Srdivacky				opv_desc_vector =
302205407Srdivacky					*(vnodeopv_descs[k]->opv_desc_vector_p);
303218893Sdim				if (opv_desc_vector != NULL)
304193323Sed					opv_desc_vector[desc->vdesc_offset] =
305193323Sed						opv_desc_vector[1];
306193323Sed			}
307218893Sdim			MALLOC(newop, struct vnodeop_desc **,
308193323Sed			       (num_op_descs - 1) * sizeof(*newop),
309193323Sed			       M_VNODE, 0);
310193323Sed			/* new reference count (for unload) */
311218893Sdim			MALLOC(newref, int *,
312193323Sed				(num_op_descs - 1) * sizeof(*newref),
313193323Sed				M_VNODE, 0);
314193323Sed			for (k = j; k < (num_op_descs - 1); k++) {
315218893Sdim				vfs_op_descs[k] = vfs_op_descs[k + 1];
316193323Sed				vfs_op_desc_refs[k] = vfs_op_desc_refs[k + 1];
317193323Sed			}
318221345Sdim			bcopy(vfs_op_descs, newop,
319218893Sdim				(num_op_descs - 1) * sizeof(*newop));
320193323Sed			bcopy(vfs_op_desc_refs, newref,
321193323Sed				(num_op_descs - 1) * sizeof(*newref));
322193323Sed			FREE(vfs_op_descs, M_VNODE);
323218893Sdim			FREE(vfs_op_desc_refs, M_VNODE);
324193323Sed			vfs_op_descs = newop;
325193323Sed			vfs_op_desc_refs = newref;
326205407Srdivacky			num_op_descs--;
327218893Sdim		}
328205407Srdivacky	}
329205407Srdivacky
330205407Srdivacky	for (i = 0; i < vnodeopv_num; i++) {
331205407Srdivacky		if (vnodeopv_descs[i] == opv) {
332205218Srdivacky			for (j = i; j < (vnodeopv_num - 1); j++)
333205407Srdivacky				vnodeopv_descs[j] = vnodeopv_descs[j + 1];
334193323Sed			break;
335193323Sed		}
336218893Sdim	}
337252723Sdim	if (i == vnodeopv_num)
338193323Sed		panic("vfs_remove_vnodeops: opv not found");
339206083Srdivacky	opv_desc_vector = *(opv->opv_desc_vector_p);
340218893Sdim	if (opv_desc_vector != NULL)
341193323Sed		FREE(opv_desc_vector, M_VNODE);
342218893Sdim	MALLOC(newopv, const struct vnodeopv_desc **,
343205218Srdivacky	       (vnodeopv_num - 1) * sizeof(*newopv), M_VNODE, 0);
344205407Srdivacky	bcopy(vnodeopv_descs, newopv, (vnodeopv_num - 1) * sizeof(*newopv));
345205407Srdivacky	FREE(vnodeopv_descs, M_VNODE);
346205407Srdivacky	vnodeopv_descs = newopv;
347205407Srdivacky	vnodeopv_num--;
348205407Srdivacky
349205407Srdivacky	vfs_opv_recalc();
350205407Srdivacky}
351205407Srdivacky
352218893Sdim/*
353205407Srdivacky * Routines having to do with the management of the vnode table.
354205407Srdivacky */
355205407Srdivackystruct vattr va_null;
356205407Srdivacky
357205407Srdivacky/*
358205407Srdivacky * Initialize the vnode structures and initialize each filesystem type.
359205407Srdivacky */
360205407Srdivacky/* ARGSUSED*/
361205407Srdivackystatic void
362218893Sdimvfsinit(void *dummy)
363193323Sed{
364193323Sed
365218893Sdim	vattr_null(&va_null);
366193323Sed}
367193323SedSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
368193323Sed
369193323Sed/* Register a new filesystem type in the global table */
370193323Sedint
371218893Sdimvfs_register(struct vfsconf *vfc)
372203954Srdivacky{
373203954Srdivacky	struct sysctl_oid *oidp;
374203954Srdivacky	struct vfsconf *vfsp;
375203954Srdivacky
376203954Srdivacky	vfsp = NULL;
377203954Srdivacky	if (vfsconf)
378193323Sed		for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
379221345Sdim			if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
380221345Sdim				return EEXIST;
381221345Sdim
382221345Sdim	vfc->vfc_typenum = maxvfsconf++;
383221345Sdim	if (vfsp)
384193323Sed		vfsp->vfc_next = vfc;
385221345Sdim	else
386193323Sed		vfsconf = vfc;
387193323Sed	vfc->vfc_next = NULL;
388193323Sed
389221345Sdim	/*
390221345Sdim	 * If this filesystem has a sysctl node under vfs
391193323Sed	 * (i.e. vfs.xxfs), then change the oid number of that node to
392193323Sed	 * match the filesystem's type number.  This allows user code
393193323Sed	 * which uses the type number to read sysctl variables defined
394193323Sed	 * by the filesystem to continue working. Since the oids are
395193323Sed	 * in a sorted list, we need to make sure the order is
396193323Sed	 * preserved by re-registering the oid after modifying its
397193323Sed	 * number.
398218893Sdim	 */
399193323Sed	SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
400193323Sed		if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
401193323Sed			sysctl_unregister_oid(oidp);
402193323Sed			oidp->oid_number = vfc->vfc_typenum;
403203954Srdivacky			sysctl_register_oid(oidp);
404203954Srdivacky		}
405203954Srdivacky
406203954Srdivacky	/*
407203954Srdivacky	 * Call init function for this VFS...
408203954Srdivacky	 */
409203954Srdivacky	(*(vfc->vfc_vfsops->vfs_init))(vfc);
410218893Sdim
411203954Srdivacky	return 0;
412203954Srdivacky}
413203954Srdivacky
414218893Sdim
415193323Sed/* Remove registration of a filesystem type */
416193323Sedint
417193323Sedvfs_unregister(struct vfsconf *vfc)
418218893Sdim{
419195340Sed	struct vfsconf *vfsp, *prev_vfsp;
420193323Sed	int error, i, maxtypenum;
421218893Sdim
422193323Sed	i = vfc->vfc_typenum;
423193323Sed
424193323Sed	prev_vfsp = NULL;
425193323Sed	for (vfsp = vfsconf; vfsp;
426193323Sed			prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
427203954Srdivacky		if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
428203954Srdivacky			break;
429203954Srdivacky	}
430218893Sdim	if (vfsp == NULL)
431193323Sed		return EINVAL;
432193323Sed	if (vfsp->vfc_refcount)
433193323Sed		return EBUSY;
434193323Sed	if (vfc->vfc_vfsops->vfs_uninit != NULL) {
435193323Sed		error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
436193323Sed		if (error)
437218893Sdim			return (error);
438193323Sed	}
439193323Sed	if (prev_vfsp)
440193323Sed		prev_vfsp->vfc_next = vfsp->vfc_next;
441193323Sed	else
442193323Sed		vfsconf = vfsp->vfc_next;
443193323Sed	maxtypenum = VFS_GENERIC;
444193323Sed	for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
445193323Sed		if (maxtypenum < vfsp->vfc_typenum)
446193323Sed			maxtypenum = vfsp->vfc_typenum;
447218893Sdim	maxvfsconf = maxtypenum + 1;
448193323Sed	return 0;
449193323Sed}
450245431Sdim
451193323Sed/*
452218893Sdim * Standard kernel module handling code for filesystem modules.
453193323Sed * Referenced from VFS_SET().
454245431Sdim */
455245431Sdimint
456193323Sedvfs_modevent(module_t mod, int type, void *data)
457205407Srdivacky{
458205407Srdivacky	struct vfsconf *vfc;
459205407Srdivacky	int error = 0;
460193323Sed
461205218Srdivacky	vfc = (struct vfsconf *)data;
462205407Srdivacky
463205407Srdivacky	switch (type) {
464205407Srdivacky	case MOD_LOAD:
465205218Srdivacky		if (vfc)
466218893Sdim			error = vfs_register(vfc);
467252723Sdim		break;
468252723Sdim
469252723Sdim	case MOD_UNLOAD:
470252723Sdim		if (vfc)
471252723Sdim			error = vfs_unregister(vfc);
472193323Sed		break;
473193323Sed	default:	/* including MOD_SHUTDOWN */
474193323Sed		break;
475205407Srdivacky	}
476205407Srdivacky	return (error);
477218893Sdim}
478193323Sed