xref: /dragonfly/sys/kern/vfs_init.c (revision b29f78b5)
1 /*
2  * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  * Copyright (c) 1989, 1993
36  *	The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed
39  * to Berkeley by John Heidemann of the UCLA Ficus project.
40  *
41  * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. Neither the name of the University nor the names of its contributors
52  *    may be used to endorse or promote products derived from this software
53  *    without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65  * SUCH DAMAGE.
66  *
67  *	@(#)vfs_init.c	8.3 (Berkeley) 1/4/94
68  * $FreeBSD: src/sys/kern/vfs_init.c,v 1.59 2002/04/30 18:44:32 dillon Exp $
69  * $DragonFly: src/sys/kern/vfs_init.c,v 1.15 2008/06/01 19:27:35 dillon Exp $
70  */
71 /*
72  * Manage vnode VOP operations vectors
73  */
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/kernel.h>
77 #include <sys/mount.h>
78 #include <sys/sysctl.h>
79 #include <sys/vnode.h>
80 #include <sys/malloc.h>
81 #include <sys/objcache.h>
82 
83 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors");
84 static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers");
85 
86 /*
87  * Zone for namei
88  */
89 struct objcache *namei_oc;
90 
91 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
92 static void vfs_calc_vnodeops(struct vop_ops *ops);
93 
94 
95 /*
96  * Add a vnode operations (vnops) vector to the global list.
97  */
98 void
99 vfs_nadd_vnodeops_sysinit(void *data)
100 {
101 	struct vop_ops *ops = data;
102 
103 	vfs_add_vnodeops(NULL, ops, NULL);	/* mount, template, newcopy */
104 }
105 
106 /*
107  * Unlink previously added vnode operations vector.
108  */
109 void
110 vfs_nrm_vnodeops_sysinit(void *data)
111 {
112 	struct vop_ops *ops = data;
113 
114 	vfs_rm_vnodeops(NULL, ops, NULL);
115 }
116 
117 void
118 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template,
119 		 struct vop_ops **ops_pp)
120 {
121 	struct vop_ops *ops;
122 
123 	if (ops_pp) {
124 		KKASSERT(*ops_pp == NULL);
125 		*ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK);
126 		ops = *ops_pp;
127 		bcopy(template, ops, sizeof(*ops));
128 	} else {
129 		ops = template;
130 	}
131 
132 	vfs_calc_vnodeops(ops);
133 	ops->head.vv_mount = mp;
134 
135 	if (mp) {
136 		if (mp->mnt_vn_coherency_ops)
137 			mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
138 		else if (mp->mnt_vn_journal_ops)
139 			mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
140 		else
141 			mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
142 	}
143 }
144 
145 /*
146  * Remove a previously installed operations vector.
147  *
148  * NOTE: Either template or ops_pp may be NULL, but not both.
149  */
150 void
151 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template,
152 		struct vop_ops **ops_pp)
153 {
154 	struct vop_ops *ops;
155 
156 	if (ops_pp) {
157 		ops = *ops_pp;
158 		*ops_pp = NULL;
159 	} else {
160 		ops = template;
161 	}
162 	if (ops == NULL)
163 		return;
164 	KKASSERT(mp == ops->head.vv_mount);
165 	if (mp) {
166 		if (mp->mnt_vn_coherency_ops)
167 			mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
168 		else if (mp->mnt_vn_journal_ops)
169 			mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
170 		else
171 			mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
172 	}
173 	if (ops_pp)
174 		kfree(ops, M_VNODEOP);
175 }
176 
177 /*
178  * Calculate the VFS operations vector array.  This function basically
179  * replaces any NULL entry with the default entry.
180  */
181 static void
182 vfs_calc_vnodeops(struct vop_ops *ops)
183 {
184 	int off;
185 
186 	for (off = __offsetof(struct vop_ops, vop_ops_first_field);
187 	     off <= __offsetof(struct vop_ops, vop_ops_last_field);
188 	     off += sizeof(void *)
189 	) {
190 		if (*(void **)((char *)ops + off) == NULL)
191 		    *(void **)((char *)ops + off) = ops->vop_default;
192 	}
193 }
194 
195 /*
196  * Routines having to do with the management of the vnode table.
197  */
198 struct vattr va_null;
199 
200 /*
201  * Initialize the vnode structures and initialize each file system type.
202  */
203 /* ARGSUSED*/
204 static void
205 vfsinit(void *dummy)
206 {
207 	TAILQ_INIT(&vnodeopv_list);
208 	namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN);
209 
210 	/*
211 	 * Initialize the vnode table
212 	 */
213 	vfs_subr_init();
214 	vfs_mount_init();
215 	vfs_lock_init();
216 
217 	/*
218 	 * Initialize the vnode name cache
219 	 */
220 	nchinit();
221 
222 	/*
223 	 * Initialize each file system type.
224 	 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
225 	 */
226 	vattr_null(&va_null);
227 }
228 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
229 
230 /*
231  * vfsconf related functions/data.
232  */
233 
234 /* highest defined filesystem type */
235 static int vfsconf_maxtypenum = VFS_GENERIC + 1;
236 
237 /* head of list of filesystem types */
238 static STAILQ_HEAD(, vfsconf) vfsconf_list =
239 	STAILQ_HEAD_INITIALIZER(vfsconf_list);
240 
241 struct vfsconf *
242 vfsconf_find_by_name(const char *name)
243 {
244 	struct vfsconf *vfsp;
245 
246 	STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
247 		if (strcmp(name, vfsp->vfc_name) == 0)
248 			break;
249 	}
250 	return vfsp;
251 }
252 
253 struct vfsconf *
254 vfsconf_find_by_typenum(int typenum)
255 {
256 	struct vfsconf *vfsp;
257 
258 	STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
259 		if (typenum == vfsp->vfc_typenum)
260 			break;
261 	}
262 	return vfsp;
263 }
264 
265 static void
266 vfsconf_add(struct vfsconf *vfc)
267 {
268 	vfc->vfc_typenum = vfsconf_maxtypenum++;
269 	STAILQ_INSERT_TAIL(&vfsconf_list, vfc, vfc_next);
270 }
271 
272 static void
273 vfsconf_remove(struct vfsconf *vfc)
274 {
275 	int maxtypenum;
276 
277 	STAILQ_REMOVE(&vfsconf_list, vfc, vfsconf, vfc_next);
278 
279 	maxtypenum = VFS_GENERIC;
280 	STAILQ_FOREACH(vfc, &vfsconf_list, vfc_next) {
281 		if (maxtypenum < vfc->vfc_typenum)
282 			maxtypenum = vfc->vfc_typenum;
283 	}
284 	vfsconf_maxtypenum = maxtypenum + 1;
285 }
286 
287 int
288 vfsconf_get_maxtypenum(void)
289 {
290 	return vfsconf_maxtypenum;
291 }
292 
293 /*
294  * Iterate over all vfsconf entries. Break out of the iterator
295  * by returning != 0.
296  */
297 int
298 vfsconf_each(int (*iter)(struct vfsconf *element, void *data), void *data)
299 {
300 	int error;
301 	struct vfsconf *vfsp;
302 
303 	STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
304 		error = iter(vfsp, data);
305 		if (error)
306 			return (error);
307 	}
308 	return (0);
309 }
310 
311 /*
312  * Register a VFS.
313  *
314  * After doing general initialisation, this function will
315  * call the filesystem specific initialisation vector op,
316  * i.e. vfsops->vfs_init().
317  */
318 int
319 vfs_register(struct vfsconf *vfc)
320 {
321 	struct sysctl_oid *oidp;
322 	struct vfsops *vfsops = NULL;
323 
324 	if (vfsconf_find_by_name(vfc->vfc_name) != NULL)
325 		return EEXIST;
326 
327 	vfsconf_add(vfc);
328 
329 	/*
330 	 * If this filesystem has a sysctl node under vfs
331 	 * (i.e. vfs.xxfs), then change the oid number of that node to
332 	 * match the filesystem's type number.  This allows user code
333 	 * which uses the type number to read sysctl variables defined
334 	 * by the filesystem to continue working. Since the oids are
335 	 * in a sorted list, we need to make sure the order is
336 	 * preserved by re-registering the oid after modifying its
337 	 * number.
338 	 */
339 	SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
340 		if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
341 			sysctl_unregister_oid(oidp);
342 			oidp->oid_number = vfc->vfc_typenum;
343 			sysctl_register_oid(oidp);
344 		}
345 
346 	/*
347 	 * Initialise unused fields in the file system's vfsops vector.
348 	 *
349 	 * NOTE the file system should provide the mount and unmount ops
350 	 * at the least.  In order for unmount to succeed, we also need
351 	 * the file system to provide us with vfsops->vfs_root otherwise
352 	 * the unmount(2) operation will not succeed.
353 	 */
354 	vfsops = vfc->vfc_vfsops;
355 	KKASSERT(vfc->vfc_vfsops != NULL);
356 	KKASSERT(vfsops->vfs_mount != NULL);
357 	KKASSERT(vfsops->vfs_root != NULL);
358 	KKASSERT(vfsops->vfs_unmount != NULL);
359 
360 	if (vfsops->vfs_root == NULL) {
361 		/* return file system's root vnode */
362 		vfsops->vfs_root = vfs_stdroot;
363 	}
364 	if (vfsops->vfs_start == NULL) {
365 		/*
366 		 * Make file system operational before first use.  This
367 		 * routine is called at mount-time for initialising MFS,
368 		 * not used by other file systems.
369 		 */
370 		vfsops->vfs_start = vfs_stdstart;
371 	}
372 	if (vfsops->vfs_quotactl == NULL) {
373 		/* quota control */
374 		vfsops->vfs_quotactl = vfs_stdquotactl;
375 	}
376 	if (vfsops->vfs_statfs == NULL) {
377 		/* return file system's status */
378 		vfsops->vfs_statfs = vfs_stdstatfs;
379 	}
380 	if (vfsops->vfs_statvfs == NULL) {
381 		/* return file system's status */
382 		vfsops->vfs_statvfs = vfs_stdstatvfs;
383 	}
384 	if (vfsops->vfs_sync == NULL) {
385 		/*
386 		 * Flush dirty buffers.  File systems can use vfs_stdsync()
387 		 * by explicitly setting it in the vfsops->vfs_sync vector
388 		 * entry.
389 		 */
390 		vfsops->vfs_sync = vfs_stdnosync;
391 	}
392 	if (vfsops->vfs_vget == NULL) {
393 		/* convert an inode number to a vnode */
394 		vfsops->vfs_vget = vfs_stdvget;
395 	}
396 	if (vfsops->vfs_fhtovp == NULL) {
397 		/* turn an NFS file handle into a vnode */
398 		vfsops->vfs_fhtovp = vfs_stdfhtovp;
399 	}
400 	if (vfsops->vfs_checkexp == NULL) {
401 		/* check if file system is exported */
402 		vfsops->vfs_checkexp = vfs_stdcheckexp;
403 	}
404 	if (vfsops->vfs_vptofh == NULL) {
405 		/* turn a vnode into an NFS file handle */
406 		vfsops->vfs_vptofh = vfs_stdvptofh;
407 	}
408 	if (vfsops->vfs_init == NULL) {
409 		/* file system specific initialisation */
410 		vfsops->vfs_init = vfs_stdinit;
411 	}
412 	if (vfsops->vfs_uninit == NULL) {
413 		/* file system specific uninitialisation */
414 		vfsops->vfs_uninit = vfs_stduninit;
415 	}
416 	if (vfsops->vfs_extattrctl == NULL) {
417 		/* extended attribute control */
418 		vfsops->vfs_extattrctl = vfs_stdextattrctl;
419 	}
420 
421 	if (vfsops->vfs_ncpgen_set == NULL) {
422 		/* namecache generation number */
423 		vfsops->vfs_ncpgen_set = vfs_stdncpgen_set;
424 	}
425 
426 	if (vfsops->vfs_ncpgen_test == NULL) {
427 		/* check namecache generation */
428 		vfsops->vfs_ncpgen_test = vfs_stdncpgen_test;
429 	}
430 
431 	/* VFS quota uid and gid accounting */
432 	if (vfs_quota_enabled && vfsops->vfs_acinit == NULL) {
433 		vfsops->vfs_acinit = vfs_stdac_init;
434 	}
435 	if (vfs_quota_enabled && vfsops->vfs_acdone == NULL) {
436 		vfsops->vfs_acdone = vfs_stdac_done;
437 	}
438 
439 	/*
440 	 * Call init function for this VFS...
441 	 */
442 	vfs_init(vfc);
443 	return 0;
444 }
445 
446 
447 /*
448  * Remove previously registered VFS.
449  *
450  * After doing general de-registration like removing sysctl
451  * nodes etc, it will call the filesystem specific vector
452  * op, i.e. vfsops->vfs_uninit().
453  *
454  */
455 int
456 vfs_unregister(struct vfsconf *vfc)
457 {
458 	struct vfsconf *vfsp;
459 	int error;
460 
461 	vfsp = vfsconf_find_by_name(vfc->vfc_name);
462 
463 	if (vfsp == NULL)
464 		return EINVAL;
465 
466 	if (vfsp->vfc_refcount != 0)
467 		return EBUSY;
468 
469 	if (vfc->vfc_vfsops->vfs_uninit != NULL) {
470 		error = vfs_uninit(vfc, vfsp);
471 		if (error)
472 			return (error);
473 	}
474 
475 	vfsconf_remove(vfsp);
476 	return 0;
477 }
478 
479 int
480 vfs_modevent(module_t mod, int type, void *data)
481 {
482 	struct vfsconf *vfc;
483 	int error = 0;
484 
485 	vfc = (struct vfsconf *)data;
486 
487 	switch (type) {
488 	case MOD_LOAD:
489 		if (vfc)
490 			error = vfs_register(vfc);
491 		break;
492 
493 	case MOD_UNLOAD:
494 		if (vfc)
495 			error = vfs_unregister(vfc);
496 		break;
497 	default:	/* including MOD_SHUTDOWN */
498 		break;
499 	}
500 	return (error);
501 }
502