xref: /freebsd/sys/kern/vfs_init.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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  * $FreeBSD$
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 
53 MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
54 
55 /*
56  * The highest defined VFS number.
57  */
58 int maxvfsconf = VFS_GENERIC + 1;
59 struct vfsconf *vfsconf;
60 
61 /*
62  * vfs_init.c
63  *
64  * Allocate and fill in operations vectors.
65  *
66  * An undocumented feature of this approach to defining operations is that
67  * there can be multiple entries in vfs_opv_descs for the same operations
68  * vector. This allows third parties to extend the set of operations
69  * supported by another layer in a binary compatibile way. For example,
70  * assume that NFS needed to be modified to support Ficus. NFS has an entry
71  * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
72  * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
73  * listing those new operations Ficus adds to NFS, all without modifying the
74  * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
75  * that is a(whole)nother story.) This is a feature.
76  */
77 
78 /* Table of known vnodeop vectors (list of VFS vnode vectors) */
79 static const struct vnodeopv_desc **vnodeopv_descs;
80 static int vnodeopv_num;
81 
82 /* Table of known descs (list of vnode op handlers "vop_access_desc") */
83 static struct vnodeop_desc **vfs_op_descs;
84 static int *vfs_op_desc_refs;			/* reference counts */
85 static int num_op_descs;
86 static int vfs_opv_numops;
87 
88 static void
89 vfs_opv_recalc(void)
90 {
91 	int i, j;
92 	vop_t ***opv_desc_vector_p;
93 	vop_t **opv_desc_vector;
94 	struct vnodeopv_entry_desc *opve_descp;
95 	const struct vnodeopv_desc *opv;
96 
97 	if (vfs_op_descs == NULL)
98 		panic("vfs_opv_recalc called with null vfs_op_descs");
99 
100 	/*
101 	 * Run through and make sure all known descs have an offset
102 	 *
103 	 * vop_default_desc is hardwired at offset 1, and offset 0
104 	 * is a panic sanity check.
105 	 */
106 	vfs_opv_numops = 0;
107 	for (i = 0; i < num_op_descs; i++)
108 		if (vfs_opv_numops < (vfs_op_descs[i]->vdesc_offset + 1))
109 			vfs_opv_numops = vfs_op_descs[i]->vdesc_offset + 1;
110 	for (i = 0; i < num_op_descs; i++)
111 		if (vfs_op_descs[i]->vdesc_offset == 0)
112 			vfs_op_descs[i]->vdesc_offset = vfs_opv_numops++;
113 	/*
114 	 * Allocate and fill in the vectors
115 	 */
116 	for (i = 0; i < vnodeopv_num; i++) {
117 		opv = vnodeopv_descs[i];
118 		opv_desc_vector_p = opv->opv_desc_vector_p;
119 		if (*opv_desc_vector_p)
120 			FREE(*opv_desc_vector_p, M_VNODE);
121 		MALLOC(*opv_desc_vector_p, vop_t **,
122 			vfs_opv_numops * sizeof(vop_t *), M_VNODE,
123 			M_WAITOK | M_ZERO);
124 		if (*opv_desc_vector_p == NULL)
125 			panic("no memory for vop_t ** vector");
126 
127 		/* Fill in, with slot 0 being to return EOPNOTSUPP */
128 		opv_desc_vector = *opv_desc_vector_p;
129 		opv_desc_vector[0] = (vop_t *)vop_eopnotsupp;
130 		for (j = 0; opv->opv_desc_ops[j].opve_op; j++) {
131 			opve_descp = &(opv->opv_desc_ops[j]);
132 			opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
133 				opve_descp->opve_impl;
134 		}
135 
136 		/* Replace unfilled routines with their default (slot 1). */
137 		opv_desc_vector = *(opv->opv_desc_vector_p);
138 		if (opv_desc_vector[1] == NULL)
139 			panic("vfs_opv_recalc: vector without a default.");
140 		for (j = 0; j < vfs_opv_numops; j++)
141 			if (opv_desc_vector[j] == NULL)
142 				opv_desc_vector[j] = opv_desc_vector[1];
143 	}
144 }
145 
146 void
147 vfs_add_vnodeops(const void *data)
148 {
149 	const struct vnodeopv_desc *opv;
150 	const struct vnodeopv_desc **newopv;
151 	struct vnodeop_desc **newop;
152 	int *newref;
153 	vop_t **opv_desc_vector;
154 	struct vnodeop_desc *desc;
155 	int i, j;
156 
157 	opv = (const struct vnodeopv_desc *)data;
158 	MALLOC(newopv, const struct vnodeopv_desc **,
159 	       (vnodeopv_num + 1) * sizeof(*newopv), M_VNODE, M_WAITOK);
160 	if (newopv == NULL)
161 		panic("vfs_add_vnodeops: no memory");
162 	if (vnodeopv_descs) {
163 		bcopy(vnodeopv_descs, newopv, vnodeopv_num * sizeof(*newopv));
164 		FREE(vnodeopv_descs, M_VNODE);
165 	}
166 	newopv[vnodeopv_num] = opv;
167 	vnodeopv_descs = newopv;
168 	vnodeopv_num++;
169 
170 	/* See if we have turned up a new vnode op desc */
171 	opv_desc_vector = *(opv->opv_desc_vector_p);
172 	for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) {
173 		for (j = 0; j < num_op_descs; j++) {
174 			if (desc == vfs_op_descs[j]) {
175 				/* found it, increase reference count */
176 				vfs_op_desc_refs[j]++;
177 				break;
178 			}
179 		}
180 		if (j == num_op_descs) {
181 			/* not found, new entry */
182 			MALLOC(newop, struct vnodeop_desc **,
183 			       (num_op_descs + 1) * sizeof(*newop),
184 			       M_VNODE, M_WAITOK);
185 			if (newop == NULL)
186 				panic("vfs_add_vnodeops: no memory for desc");
187 			/* new reference count (for unload) */
188 			MALLOC(newref, int *,
189 				(num_op_descs + 1) * sizeof(*newref),
190 				M_VNODE, M_WAITOK);
191 			if (newref == NULL)
192 				panic("vfs_add_vnodeops: no memory for refs");
193 			if (vfs_op_descs) {
194 				bcopy(vfs_op_descs, newop,
195 					num_op_descs * sizeof(*newop));
196 				FREE(vfs_op_descs, M_VNODE);
197 			}
198 			if (vfs_op_desc_refs) {
199 				bcopy(vfs_op_desc_refs, newref,
200 					num_op_descs * sizeof(*newref));
201 				FREE(vfs_op_desc_refs, M_VNODE);
202 			}
203 			newop[num_op_descs] = desc;
204 			newref[num_op_descs] = 1;
205 			vfs_op_descs = newop;
206 			vfs_op_desc_refs = newref;
207 			num_op_descs++;
208 		}
209 	}
210 	vfs_opv_recalc();
211 }
212 
213 void
214 vfs_rm_vnodeops(const void *data)
215 {
216 	const struct vnodeopv_desc *opv;
217 	const struct vnodeopv_desc **newopv;
218 	struct vnodeop_desc **newop;
219 	int *newref;
220 	vop_t **opv_desc_vector;
221 	struct vnodeop_desc *desc;
222 	int i, j, k;
223 
224 	opv = (const struct vnodeopv_desc *)data;
225 	/* Lower ref counts on descs in the table and release if zero */
226 	opv_desc_vector = *(opv->opv_desc_vector_p);
227 	for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) {
228 		for (j = 0; j < num_op_descs; j++) {
229 			if (desc == vfs_op_descs[j]) {
230 				/* found it, decrease reference count */
231 				vfs_op_desc_refs[j]--;
232 				break;
233 			}
234 		}
235 		for (j = 0; j < num_op_descs; j++) {
236 			if (vfs_op_desc_refs[j] > 0)
237 				continue;
238 			if (vfs_op_desc_refs[j] < 0)
239 				panic("vfs_remove_vnodeops: negative refcnt");
240 			MALLOC(newop, struct vnodeop_desc **,
241 			       (num_op_descs - 1) * sizeof(*newop),
242 			       M_VNODE, M_WAITOK);
243 			if (newop == NULL)
244 				panic("vfs_remove_vnodeops: no memory for desc");
245 			/* new reference count (for unload) */
246 			MALLOC(newref, int *,
247 				(num_op_descs - 1) * sizeof(*newref),
248 				M_VNODE, M_WAITOK);
249 			if (newref == NULL)
250 				panic("vfs_remove_vnodeops: no memory for refs");
251 			for (k = j; k < (num_op_descs - 1); k++) {
252 				vfs_op_descs[k] = vfs_op_descs[k + 1];
253 				vfs_op_desc_refs[k] = vfs_op_desc_refs[k + 1];
254 			}
255 			bcopy(vfs_op_descs, newop,
256 				(num_op_descs - 1) * sizeof(*newop));
257 			bcopy(vfs_op_desc_refs, newref,
258 				(num_op_descs - 1) * sizeof(*newref));
259 			FREE(vfs_op_descs, M_VNODE);
260 			FREE(vfs_op_desc_refs, M_VNODE);
261 			vfs_op_descs = newop;
262 			vfs_op_desc_refs = newref;
263 			num_op_descs--;
264 		}
265 	}
266 
267 	for (i = 0; i < vnodeopv_num; i++) {
268 		if (vnodeopv_descs[i] == opv) {
269 			for (j = i; j < (vnodeopv_num - 1); j++)
270 				vnodeopv_descs[j] = vnodeopv_descs[j + 1];
271 			break;
272 		}
273 	}
274 	if (i == vnodeopv_num)
275 		panic("vfs_remove_vnodeops: opv not found");
276 	MALLOC(newopv, const struct vnodeopv_desc **,
277 	       (vnodeopv_num - 1) * sizeof(*newopv), M_VNODE, M_WAITOK);
278 	if (newopv == NULL)
279 		panic("vfs_remove_vnodeops: no memory");
280 	bcopy(vnodeopv_descs, newopv, (vnodeopv_num - 1) * sizeof(*newopv));
281 	FREE(vnodeopv_descs, M_VNODE);
282 	vnodeopv_descs = newopv;
283 	vnodeopv_num--;
284 
285 	vfs_opv_recalc();
286 }
287 
288 /*
289  * Routines having to do with the management of the vnode table.
290  */
291 struct vattr va_null;
292 
293 /*
294  * Initialize the vnode structures and initialize each file system type.
295  */
296 /* ARGSUSED*/
297 static void
298 vfsinit(void *dummy)
299 {
300 
301 	vattr_null(&va_null);
302 }
303 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
304 
305 int
306 vfs_register(struct vfsconf *vfc)
307 {
308 	struct sysctl_oid *oidp;
309 	struct vfsconf *vfsp;
310 
311 	vfsp = NULL;
312 	if (vfsconf)
313 		for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
314 			if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
315 				return EEXIST;
316 
317 	vfc->vfc_typenum = maxvfsconf++;
318 	if (vfsp)
319 		vfsp->vfc_next = vfc;
320 	else
321 		vfsconf = vfc;
322 	vfc->vfc_next = NULL;
323 
324 	/*
325 	 * If this filesystem has a sysctl node under vfs
326 	 * (i.e. vfs.xxfs), then change the oid number of that node to
327 	 * match the filesystem's type number.  This allows user code
328 	 * which uses the type number to read sysctl variables defined
329 	 * by the filesystem to continue working. Since the oids are
330 	 * in a sorted list, we need to make sure the order is
331 	 * preserved by re-registering the oid after modifying its
332 	 * number.
333 	 */
334 	SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
335 		if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
336 			sysctl_unregister_oid(oidp);
337 			oidp->oid_number = vfc->vfc_typenum;
338 			sysctl_register_oid(oidp);
339 		}
340 
341 	/*
342 	 * Call init function for this VFS...
343 	 */
344 	(*(vfc->vfc_vfsops->vfs_init))(vfc);
345 
346 	return 0;
347 }
348 
349 
350 int
351 vfs_unregister(struct vfsconf *vfc)
352 {
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 	maxtypenum = VFS_GENERIC;
378 	for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
379 		if (maxtypenum < vfsp->vfc_typenum)
380 			maxtypenum = vfsp->vfc_typenum;
381 	maxvfsconf = maxtypenum + 1;
382 	return 0;
383 }
384 
385 int
386 vfs_modevent(module_t mod, int type, void *data)
387 {
388 	struct vfsconf *vfc;
389 	int error = 0;
390 
391 	vfc = (struct vfsconf *)data;
392 
393 	switch (type) {
394 	case MOD_LOAD:
395 		if (vfc)
396 			error = vfs_register(vfc);
397 		break;
398 
399 	case MOD_UNLOAD:
400 		if (vfc)
401 			error = vfs_unregister(vfc);
402 		break;
403 	default:	/* including MOD_SHUTDOWN */
404 		break;
405 	}
406 	return (error);
407 }
408