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. 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.
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
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 $
72 * Manage vnode VOP operations vectors
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>
83 static MALLOC_DEFINE(M_VNODEOP
, "vnodeops", "vnode operations vectors");
84 static MALLOC_DEFINE(M_NAMEI
, "nameibufs", "namei path buffers");
89 struct objcache
*namei_oc
;
91 static TAILQ_HEAD(, vnodeopv_node
) vnodeopv_list
;
92 static void vfs_calc_vnodeops(struct vop_ops
*ops
);
96 * Add a vnode operations (vnops) vector to the global list.
99 vfs_nadd_vnodeops_sysinit(void *data
)
101 struct vop_ops
*ops
= data
;
103 vfs_add_vnodeops(NULL
, ops
, NULL
); /* mount, template, newcopy */
107 * Unlink previously added vnode operations vector.
110 vfs_nrm_vnodeops_sysinit(void *data
)
112 struct vop_ops
*ops
= data
;
114 vfs_rm_vnodeops(NULL
, ops
, NULL
);
118 vfs_add_vnodeops(struct mount
*mp
, struct vop_ops
*template,
119 struct vop_ops
**ops_pp
)
124 KKASSERT(*ops_pp
== NULL
);
125 *ops_pp
= kmalloc(sizeof(*ops
), M_VNODEOP
, M_WAITOK
);
127 bcopy(template, ops
, sizeof(*ops
));
132 vfs_calc_vnodeops(ops
);
133 ops
->head
.vv_mount
= 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
;
141 mp
->mnt_vn_use_ops
= mp
->mnt_vn_norm_ops
;
146 * Remove a previously installed operations vector.
148 * NOTE: Either template or ops_pp may be NULL, but not both.
151 vfs_rm_vnodeops(struct mount
*mp
, struct vop_ops
*template,
152 struct vop_ops
**ops_pp
)
164 KKASSERT(mp
== ops
->head
.vv_mount
);
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
;
171 mp
->mnt_vn_use_ops
= mp
->mnt_vn_norm_ops
;
174 kfree(ops
, M_VNODEOP
);
178 * Calculate the VFS operations vector array. This function basically
179 * replaces any NULL entry with the default entry.
182 vfs_calc_vnodeops(struct vop_ops
*ops
)
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 *)
190 if (*(void **)((char *)ops
+ off
) == NULL
)
191 *(void **)((char *)ops
+ off
) = ops
->vop_default
;
196 * Routines having to do with the management of the vnode table.
198 struct vattr va_null
;
201 * Initialize the vnode structures and initialize each file system type.
207 TAILQ_INIT(&vnodeopv_list
);
208 namei_oc
= objcache_create_simple(M_NAMEI
, MAXPATHLEN
);
211 * Initialize the vnode table
218 * Initialize the vnode name cache
223 * Initialize each file system type.
224 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
226 vattr_null(&va_null
);
228 SYSINIT(vfs
, SI_SUB_VFS
, SI_ORDER_FIRST
, vfsinit
, NULL
)
231 * vfsconf related functions/data.
234 /* highest defined filesystem type */
235 static int vfsconf_maxtypenum
= VFS_GENERIC
+ 1;
237 /* head of list of filesystem types */
238 static STAILQ_HEAD(, vfsconf
) vfsconf_list
=
239 STAILQ_HEAD_INITIALIZER(vfsconf_list
);
242 vfsconf_find_by_name(const char *name
)
244 struct vfsconf
*vfsp
;
246 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
247 if (strcmp(name
, vfsp
->vfc_name
) == 0)
254 vfsconf_find_by_typenum(int typenum
)
256 struct vfsconf
*vfsp
;
258 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
259 if (typenum
== vfsp
->vfc_typenum
)
266 vfsconf_add(struct vfsconf
*vfc
)
268 vfc
->vfc_typenum
= vfsconf_maxtypenum
++;
269 STAILQ_INSERT_TAIL(&vfsconf_list
, vfc
, vfc_next
);
273 vfsconf_remove(struct vfsconf
*vfc
)
277 STAILQ_REMOVE(&vfsconf_list
, vfc
, vfsconf
, vfc_next
);
279 maxtypenum
= VFS_GENERIC
;
280 STAILQ_FOREACH(vfc
, &vfsconf_list
, vfc_next
) {
281 if (maxtypenum
< vfc
->vfc_typenum
)
282 maxtypenum
= vfc
->vfc_typenum
;
284 vfsconf_maxtypenum
= maxtypenum
+ 1;
288 vfsconf_get_maxtypenum(void)
290 return vfsconf_maxtypenum
;
294 * Iterate over all vfsconf entries. Break out of the iterator
298 vfsconf_each(int (*iter
)(struct vfsconf
*element
, void *data
), void *data
)
301 struct vfsconf
*vfsp
;
303 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
304 error
= iter(vfsp
, data
);
314 * After doing general initialisation, this function will
315 * call the filesystem specific initialisation vector op,
316 * i.e. vfsops->vfs_init().
319 vfs_register(struct vfsconf
*vfc
)
321 struct sysctl_oid
*oidp
;
322 struct vfsops
*vfsops
= NULL
;
324 if (vfsconf_find_by_name(vfc
->vfc_name
) != NULL
)
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
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
);
347 * Initialise unused fields in the file system's vfsops vector.
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.
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
);
360 if (vfsops
->vfs_root
== NULL
) {
361 /* return file system's root vnode */
362 vfsops
->vfs_root
= vfs_stdroot
;
364 if (vfsops
->vfs_start
== NULL
) {
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.
370 vfsops
->vfs_start
= vfs_stdstart
;
372 if (vfsops
->vfs_quotactl
== NULL
) {
374 vfsops
->vfs_quotactl
= vfs_stdquotactl
;
376 if (vfsops
->vfs_statfs
== NULL
) {
377 /* return file system's status */
378 vfsops
->vfs_statfs
= vfs_stdstatfs
;
380 if (vfsops
->vfs_statvfs
== NULL
) {
381 /* return file system's status */
382 vfsops
->vfs_statvfs
= vfs_stdstatvfs
;
384 if (vfsops
->vfs_sync
== NULL
) {
386 * Flush dirty buffers. File systems can use vfs_stdsync()
387 * by explicitly setting it in the vfsops->vfs_sync vector
390 vfsops
->vfs_sync
= vfs_stdnosync
;
392 if (vfsops
->vfs_vget
== NULL
) {
393 /* convert an inode number to a vnode */
394 vfsops
->vfs_vget
= vfs_stdvget
;
396 if (vfsops
->vfs_fhtovp
== NULL
) {
397 /* turn an NFS file handle into a vnode */
398 vfsops
->vfs_fhtovp
= vfs_stdfhtovp
;
400 if (vfsops
->vfs_checkexp
== NULL
) {
401 /* check if file system is exported */
402 vfsops
->vfs_checkexp
= vfs_stdcheckexp
;
404 if (vfsops
->vfs_vptofh
== NULL
) {
405 /* turn a vnode into an NFS file handle */
406 vfsops
->vfs_vptofh
= vfs_stdvptofh
;
408 if (vfsops
->vfs_init
== NULL
) {
409 /* file system specific initialisation */
410 vfsops
->vfs_init
= vfs_stdinit
;
412 if (vfsops
->vfs_uninit
== NULL
) {
413 /* file system specific uninitialisation */
414 vfsops
->vfs_uninit
= vfs_stduninit
;
416 if (vfsops
->vfs_extattrctl
== NULL
) {
417 /* extended attribute control */
418 vfsops
->vfs_extattrctl
= vfs_stdextattrctl
;
421 if (vfsops
->vfs_ncpgen_set
== NULL
) {
422 /* namecache generation number */
423 vfsops
->vfs_ncpgen_set
= vfs_stdncpgen_set
;
426 if (vfsops
->vfs_ncpgen_test
== NULL
) {
427 /* check namecache generation */
428 vfsops
->vfs_ncpgen_test
= vfs_stdncpgen_test
;
431 /* VFS quota uid and gid accounting */
432 if (vfs_quota_enabled
&& vfsops
->vfs_acinit
== NULL
) {
433 vfsops
->vfs_acinit
= vfs_stdac_init
;
435 if (vfs_quota_enabled
&& vfsops
->vfs_acdone
== NULL
) {
436 vfsops
->vfs_acdone
= vfs_stdac_done
;
440 * Call init function for this VFS...
448 * Remove previously registered VFS.
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().
456 vfs_unregister(struct vfsconf
*vfc
)
458 struct vfsconf
*vfsp
;
461 vfsp
= vfsconf_find_by_name(vfc
->vfc_name
);
466 if (vfsp
->vfc_refcount
!= 0)
469 if (vfc
->vfc_vfsops
->vfs_uninit
!= NULL
) {
470 error
= vfs_uninit(vfc
, vfsp
);
475 vfsconf_remove(vfsp
);
480 vfs_modevent(module_t mod
, int type
, void *data
)
485 vfc
= (struct vfsconf
*)data
;
490 error
= vfs_register(vfc
);
495 error
= vfs_unregister(vfc
);
497 default: /* including MOD_SHUTDOWN */