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.12 2006/06/01 06:10:50 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;
96 * vfs_init() will set maxvfsconf
97 * to the highest defined type number.
100 struct vfsconf *vfsconf;
102 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
103 static void vfs_recalc_vnodeops(void);
106 * Add a vnode operations (vnops) vector to the global list.
109 vfs_add_vnodeops_sysinit(const void *data)
111 const struct vnodeopv_desc *vdesc = data;
113 vfs_add_vnodeops(NULL, vdesc->opv_desc_vector,
114 vdesc->opv_desc_ops, vdesc->opv_flags);
118 * Unlink previously added vnode operations vector.
121 vfs_rm_vnodeops_sysinit(const void *data)
123 const struct vnodeopv_desc *vdesc = data;
125 vfs_rm_vnodeops(vdesc->opv_desc_vector);
129 vfs_add_vnodeops(struct mount *mp, struct vop_ops **vops_pp,
130 struct vnodeopv_entry_desc *descs, int flags)
132 struct vnodeopv_node *node;
135 node = malloc(sizeof(*node), M_VNODEOP, M_ZERO|M_WAITOK);
136 KKASSERT(*vops_pp == NULL);
137 if ((ops = *vops_pp) == NULL) {
138 ops = malloc(sizeof(struct vop_ops),
139 M_VNODEOP, M_ZERO|M_WAITOK);
145 ops->vv_flags |= flags;
148 * Journal and coherency ops inherit normal ops flags
150 if (vops_pp == &mp->mnt_vn_coherency_ops && mp->mnt_vn_norm_ops)
151 ops->vv_flags |= mp->mnt_vn_norm_ops->vv_flags;
152 if (vops_pp == &mp->mnt_vn_journal_ops && mp->mnt_vn_norm_ops)
153 ops->vv_flags |= mp->mnt_vn_norm_ops->vv_flags;
156 TAILQ_INSERT_TAIL(&vnodeopv_list, node, entry);
158 vfs_recalc_vnodeops();
161 if (mp->mnt_vn_coherency_ops)
162 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
163 else if (mp->mnt_vn_journal_ops)
164 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
166 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
171 vfs_rm_vnodeops(struct vop_ops **vops_pp)
173 struct vop_ops *ops = *vops_pp;
174 struct vnodeopv_node *node;
180 TAILQ_FOREACH(node, &vnodeopv_list, entry) {
181 if (node->ops == ops)
185 printf("vfs_rm_vnodeops: unable to find ops: %p\n", ops);
188 TAILQ_REMOVE(&vnodeopv_list, node, entry);
189 free(node, M_VNODEOP);
190 KKASSERT(ops != NULL && ops->vv_refs > 0);
191 if (--ops->vv_refs == 0) {
193 if ((mp = ops->vv_mount) != NULL) {
194 if (mp->mnt_vn_coherency_ops)
195 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
196 else if (mp->mnt_vn_journal_ops)
197 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
199 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
201 free(ops, M_VNODEOP);
203 vfs_recalc_vnodeops();
207 * Recalculate VFS operations vectors
210 vfs_recalc_vnodeops(void)
212 struct vnodeopv_node *node;
213 struct vnodeopv_entry_desc *desc;
215 struct vop_ops *vnew;
219 * Because vop_ops may be active we can't just blow them away, we
220 * have to generate new vop_ops and then copy them into the running
221 * vop_ops. Any missing entries will be assigned to the default
222 * entry. If the default entry itself is missing it will be assigned
225 TAILQ_FOREACH(node, &vnodeopv_list, entry) {
227 if ((vnew = ops->vv_new) == NULL) {
228 vnew = malloc(sizeof(struct vop_ops),
229 M_VNODEOP, M_ZERO|M_WAITOK);
231 vnew->vop_default = vop_eopnotsupp;
233 for (desc = node->descs; desc->opve_op; ++desc) {
234 off = desc->opve_op->vdesc_offset;
235 *(void **)((char *)vnew + off) = desc->opve_func;
237 for (off = __offsetof(struct vop_ops, vop_ops_first_field);
238 off <= __offsetof(struct vop_ops, vop_ops_last_field);
239 off += sizeof(void **)
241 if (*(void **)((char *)vnew + off) == NULL)
242 *(void **)((char *)vnew + off) = vnew->vop_default;
247 * Copy the temporary ops into the running configuration and then
250 TAILQ_FOREACH(node, &vnodeopv_list, entry) {
252 if ((vnew = ops->vv_new) == NULL)
254 for (off = __offsetof(struct vop_ops, vop_ops_first_field);
255 off <= __offsetof(struct vop_ops, vop_ops_last_field);
256 off += sizeof(void **)
258 *(void **)((char *)ops + off) =
259 *(void **)((char *)vnew + off);
262 free(vnew, M_VNODEOP);
267 * Routines having to do with the management of the vnode table.
269 struct vattr va_null;
272 * Initialize the vnode structures and initialize each file system type.
278 TAILQ_INIT(&vnodeopv_list);
279 namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN);
282 * Initialize the vnode table
289 * Initialize the vnode name cache
293 * Initialize each file system type.
294 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
296 vattr_null(&va_null);
297 maxvfsconf = VFS_GENERIC + 1;
299 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
304 * After doing general initialisation, this function will
305 * call the filesystem specific initialisation vector op,
306 * i.e. vfsops->vfs_init().
309 vfs_register(struct vfsconf *vfc)
311 struct sysctl_oid *oidp;
312 struct vfsconf *vfsp;
313 struct vfsops *vfsops = NULL;
317 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
318 if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
321 vfc->vfc_typenum = maxvfsconf++;
323 vfsp->vfc_next = vfc;
326 vfc->vfc_next = 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_sync == NULL) {
381 * Flush dirty buffers. File systems can use vfs_stdsync()
382 * by explicitly setting it in the vfsops->vfs_sync vector
385 vfsops->vfs_sync = vfs_stdnosync;
387 if (vfsops->vfs_vget == NULL) {
388 /* convert an inode number to a vnode */
389 vfsops->vfs_vget = vfs_stdvget;
391 if (vfsops->vfs_fhtovp == NULL) {
392 /* turn an NFS file handle into a vnode */
393 vfsops->vfs_fhtovp = vfs_stdfhtovp;
395 if (vfsops->vfs_checkexp == NULL) {
396 /* check if file system is exported */
397 vfsops->vfs_checkexp = vfs_stdcheckexp;
399 if (vfsops->vfs_vptofh == NULL) {
400 /* turn a vnode into an NFS file handle */
401 vfsops->vfs_vptofh = vfs_stdvptofh;
403 if (vfsops->vfs_init == NULL) {
404 /* file system specific initialisation */
405 vfsops->vfs_init = vfs_stdinit;
407 if (vfsops->vfs_uninit == NULL) {
408 /* file system specific uninitialisation */
409 vfsops->vfs_uninit = vfs_stduninit;
411 if (vfsops->vfs_extattrctl == NULL) {
412 /* extended attribute control */
413 vfsops->vfs_extattrctl = vfs_stdextattrctl;
417 * Call init function for this VFS...
419 (*(vfc->vfc_vfsops->vfs_init))(vfc);
426 * Remove previously registered VFS.
428 * After doing general de-registration like removing sysctl
429 * nodes etc, it will call the filesystem specific vector
430 * op, i.e. vfsops->vfs_uninit().
434 vfs_unregister(struct vfsconf *vfc)
436 struct vfsconf *vfsp, *prev_vfsp;
437 int error, i, maxtypenum;
439 i = vfc->vfc_typenum;
442 for (vfsp = vfsconf; vfsp;
443 prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
444 if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
449 if (vfsp->vfc_refcount)
451 if (vfc->vfc_vfsops->vfs_uninit != NULL) {
452 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
457 prev_vfsp->vfc_next = vfsp->vfc_next;
459 vfsconf = vfsp->vfc_next;
460 maxtypenum = VFS_GENERIC;
461 for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
462 if (maxtypenum < vfsp->vfc_typenum)
463 maxtypenum = vfsp->vfc_typenum;
464 maxvfsconf = maxtypenum + 1;
469 vfs_modevent(module_t mod, int type, void *data)
474 vfc = (struct vfsconf *)data;
479 error = vfs_register(vfc);
484 error = vfs_unregister(vfc);
486 default: /* including MOD_SHUTDOWN */