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 $
71 * Manage vnode VOP operations vectors
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/kernel.h>
76 #include <sys/mount.h>
77 #include <sys/sysctl.h>
78 #include <sys/vnode.h>
79 #include <sys/malloc.h>
80 #include <sys/objcache.h>
82 static MALLOC_DEFINE(M_VNODEOP
, "vnodeops", "vnode operations vectors");
83 static MALLOC_DEFINE(M_NAMEI
, "nameibufs", "namei path buffers");
88 struct objcache
*namei_oc
;
90 static TAILQ_HEAD(, vnodeopv_node
) vnodeopv_list
;
91 static void vfs_calc_vnodeops(struct vop_ops
*ops
);
95 * Add a vnode operations (vnops) vector to the global list.
98 vfs_nadd_vnodeops_sysinit(void *data
)
100 struct vop_ops
*ops
= data
;
102 vfs_add_vnodeops(NULL
, ops
, NULL
); /* mount, template, newcopy */
106 * Unlink previously added vnode operations vector.
109 vfs_nrm_vnodeops_sysinit(void *data
)
111 struct vop_ops
*ops
= data
;
113 vfs_rm_vnodeops(NULL
, ops
, NULL
);
117 vfs_add_vnodeops(struct mount
*mp
, struct vop_ops
*template,
118 struct vop_ops
**ops_pp
)
123 KKASSERT(*ops_pp
== NULL
);
124 *ops_pp
= kmalloc(sizeof(*ops
), M_VNODEOP
, M_WAITOK
);
126 bcopy(template, ops
, sizeof(*ops
));
131 vfs_calc_vnodeops(ops
);
132 ops
->head
.vv_mount
= mp
;
135 if (mp
->mnt_vn_coherency_ops
)
136 mp
->mnt_vn_use_ops
= mp
->mnt_vn_coherency_ops
;
137 else if (mp
->mnt_vn_journal_ops
)
138 mp
->mnt_vn_use_ops
= mp
->mnt_vn_journal_ops
;
140 mp
->mnt_vn_use_ops
= mp
->mnt_vn_norm_ops
;
145 * Remove a previously installed operations vector.
147 * NOTE: Either template or ops_pp may be NULL, but not both.
150 vfs_rm_vnodeops(struct mount
*mp
, struct vop_ops
*template,
151 struct vop_ops
**ops_pp
)
163 KKASSERT(mp
== ops
->head
.vv_mount
);
165 if (mp
->mnt_vn_coherency_ops
)
166 mp
->mnt_vn_use_ops
= mp
->mnt_vn_coherency_ops
;
167 else if (mp
->mnt_vn_journal_ops
)
168 mp
->mnt_vn_use_ops
= mp
->mnt_vn_journal_ops
;
170 mp
->mnt_vn_use_ops
= mp
->mnt_vn_norm_ops
;
173 kfree(ops
, M_VNODEOP
);
177 * Calculate the VFS operations vector array. This function basically
178 * replaces any NULL entry with the default entry.
181 vfs_calc_vnodeops(struct vop_ops
*ops
)
185 for (off
= __offsetof(struct vop_ops
, vop_ops_first_field
);
186 off
<= __offsetof(struct vop_ops
, vop_ops_last_field
);
187 off
+= sizeof(void *)
189 if (*(void **)((char *)ops
+ off
) == NULL
)
190 *(void **)((char *)ops
+ off
) = ops
->vop_default
;
195 * Routines having to do with the management of the vnode table.
197 struct vattr va_null
;
200 * Initialize the vnode structures and initialize each file system type.
206 TAILQ_INIT(&vnodeopv_list
);
207 namei_oc
= objcache_create_simple(M_NAMEI
, MAXPATHLEN
);
210 * Initialize the vnode table
217 * Initialize the vnode name cache
222 * Initialize each file system type.
223 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
225 vattr_null(&va_null
);
227 SYSINIT(vfs
, SI_SUB_VFS
, SI_ORDER_FIRST
, vfsinit
, NULL
);
230 * vfsconf related functions/data.
233 /* highest defined filesystem type */
234 static int vfsconf_maxtypenum
= VFS_GENERIC
+ 1;
236 /* head of list of filesystem types */
237 static STAILQ_HEAD(, vfsconf
) vfsconf_list
=
238 STAILQ_HEAD_INITIALIZER(vfsconf_list
);
241 vfsconf_find_by_name(const char *name
)
243 struct vfsconf
*vfsp
;
245 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
246 if (strcmp(name
, vfsp
->vfc_name
) == 0)
253 vfsconf_find_by_typenum(int typenum
)
255 struct vfsconf
*vfsp
;
257 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
258 if (typenum
== vfsp
->vfc_typenum
)
265 vfsconf_add(struct vfsconf
*vfc
)
267 vfc
->vfc_typenum
= vfsconf_maxtypenum
++;
268 STAILQ_INSERT_TAIL(&vfsconf_list
, vfc
, vfc_next
);
272 vfsconf_remove(struct vfsconf
*vfc
)
276 STAILQ_REMOVE(&vfsconf_list
, vfc
, vfsconf
, vfc_next
);
278 maxtypenum
= VFS_GENERIC
;
279 STAILQ_FOREACH(vfc
, &vfsconf_list
, vfc_next
) {
280 if (maxtypenum
< vfc
->vfc_typenum
)
281 maxtypenum
= vfc
->vfc_typenum
;
283 vfsconf_maxtypenum
= maxtypenum
+ 1;
287 vfsconf_get_maxtypenum(void)
289 return vfsconf_maxtypenum
;
293 * Iterate over all vfsconf entries. Break out of the iterator
297 vfsconf_each(int (*iter
)(struct vfsconf
*element
, void *data
), void *data
)
300 struct vfsconf
*vfsp
;
302 STAILQ_FOREACH(vfsp
, &vfsconf_list
, vfc_next
) {
303 error
= iter(vfsp
, data
);
313 * After doing general initialisation, this function will
314 * call the filesystem specific initialisation vector op,
315 * i.e. vfsops->vfs_init().
318 vfs_register(struct vfsconf
*vfc
)
320 struct sysctl_oid
*oidp
;
321 struct vfsops
*vfsops
= NULL
;
323 if (vfsconf_find_by_name(vfc
->vfc_name
) != NULL
)
329 * If this filesystem has a sysctl node under vfs
330 * (i.e. vfs.xxfs), then change the oid number of that node to
331 * match the filesystem's type number. This allows user code
332 * which uses the type number to read sysctl variables defined
333 * by the filesystem to continue working. Since the oids are
334 * in a sorted list, we need to make sure the order is
335 * preserved by re-registering the oid after modifying its
338 SLIST_FOREACH(oidp
, &sysctl__vfs_children
, oid_link
)
339 if (strcmp(oidp
->oid_name
, vfc
->vfc_name
) == 0) {
340 sysctl_unregister_oid(oidp
);
341 oidp
->oid_number
= vfc
->vfc_typenum
;
342 sysctl_register_oid(oidp
);
346 * Initialise unused fields in the file system's vfsops vector.
348 * NOTE the file system should provide the mount and unmount ops
349 * at the least. In order for unmount to succeed, we also need
350 * the file system to provide us with vfsops->vfs_root otherwise
351 * the unmount(2) operation will not succeed.
353 vfsops
= vfc
->vfc_vfsops
;
354 KKASSERT(vfc
->vfc_vfsops
!= NULL
);
355 KKASSERT(vfsops
->vfs_mount
!= NULL
);
356 KKASSERT(vfsops
->vfs_root
!= NULL
);
357 KKASSERT(vfsops
->vfs_unmount
!= NULL
);
359 if (vfsops
->vfs_root
== NULL
) {
360 /* return file system's root vnode */
361 vfsops
->vfs_root
= vfs_stdroot
;
363 if (vfsops
->vfs_start
== NULL
) {
365 * Make file system operational before first use. This
366 * routine is called at mount-time for initialising MFS,
367 * not used by other file systems.
369 vfsops
->vfs_start
= vfs_stdstart
;
371 if (vfsops
->vfs_quotactl
== NULL
) {
373 vfsops
->vfs_quotactl
= vfs_stdquotactl
;
375 if (vfsops
->vfs_statfs
== NULL
) {
376 /* return file system's status */
377 vfsops
->vfs_statfs
= vfs_stdstatfs
;
379 if (vfsops
->vfs_statvfs
== NULL
) {
380 /* return file system's status */
381 vfsops
->vfs_statvfs
= vfs_stdstatvfs
;
383 if (vfsops
->vfs_sync
== NULL
) {
385 * Flush dirty buffers. File systems can use vfs_stdsync()
386 * by explicitly setting it in the vfsops->vfs_sync vector
389 vfsops
->vfs_sync
= vfs_stdnosync
;
391 if (vfsops
->vfs_vget
== NULL
) {
392 /* convert an inode number to a vnode */
393 vfsops
->vfs_vget
= vfs_stdvget
;
395 if (vfsops
->vfs_fhtovp
== NULL
) {
396 /* turn an NFS file handle into a vnode */
397 vfsops
->vfs_fhtovp
= vfs_stdfhtovp
;
399 if (vfsops
->vfs_checkexp
== NULL
) {
400 /* check if file system is exported */
401 vfsops
->vfs_checkexp
= vfs_stdcheckexp
;
403 if (vfsops
->vfs_vptofh
== NULL
) {
404 /* turn a vnode into an NFS file handle */
405 vfsops
->vfs_vptofh
= vfs_stdvptofh
;
407 if (vfsops
->vfs_init
== NULL
) {
408 /* file system specific initialisation */
409 vfsops
->vfs_init
= vfs_stdinit
;
411 if (vfsops
->vfs_uninit
== NULL
) {
412 /* file system specific uninitialisation */
413 vfsops
->vfs_uninit
= vfs_stduninit
;
415 if (vfsops
->vfs_extattrctl
== NULL
) {
416 /* extended attribute control */
417 vfsops
->vfs_extattrctl
= vfs_stdextattrctl
;
420 if (vfsops
->vfs_ncpgen_set
== NULL
) {
421 /* namecache generation number */
422 vfsops
->vfs_ncpgen_set
= vfs_stdncpgen_set
;
425 if (vfsops
->vfs_ncpgen_test
== NULL
) {
426 /* check namecache generation */
427 vfsops
->vfs_ncpgen_test
= vfs_stdncpgen_test
;
430 /* VFS quota uid and gid accounting */
431 if (vfs_quota_enabled
&& vfsops
->vfs_acinit
== NULL
) {
432 vfsops
->vfs_acinit
= vfs_stdac_init
;
434 if (vfs_quota_enabled
&& vfsops
->vfs_acdone
== NULL
) {
435 vfsops
->vfs_acdone
= vfs_stdac_done
;
439 * Call init function for this VFS...
447 * Remove previously registered VFS.
449 * After doing general de-registration like removing sysctl
450 * nodes etc, it will call the filesystem specific vector
451 * op, i.e. vfsops->vfs_uninit().
455 vfs_unregister(struct vfsconf
*vfc
)
457 struct vfsconf
*vfsp
;
460 vfsp
= vfsconf_find_by_name(vfc
->vfc_name
);
465 if (vfsp
->vfc_refcount
!= 0)
468 if (vfc
->vfc_vfsops
->vfs_uninit
!= NULL
) {
469 error
= vfs_uninit(vfc
, vfsp
);
474 vfsconf_remove(vfsp
);
479 vfs_modevent(module_t mod
, int type
, void *data
)
484 vfc
= (struct vfsconf
*)data
;
489 error
= vfs_register(vfc
);
494 error
= vfs_unregister(vfc
);
496 default: /* including MOD_SHUTDOWN */