xref: /dragonfly/sys/kern/vfs_init.c (revision 6b5c5d0d)
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. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *	This product includes software developed by the University of
54  *	California, Berkeley and its contributors.
55  * 4. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  *
71  *	@(#)vfs_init.c	8.3 (Berkeley) 1/4/94
72  * $FreeBSD: src/sys/kern/vfs_init.c,v 1.59 2002/04/30 18:44:32 dillon Exp $
73  * $DragonFly: src/sys/kern/vfs_init.c,v 1.14 2006/09/05 00:55:45 dillon Exp $
74  */
75 /*
76  * Manage vnode VOP operations vectors
77  */
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/kernel.h>
81 #include <sys/mount.h>
82 #include <sys/sysctl.h>
83 #include <sys/vnode.h>
84 #include <sys/malloc.h>
85 #include <sys/objcache.h>
86 
87 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors");
88 static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers");
89 
90 /*
91  * Zone for namei
92  */
93 struct objcache *namei_oc;
94 
95 /*
96  * vfs_init() will set maxvfsconf
97  * to the highest defined type number.
98  */
99 int maxvfsconf;
100 struct vfsconf *vfsconf;
101 
102 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
103 static void vfs_calc_vnodeops(struct vop_ops *ops);
104 
105 /*
106  * Add a vnode operations (vnops) vector to the global list.
107  */
108 void
109 vfs_nadd_vnodeops_sysinit(void *data)
110 {
111 	struct vop_ops *ops = data;
112 
113 	vfs_add_vnodeops(NULL, ops, NULL);	/* mount, template, newcopy */
114 }
115 
116 /*
117  * Unlink previously added vnode operations vector.
118  */
119 void
120 vfs_nrm_vnodeops_sysinit(void *data)
121 {
122 	struct vop_ops *ops = data;
123 
124 	vfs_rm_vnodeops(NULL, ops, NULL);
125 }
126 
127 void
128 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template,
129 		 struct vop_ops **ops_pp)
130 {
131 	struct vop_ops *ops;
132 
133 	if (ops_pp) {
134 		KKASSERT(*ops_pp == NULL);
135 		*ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK);
136 		ops = *ops_pp;
137 		bcopy(template, ops, sizeof(*ops));
138 	} else {
139 		ops = template;
140 	}
141 
142 	vfs_calc_vnodeops(ops);
143 	ops->head.vv_mount = mp;
144 
145 	if (mp) {
146 		if (mp->mnt_vn_coherency_ops)
147 			mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
148 		else if (mp->mnt_vn_journal_ops)
149 			mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
150 		else
151 			mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
152 	}
153 }
154 
155 /*
156  * Remove a previously installed operations vector.
157  *
158  * NOTE: Either template or ops_pp may be NULL, but not both.
159  */
160 void
161 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template,
162 		struct vop_ops **ops_pp)
163 {
164 	struct vop_ops *ops;
165 
166 	if (ops_pp) {
167 		ops = *ops_pp;
168 		*ops_pp = NULL;
169 	} else {
170 		ops = template;
171 	}
172 	if (ops == NULL)
173 		return;
174 	KKASSERT(mp == ops->head.vv_mount);
175 	if (mp) {
176 		if (mp->mnt_vn_coherency_ops)
177 			mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
178 		else if (mp->mnt_vn_journal_ops)
179 			mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
180 		else
181 			mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
182 	}
183 	if (ops_pp)
184 		kfree(ops, M_VNODEOP);
185 }
186 
187 /*
188  * Calculate the VFS operations vector array.  This function basically
189  * replaces any NULL entry with the default entry.
190  */
191 static void
192 vfs_calc_vnodeops(struct vop_ops *ops)
193 {
194 	int off;
195 
196 	for (off = __offsetof(struct vop_ops, vop_ops_first_field);
197 	     off <= __offsetof(struct vop_ops, vop_ops_last_field);
198 	     off += sizeof(void *)
199 	) {
200 		if (*(void **)((char *)ops + off) == NULL)
201 		    *(void **)((char *)ops + off) = ops->vop_default;
202 	}
203 }
204 
205 /*
206  * Routines having to do with the management of the vnode table.
207  */
208 struct vattr va_null;
209 
210 /*
211  * Initialize the vnode structures and initialize each file system type.
212  */
213 /* ARGSUSED*/
214 static void
215 vfsinit(void *dummy)
216 {
217 	TAILQ_INIT(&vnodeopv_list);
218 	namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN);
219 
220 	/*
221 	 * Initialize the vnode table
222 	 */
223 	vfs_subr_init();
224 	vfs_mount_init();
225 	vfs_lock_init();
226 	vfs_sync_init();
227 	/*
228 	 * Initialize the vnode name cache
229 	 */
230 	nchinit();
231 	/*
232 	 * Initialize each file system type.
233 	 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
234 	 */
235 	vattr_null(&va_null);
236 	maxvfsconf = VFS_GENERIC + 1;
237 }
238 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
239 
240 /*
241  * Register a VFS.
242  *
243  * After doing general initialisation, this function will
244  * call the filesystem specific initialisation vector op,
245  * i.e. vfsops->vfs_init().
246  */
247 int
248 vfs_register(struct vfsconf *vfc)
249 {
250 	struct sysctl_oid *oidp;
251 	struct vfsconf *vfsp;
252 	struct vfsops *vfsops = NULL;
253 
254 	vfsp = NULL;
255 	if (vfsconf)
256 		for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
257 			if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
258 				return EEXIST;
259 
260 	vfc->vfc_typenum = maxvfsconf++;
261 	if (vfsp)
262 		vfsp->vfc_next = vfc;
263 	else
264 		vfsconf = vfc;
265 	vfc->vfc_next = NULL;
266 
267 	/*
268 	 * If this filesystem has a sysctl node under vfs
269 	 * (i.e. vfs.xxfs), then change the oid number of that node to
270 	 * match the filesystem's type number.  This allows user code
271 	 * which uses the type number to read sysctl variables defined
272 	 * by the filesystem to continue working. Since the oids are
273 	 * in a sorted list, we need to make sure the order is
274 	 * preserved by re-registering the oid after modifying its
275 	 * number.
276 	 */
277 	SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
278 		if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
279 			sysctl_unregister_oid(oidp);
280 			oidp->oid_number = vfc->vfc_typenum;
281 			sysctl_register_oid(oidp);
282 		}
283 
284 	/*
285 	 * Initialise unused fields in the file system's vfsops vector.
286 	 *
287 	 * NOTE the file system should provide the mount and unmount ops
288 	 * at the least.  In order for unmount to succeed, we also need
289 	 * the file system to provide us with vfsops->vfs_root otherwise
290 	 * the unmount(2) operation will not succeed.
291 	 */
292 	vfsops = vfc->vfc_vfsops;
293 	KKASSERT(vfc->vfc_vfsops != NULL);
294 	KKASSERT(vfsops->vfs_mount != NULL);
295 	KKASSERT(vfsops->vfs_root != NULL);
296 	KKASSERT(vfsops->vfs_unmount != NULL);
297 
298 	if (vfsops->vfs_root == NULL) {
299 		/* return file system's root vnode */
300 		vfsops->vfs_root = vfs_stdroot;
301 	}
302 	if (vfsops->vfs_start == NULL) {
303 		/*
304 		 * Make file system operational before first use.  This
305 		 * routine is called at mount-time for initialising MFS,
306 		 * not used by other file systems.
307 		 */
308 		vfsops->vfs_start = vfs_stdstart;
309 	}
310 	if (vfsops->vfs_quotactl == NULL) {
311 		/* quota control */
312 		vfsops->vfs_quotactl = vfs_stdquotactl;
313 	}
314 	if (vfsops->vfs_statfs == NULL) {
315 		/* return file system's status */
316 		vfsops->vfs_statfs = vfs_stdstatfs;
317 	}
318 	if (vfsops->vfs_sync == NULL) {
319 		/*
320 		 * Flush dirty buffers.  File systems can use vfs_stdsync()
321 		 * by explicitly setting it in the vfsops->vfs_sync vector
322 		 * entry.
323 		 */
324 		vfsops->vfs_sync = vfs_stdnosync;
325 	}
326 	if (vfsops->vfs_vget == NULL) {
327 		/* convert an inode number to a vnode */
328 		vfsops->vfs_vget = vfs_stdvget;
329 	}
330 	if (vfsops->vfs_fhtovp == NULL) {
331 		/* turn an NFS file handle into a vnode */
332 		vfsops->vfs_fhtovp = vfs_stdfhtovp;
333 	}
334 	if (vfsops->vfs_checkexp == NULL) {
335 		/* check if file system is exported */
336 		vfsops->vfs_checkexp = vfs_stdcheckexp;
337 	}
338 	if (vfsops->vfs_vptofh == NULL) {
339 		/* turn a vnode into an NFS file handle */
340 		vfsops->vfs_vptofh = vfs_stdvptofh;
341 	}
342 	if (vfsops->vfs_init == NULL) {
343 		/* file system specific initialisation */
344 		vfsops->vfs_init = vfs_stdinit;
345 	}
346 	if (vfsops->vfs_uninit == NULL) {
347 		/* file system specific uninitialisation */
348 		vfsops->vfs_uninit = vfs_stduninit;
349 	}
350 	if (vfsops->vfs_extattrctl == NULL) {
351 		/* extended attribute control */
352 		vfsops->vfs_extattrctl = vfs_stdextattrctl;
353 	}
354 
355 	/*
356 	 * Call init function for this VFS...
357 	 */
358 	(*(vfc->vfc_vfsops->vfs_init))(vfc);
359 
360 	return 0;
361 }
362 
363 
364 /*
365  * Remove previously registered VFS.
366  *
367  * After doing general de-registration like removing sysctl
368  * nodes etc, it will call the filesystem specific vector
369  * op, i.e. vfsops->vfs_uninit().
370  *
371  */
372 int
373 vfs_unregister(struct vfsconf *vfc)
374 {
375 	struct vfsconf *vfsp, *prev_vfsp;
376 	int error, i, maxtypenum;
377 
378 	i = vfc->vfc_typenum;
379 
380 	prev_vfsp = NULL;
381 	for (vfsp = vfsconf; vfsp;
382 			prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
383 		if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
384 			break;
385 	}
386 	if (vfsp == NULL)
387 		return EINVAL;
388 	if (vfsp->vfc_refcount)
389 		return EBUSY;
390 	if (vfc->vfc_vfsops->vfs_uninit != NULL) {
391 		error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
392 		if (error)
393 			return (error);
394 	}
395 	if (prev_vfsp)
396 		prev_vfsp->vfc_next = vfsp->vfc_next;
397 	else
398 		vfsconf = vfsp->vfc_next;
399 	maxtypenum = VFS_GENERIC;
400 	for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
401 		if (maxtypenum < vfsp->vfc_typenum)
402 			maxtypenum = vfsp->vfc_typenum;
403 	maxvfsconf = maxtypenum + 1;
404 	return 0;
405 }
406 
407 int
408 vfs_modevent(module_t mod, int type, void *data)
409 {
410 	struct vfsconf *vfc;
411 	int error = 0;
412 
413 	vfc = (struct vfsconf *)data;
414 
415 	switch (type) {
416 	case MOD_LOAD:
417 		if (vfc)
418 			error = vfs_register(vfc);
419 		break;
420 
421 	case MOD_UNLOAD:
422 		if (vfc)
423 			error = vfs_unregister(vfc);
424 		break;
425 	default:	/* including MOD_SHUTDOWN */
426 		break;
427 	}
428 	return (error);
429 }
430