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.10 2005/09/17 07:43:00 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 <vm/vm_zone.h>
87 static MALLOC_DEFINE(M_VNODEOP
, "vnodeops", "vnode operations vectors");
92 struct vm_zone
*namei_zone
;
95 * vfs_init() will set maxvfsconf
96 * to the highest defined type number.
99 struct vfsconf
*vfsconf
;
101 static TAILQ_HEAD(, vnodeopv_node
) vnodeopv_list
;
102 static void vfs_recalc_vnodeops(void);
105 * Add a vnode operations (vnops) vector to the global list.
108 vfs_add_vnodeops_sysinit(const void *data
)
110 const struct vnodeopv_desc
*vdesc
= data
;
112 vfs_add_vnodeops(NULL
, vdesc
->opv_desc_vector
,
113 vdesc
->opv_desc_ops
, vdesc
->opv_flags
);
117 * Unlink previously added vnode operations vector.
120 vfs_rm_vnodeops_sysinit(const void *data
)
122 const struct vnodeopv_desc
*vdesc
= data
;
124 vfs_rm_vnodeops(vdesc
->opv_desc_vector
);
128 vfs_add_vnodeops(struct mount
*mp
, struct vop_ops
**vops_pp
,
129 struct vnodeopv_entry_desc
*descs
, int flags
)
131 struct vnodeopv_node
*node
;
134 node
= malloc(sizeof(*node
), M_VNODEOP
, M_ZERO
|M_WAITOK
);
135 if ((ops
= *vops_pp
) == NULL
) {
136 ops
= malloc(sizeof(struct vop_ops
),
137 M_VNODEOP
, M_ZERO
|M_WAITOK
);
143 ops
->vv_flags
|= flags
;
146 * Journal and coherency ops inherit normal ops flags
148 if (vops_pp
== &mp
->mnt_vn_coherency_ops
&& mp
->mnt_vn_norm_ops
)
149 ops
->vv_flags
|= mp
->mnt_vn_norm_ops
->vv_flags
;
150 if (vops_pp
== &mp
->mnt_vn_journal_ops
&& mp
->mnt_vn_norm_ops
)
151 ops
->vv_flags
|= mp
->mnt_vn_norm_ops
->vv_flags
;
154 TAILQ_INSERT_TAIL(&vnodeopv_list
, node
, entry
);
156 vfs_recalc_vnodeops();
159 if (mp
->mnt_vn_coherency_ops
)
160 mp
->mnt_vn_use_ops
= mp
->mnt_vn_coherency_ops
;
161 else if (mp
->mnt_vn_journal_ops
)
162 mp
->mnt_vn_use_ops
= mp
->mnt_vn_journal_ops
;
164 mp
->mnt_vn_use_ops
= mp
->mnt_vn_norm_ops
;
169 vfs_rm_vnodeops(struct vop_ops
**vops_pp
)
171 struct vop_ops
*ops
= *vops_pp
;
172 struct vnodeopv_node
*node
;
178 TAILQ_FOREACH(node
, &vnodeopv_list
, entry
) {
179 if (node
->ops
== ops
)
183 printf("vfs_rm_vnodeops: unable to find ops: %p\n", ops
);
186 TAILQ_REMOVE(&vnodeopv_list
, node
, entry
);
187 free(node
, M_VNODEOP
);
188 KKASSERT(ops
!= NULL
&& ops
->vv_refs
> 0);
189 if (--ops
->vv_refs
== 0) {
191 if ((mp
= ops
->vv_mount
) != NULL
) {
192 if (mp
->mnt_vn_coherency_ops
)
193 mp
->mnt_vn_use_ops
= mp
->mnt_vn_coherency_ops
;
194 else if (mp
->mnt_vn_journal_ops
)
195 mp
->mnt_vn_use_ops
= mp
->mnt_vn_journal_ops
;
197 mp
->mnt_vn_use_ops
= mp
->mnt_vn_norm_ops
;
199 free(ops
, M_VNODEOP
);
201 vfs_recalc_vnodeops();
205 * Recalculate VFS operations vectors
208 vfs_recalc_vnodeops(void)
210 struct vnodeopv_node
*node
;
211 struct vnodeopv_entry_desc
*desc
;
213 struct vop_ops
*vnew
;
217 * Because vop_ops may be active we can't just blow them away, we
218 * have to generate new vop_ops and then copy them into the running
219 * vop_ops. Any missing entries will be assigned to the default
220 * entry. If the default entry itself is missing it will be assigned
223 TAILQ_FOREACH(node
, &vnodeopv_list
, entry
) {
225 if ((vnew
= ops
->vv_new
) == NULL
) {
226 vnew
= malloc(sizeof(struct vop_ops
),
227 M_VNODEOP
, M_ZERO
|M_WAITOK
);
229 vnew
->vop_default
= vop_eopnotsupp
;
231 for (desc
= node
->descs
; desc
->opve_op
; ++desc
) {
232 off
= desc
->opve_op
->vdesc_offset
;
233 *(void **)((char *)vnew
+ off
) = desc
->opve_func
;
235 for (off
= __offsetof(struct vop_ops
, vop_ops_first_field
);
236 off
<= __offsetof(struct vop_ops
, vop_ops_last_field
);
237 off
+= sizeof(void **)
239 if (*(void **)((char *)vnew
+ off
) == NULL
)
240 *(void **)((char *)vnew
+ off
) = vnew
->vop_default
;
245 * Copy the temporary ops into the running configuration and then
248 TAILQ_FOREACH(node
, &vnodeopv_list
, entry
) {
250 if ((vnew
= ops
->vv_new
) == NULL
)
252 for (off
= __offsetof(struct vop_ops
, vop_ops_first_field
);
253 off
<= __offsetof(struct vop_ops
, vop_ops_last_field
);
254 off
+= sizeof(void **)
256 *(void **)((char *)ops
+ off
) =
257 *(void **)((char *)vnew
+ off
);
260 free(vnew
, M_VNODEOP
);
265 * Routines having to do with the management of the vnode table.
267 struct vattr va_null
;
270 * Initialize the vnode structures and initialize each file system type.
276 TAILQ_INIT(&vnodeopv_list
);
277 namei_zone
= zinit("NAMEI", MAXPATHLEN
, 0, 0, 2);
280 * Initialize the vnode table
287 * Initialize the vnode name cache
291 * Initialize each file system type.
292 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
294 vattr_null(&va_null
);
295 maxvfsconf
= VFS_GENERIC
+ 1;
297 SYSINIT(vfs
, SI_SUB_VFS
, SI_ORDER_FIRST
, vfsinit
, NULL
)
302 * After doing general initialisation, this function will
303 * call the filesystem specific initialisation vector op,
304 * i.e. vfsops->vfs_init().
307 vfs_register(struct vfsconf
*vfc
)
309 struct sysctl_oid
*oidp
;
310 struct vfsconf
*vfsp
;
311 struct vfsops
*vfsops
= NULL
;
315 for (vfsp
= vfsconf
; vfsp
->vfc_next
; vfsp
= vfsp
->vfc_next
)
316 if (strcmp(vfc
->vfc_name
, vfsp
->vfc_name
) == 0)
319 vfc
->vfc_typenum
= maxvfsconf
++;
321 vfsp
->vfc_next
= vfc
;
324 vfc
->vfc_next
= NULL
;
327 * If this filesystem has a sysctl node under vfs
328 * (i.e. vfs.xxfs), then change the oid number of that node to
329 * match the filesystem's type number. This allows user code
330 * which uses the type number to read sysctl variables defined
331 * by the filesystem to continue working. Since the oids are
332 * in a sorted list, we need to make sure the order is
333 * preserved by re-registering the oid after modifying its
336 SLIST_FOREACH(oidp
, &sysctl__vfs_children
, oid_link
)
337 if (strcmp(oidp
->oid_name
, vfc
->vfc_name
) == 0) {
338 sysctl_unregister_oid(oidp
);
339 oidp
->oid_number
= vfc
->vfc_typenum
;
340 sysctl_register_oid(oidp
);
344 * Initialise unused fields in the file system's vfsops vector.
346 * NOTE the file system should provide the mount and unmount ops
347 * at the least. In order for unmount to succeed, we also need
348 * the file system to provide us with vfsops->vfs_root otherwise
349 * the unmount(2) operation will not succeed.
351 vfsops
= vfc
->vfc_vfsops
;
352 KKASSERT(vfc
->vfc_vfsops
!= NULL
);
353 KKASSERT(vfsops
->vfs_mount
!= NULL
);
354 KKASSERT(vfsops
->vfs_root
!= NULL
);
355 KKASSERT(vfsops
->vfs_unmount
!= NULL
);
357 if (vfsops
->vfs_root
== NULL
) {
358 /* return file system's root vnode */
359 vfsops
->vfs_root
= vfs_stdroot
;
361 if (vfsops
->vfs_start
== NULL
) {
363 * Make file system operational before first use. This
364 * routine is called at mount-time for initialising MFS,
365 * not used by other file systems.
367 vfsops
->vfs_start
= vfs_stdstart
;
369 if (vfsops
->vfs_quotactl
== NULL
) {
371 vfsops
->vfs_quotactl
= vfs_stdquotactl
;
373 if (vfsops
->vfs_statfs
== NULL
) {
374 /* return file system's status */
375 vfsops
->vfs_statfs
= vfs_stdstatfs
;
377 if (vfsops
->vfs_sync
== NULL
) {
379 * Flush dirty buffers. File systems can use vfs_stdsync()
380 * by explicitly setting it in the vfsops->vfs_sync vector
383 vfsops
->vfs_sync
= vfs_stdnosync
;
385 if (vfsops
->vfs_vget
== NULL
) {
386 /* convert an inode number to a vnode */
387 vfsops
->vfs_vget
= vfs_stdvget
;
389 if (vfsops
->vfs_fhtovp
== NULL
) {
390 /* turn an NFS file handle into a vnode */
391 vfsops
->vfs_fhtovp
= vfs_stdfhtovp
;
393 if (vfsops
->vfs_checkexp
== NULL
) {
394 /* check if file system is exported */
395 vfsops
->vfs_checkexp
= vfs_stdcheckexp
;
397 if (vfsops
->vfs_vptofh
== NULL
) {
398 /* turn a vnode into an NFS file handle */
399 vfsops
->vfs_vptofh
= vfs_stdvptofh
;
401 if (vfsops
->vfs_init
== NULL
) {
402 /* file system specific initialisation */
403 vfsops
->vfs_init
= vfs_stdinit
;
405 if (vfsops
->vfs_uninit
== NULL
) {
406 /* file system specific uninitialisation */
407 vfsops
->vfs_uninit
= vfs_stduninit
;
409 if (vfsops
->vfs_extattrctl
== NULL
) {
410 /* extended attribute control */
411 vfsops
->vfs_extattrctl
= vfs_stdextattrctl
;
415 * Call init function for this VFS...
417 (*(vfc
->vfc_vfsops
->vfs_init
))(vfc
);
424 * Remove previously registered VFS.
426 * After doing general de-registration like removing sysctl
427 * nodes etc, it will call the filesystem specific vector
428 * op, i.e. vfsops->vfs_uninit().
432 vfs_unregister(struct vfsconf
*vfc
)
434 struct vfsconf
*vfsp
, *prev_vfsp
;
435 int error
, i
, maxtypenum
;
437 i
= vfc
->vfc_typenum
;
440 for (vfsp
= vfsconf
; vfsp
;
441 prev_vfsp
= vfsp
, vfsp
= vfsp
->vfc_next
) {
442 if (!strcmp(vfc
->vfc_name
, vfsp
->vfc_name
))
447 if (vfsp
->vfc_refcount
)
449 if (vfc
->vfc_vfsops
->vfs_uninit
!= NULL
) {
450 error
= (*vfc
->vfc_vfsops
->vfs_uninit
)(vfsp
);
455 prev_vfsp
->vfc_next
= vfsp
->vfc_next
;
457 vfsconf
= vfsp
->vfc_next
;
458 maxtypenum
= VFS_GENERIC
;
459 for (vfsp
= vfsconf
; vfsp
!= NULL
; vfsp
= vfsp
->vfc_next
)
460 if (maxtypenum
< vfsp
->vfc_typenum
)
461 maxtypenum
= vfsp
->vfc_typenum
;
462 maxvfsconf
= maxtypenum
+ 1;
467 vfs_modevent(module_t mod
, int type
, void *data
)
472 vfc
= (struct vfsconf
*)data
;
477 error
= vfs_register(vfc
);
482 error
= vfs_unregister(vfc
);
484 default: /* including MOD_SHUTDOWN */