2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 * Copyright (c) 1989, 1993
36 * The Regents of the University of California. All rights reserved.
38 * This code is derived from software contributed
39 * to Berkeley by John Heidemann of the UCLA Ficus project.
41 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
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.
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
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.15 2008/06/01 19:27:35 dillon Exp $
76 * Manage vnode VOP operations vectors
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>
87 static MALLOC_DEFINE(M_VNODEOP
, "vnodeops", "vnode operations vectors");
88 static MALLOC_DEFINE(M_NAMEI
, "nameibufs", "namei path buffers");
93 struct objcache
*namei_oc
;
95 static TAILQ_HEAD(, vnodeopv_node
) vnodeopv_list
;
96 static void vfs_calc_vnodeops(struct vop_ops
*ops
);
100 * Add a vnode operations (vnops) vector to the global list.
103 vfs_nadd_vnodeops_sysinit(void *data
)
105 struct vop_ops
*ops
= data
;
107 vfs_add_vnodeops(NULL
, ops
, NULL
); /* mount, template, newcopy */
111 * Unlink previously added vnode operations vector.
114 vfs_nrm_vnodeops_sysinit(void *data
)
116 struct vop_ops
*ops
= data
;
118 vfs_rm_vnodeops(NULL
, ops
, NULL
);
122 vfs_add_vnodeops(struct mount
*mp
, struct vop_ops
*template,
123 struct vop_ops
**ops_pp
)
128 KKASSERT(*ops_pp
== NULL
);
129 *ops_pp
= kmalloc(sizeof(*ops
), M_VNODEOP
, M_WAITOK
);
131 bcopy(template, ops
, sizeof(*ops
));
136 vfs_calc_vnodeops(ops
);
137 ops
->head
.vv_mount
= mp
;
140 if (mp
->mnt_vn_coherency_ops
)
141 mp
->mnt_vn_use_ops
= mp
->mnt_vn_coherency_ops
;
142 else if (mp
->mnt_vn_journal_ops
)
143 mp
->mnt_vn_use_ops
= mp
->mnt_vn_journal_ops
;
145 mp
->mnt_vn_use_ops
= mp
->mnt_vn_norm_ops
;
150 * Remove a previously installed operations vector.
152 * NOTE: Either template or ops_pp may be NULL, but not both.
155 vfs_rm_vnodeops(struct mount
*mp
, struct vop_ops
*template,
156 struct vop_ops
**ops_pp
)
168 KKASSERT(mp
== ops
->head
.vv_mount
);
170 if (mp
->mnt_vn_coherency_ops
)
171 mp
->mnt_vn_use_ops
= mp
->mnt_vn_coherency_ops
;
172 else if (mp
->mnt_vn_journal_ops
)
173 mp
->mnt_vn_use_ops
= mp
->mnt_vn_journal_ops
;
175 mp
->mnt_vn_use_ops
= mp
->mnt_vn_norm_ops
;
178 kfree(ops
, M_VNODEOP
);
182 * Calculate the VFS operations vector array. This function basically
183 * replaces any NULL entry with the default entry.
186 vfs_calc_vnodeops(struct vop_ops
*ops
)
190 for (off
= __offsetof(struct vop_ops
, vop_ops_first_field
);
191 off
<= __offsetof(struct vop_ops
, vop_ops_last_field
);
192 off
+= sizeof(void *)
194 if (*(void **)((char *)ops
+ off
) == NULL
)
195 *(void **)((char *)ops
+ off
) = ops
->vop_default
;
200 * Routines having to do with the management of the vnode table.
202 struct vattr va_null
;
205 * Initialize the vnode structures and initialize each file system type.
211 TAILQ_INIT(&vnodeopv_list
);
212 namei_oc
= objcache_create_simple(M_NAMEI
, MAXPATHLEN
);
215 * Initialize the vnode table
222 * Initialize the vnode name cache
226 * Initialize each file system type.
227 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
229 vattr_null(&va_null
);
231 SYSINIT(vfs
, SI_SUB_VFS
, SI_ORDER_FIRST
, vfsinit
, NULL
)
234 * vfsconf related functions/data.
237 /* highest defined filesystem type */
238 static int vfsconf_maxtypenum
= VFS_GENERIC
+ 1;
240 /* head of list of filesystem types */
241 static STAILQ_HEAD(, vfsconf
) vfsconf_list
=
242 STAILQ_HEAD_INITIALIZER(vfsconf_list
);
245 vfsconf_find_by_name(const char *name
)
247 struct vfsconf
*vfsp
;
249 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
250 if (strcmp(name
, vfsp
->vfc_name
) == 0)
257 vfsconf_find_by_typenum(int typenum
)
259 struct vfsconf
*vfsp
;
261 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
262 if (typenum
== vfsp
->vfc_typenum
)
269 vfsconf_add(struct vfsconf
*vfc
)
271 vfc
->vfc_typenum
= vfsconf_maxtypenum
++;
272 STAILQ_INSERT_TAIL(&vfsconf_list
, vfc
, vfc_next
);
276 vfsconf_remove(struct vfsconf
*vfc
)
280 STAILQ_REMOVE(&vfsconf_list
, vfc
, vfsconf
, vfc_next
);
282 maxtypenum
= VFS_GENERIC
;
283 STAILQ_FOREACH(vfc
, &vfsconf_list
, vfc_next
) {
284 if (maxtypenum
< vfc
->vfc_typenum
)
285 maxtypenum
= vfc
->vfc_typenum
;
287 vfsconf_maxtypenum
= maxtypenum
+ 1;
291 vfsconf_get_maxtypenum(void)
293 return vfsconf_maxtypenum
;
297 * Iterate over all vfsconf entries. Break out of the iterator
301 vfsconf_each(int (*iter
)(struct vfsconf
*element
, void *data
), void *data
)
304 struct vfsconf
*vfsp
;
306 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
307 error
= iter(vfsp
, data
);
317 * After doing general initialisation, this function will
318 * call the filesystem specific initialisation vector op,
319 * i.e. vfsops->vfs_init().
322 vfs_register(struct vfsconf
*vfc
)
324 struct sysctl_oid
*oidp
;
325 struct vfsops
*vfsops
= NULL
;
327 if (vfsconf_find_by_name(vfc
->vfc_name
) != NULL
)
333 * If this filesystem has a sysctl node under vfs
334 * (i.e. vfs.xxfs), then change the oid number of that node to
335 * match the filesystem's type number. This allows user code
336 * which uses the type number to read sysctl variables defined
337 * by the filesystem to continue working. Since the oids are
338 * in a sorted list, we need to make sure the order is
339 * preserved by re-registering the oid after modifying its
342 SLIST_FOREACH(oidp
, &sysctl__vfs_children
, oid_link
)
343 if (strcmp(oidp
->oid_name
, vfc
->vfc_name
) == 0) {
344 sysctl_unregister_oid(oidp
);
345 oidp
->oid_number
= vfc
->vfc_typenum
;
346 sysctl_register_oid(oidp
);
350 * Initialise unused fields in the file system's vfsops vector.
352 * NOTE the file system should provide the mount and unmount ops
353 * at the least. In order for unmount to succeed, we also need
354 * the file system to provide us with vfsops->vfs_root otherwise
355 * the unmount(2) operation will not succeed.
357 vfsops
= vfc
->vfc_vfsops
;
358 KKASSERT(vfc
->vfc_vfsops
!= NULL
);
359 KKASSERT(vfsops
->vfs_mount
!= NULL
);
360 KKASSERT(vfsops
->vfs_root
!= NULL
);
361 KKASSERT(vfsops
->vfs_unmount
!= NULL
);
363 if (vfsops
->vfs_root
== NULL
) {
364 /* return file system's root vnode */
365 vfsops
->vfs_root
= vfs_stdroot
;
367 if (vfsops
->vfs_start
== NULL
) {
369 * Make file system operational before first use. This
370 * routine is called at mount-time for initialising MFS,
371 * not used by other file systems.
373 vfsops
->vfs_start
= vfs_stdstart
;
375 if (vfsops
->vfs_quotactl
== NULL
) {
377 vfsops
->vfs_quotactl
= vfs_stdquotactl
;
379 if (vfsops
->vfs_statfs
== NULL
) {
380 /* return file system's status */
381 vfsops
->vfs_statfs
= vfs_stdstatfs
;
383 if (vfsops
->vfs_statvfs
== NULL
) {
384 /* return file system's status */
385 vfsops
->vfs_statvfs
= vfs_stdstatvfs
;
387 if (vfsops
->vfs_sync
== NULL
) {
389 * Flush dirty buffers. File systems can use vfs_stdsync()
390 * by explicitly setting it in the vfsops->vfs_sync vector
393 vfsops
->vfs_sync
= vfs_stdnosync
;
395 if (vfsops
->vfs_vget
== NULL
) {
396 /* convert an inode number to a vnode */
397 vfsops
->vfs_vget
= vfs_stdvget
;
399 if (vfsops
->vfs_fhtovp
== NULL
) {
400 /* turn an NFS file handle into a vnode */
401 vfsops
->vfs_fhtovp
= vfs_stdfhtovp
;
403 if (vfsops
->vfs_checkexp
== NULL
) {
404 /* check if file system is exported */
405 vfsops
->vfs_checkexp
= vfs_stdcheckexp
;
407 if (vfsops
->vfs_vptofh
== NULL
) {
408 /* turn a vnode into an NFS file handle */
409 vfsops
->vfs_vptofh
= vfs_stdvptofh
;
411 if (vfsops
->vfs_init
== NULL
) {
412 /* file system specific initialisation */
413 vfsops
->vfs_init
= vfs_stdinit
;
415 if (vfsops
->vfs_uninit
== NULL
) {
416 /* file system specific uninitialisation */
417 vfsops
->vfs_uninit
= vfs_stduninit
;
419 if (vfsops
->vfs_extattrctl
== NULL
) {
420 /* extended attribute control */
421 vfsops
->vfs_extattrctl
= vfs_stdextattrctl
;
425 * Call init function for this VFS...
427 (*(vfc
->vfc_vfsops
->vfs_init
))(vfc
);
434 * Remove previously registered VFS.
436 * After doing general de-registration like removing sysctl
437 * nodes etc, it will call the filesystem specific vector
438 * op, i.e. vfsops->vfs_uninit().
442 vfs_unregister(struct vfsconf
*vfc
)
444 struct vfsconf
*vfsp
;
447 vfsp
= vfsconf_find_by_name(vfc
->vfc_name
);
452 if (vfsp
->vfc_refcount
!= 0)
455 if (vfc
->vfc_vfsops
->vfs_uninit
!= NULL
) {
456 error
= (*vfc
->vfc_vfsops
->vfs_uninit
)(vfsp
);
461 vfsconf_remove(vfsp
);
466 vfs_modevent(module_t mod
, int type
, void *data
)
471 vfc
= (struct vfsconf
*)data
;
476 error
= vfs_register(vfc
);
481 error
= vfs_unregister(vfc
);
483 default: /* including MOD_SHUTDOWN */