HAMMER 40B/Many: Inode/link-count sequencer cleanup pass.
[dragonfly.git] / sys / kern / vfs_init.c
blobe85c58638d62b5cbb521fb176664549650733d4f
1 /*
2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
16 * distribution.
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
32 * SUCH DAMAGE.
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
45 * are met:
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
69 * SUCH DAMAGE.
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.14 2006/09/05 00:55:45 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");
91 * Zone for namei
93 struct objcache *namei_oc;
96 * vfs_init() will set maxvfsconf
97 * to the highest defined type number.
99 int maxvfsconf;
100 struct vfsconf *vfsconf;
102 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
103 static void vfs_calc_vnodeops(struct vop_ops *ops);
106 * Add a vnode operations (vnops) vector to the global list.
108 void
109 vfs_nadd_vnodeops_sysinit(void *data)
111 struct vop_ops *ops = data;
113 vfs_add_vnodeops(NULL, ops, NULL); /* mount, template, newcopy */
117 * Unlink previously added vnode operations vector.
119 void
120 vfs_nrm_vnodeops_sysinit(void *data)
122 struct vop_ops *ops = data;
124 vfs_rm_vnodeops(NULL, ops, NULL);
127 void
128 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template,
129 struct vop_ops **ops_pp)
131 struct vop_ops *ops;
133 if (ops_pp) {
134 KKASSERT(*ops_pp == NULL);
135 *ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK);
136 ops = *ops_pp;
137 bcopy(template, ops, sizeof(*ops));
138 } else {
139 ops = template;
142 vfs_calc_vnodeops(ops);
143 ops->head.vv_mount = mp;
145 if (mp) {
146 if (mp->mnt_vn_coherency_ops)
147 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
148 else if (mp->mnt_vn_journal_ops)
149 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
150 else
151 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
156 * Remove a previously installed operations vector.
158 * NOTE: Either template or ops_pp may be NULL, but not both.
160 void
161 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template,
162 struct vop_ops **ops_pp)
164 struct vop_ops *ops;
166 if (ops_pp) {
167 ops = *ops_pp;
168 *ops_pp = NULL;
169 } else {
170 ops = template;
172 if (ops == NULL)
173 return;
174 KKASSERT(mp == ops->head.vv_mount);
175 if (mp) {
176 if (mp->mnt_vn_coherency_ops)
177 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
178 else if (mp->mnt_vn_journal_ops)
179 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
180 else
181 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
183 if (ops_pp)
184 kfree(ops, M_VNODEOP);
188 * Calculate the VFS operations vector array. This function basically
189 * replaces any NULL entry with the default entry.
191 static void
192 vfs_calc_vnodeops(struct vop_ops *ops)
194 int off;
196 for (off = __offsetof(struct vop_ops, vop_ops_first_field);
197 off <= __offsetof(struct vop_ops, vop_ops_last_field);
198 off += sizeof(void *)
200 if (*(void **)((char *)ops + off) == NULL)
201 *(void **)((char *)ops + off) = ops->vop_default;
206 * Routines having to do with the management of the vnode table.
208 struct vattr va_null;
211 * Initialize the vnode structures and initialize each file system type.
213 /* ARGSUSED*/
214 static void
215 vfsinit(void *dummy)
217 TAILQ_INIT(&vnodeopv_list);
218 namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN);
221 * Initialize the vnode table
223 vfs_subr_init();
224 vfs_mount_init();
225 vfs_lock_init();
226 vfs_sync_init();
228 * Initialize the vnode name cache
230 nchinit();
232 * Initialize each file system type.
233 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
235 vattr_null(&va_null);
236 maxvfsconf = VFS_GENERIC + 1;
238 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
241 * Register a VFS.
243 * After doing general initialisation, this function will
244 * call the filesystem specific initialisation vector op,
245 * i.e. vfsops->vfs_init().
248 vfs_register(struct vfsconf *vfc)
250 struct sysctl_oid *oidp;
251 struct vfsconf *vfsp;
252 struct vfsops *vfsops = NULL;
254 vfsp = NULL;
255 if (vfsconf)
256 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
257 if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
258 return EEXIST;
260 vfc->vfc_typenum = maxvfsconf++;
261 if (vfsp)
262 vfsp->vfc_next = vfc;
263 else
264 vfsconf = vfc;
265 vfc->vfc_next = NULL;
268 * If this filesystem has a sysctl node under vfs
269 * (i.e. vfs.xxfs), then change the oid number of that node to
270 * match the filesystem's type number. This allows user code
271 * which uses the type number to read sysctl variables defined
272 * by the filesystem to continue working. Since the oids are
273 * in a sorted list, we need to make sure the order is
274 * preserved by re-registering the oid after modifying its
275 * number.
277 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
278 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
279 sysctl_unregister_oid(oidp);
280 oidp->oid_number = vfc->vfc_typenum;
281 sysctl_register_oid(oidp);
285 * Initialise unused fields in the file system's vfsops vector.
287 * NOTE the file system should provide the mount and unmount ops
288 * at the least. In order for unmount to succeed, we also need
289 * the file system to provide us with vfsops->vfs_root otherwise
290 * the unmount(2) operation will not succeed.
292 vfsops = vfc->vfc_vfsops;
293 KKASSERT(vfc->vfc_vfsops != NULL);
294 KKASSERT(vfsops->vfs_mount != NULL);
295 KKASSERT(vfsops->vfs_root != NULL);
296 KKASSERT(vfsops->vfs_unmount != NULL);
298 if (vfsops->vfs_root == NULL) {
299 /* return file system's root vnode */
300 vfsops->vfs_root = vfs_stdroot;
302 if (vfsops->vfs_start == NULL) {
304 * Make file system operational before first use. This
305 * routine is called at mount-time for initialising MFS,
306 * not used by other file systems.
308 vfsops->vfs_start = vfs_stdstart;
310 if (vfsops->vfs_quotactl == NULL) {
311 /* quota control */
312 vfsops->vfs_quotactl = vfs_stdquotactl;
314 if (vfsops->vfs_statfs == NULL) {
315 /* return file system's status */
316 vfsops->vfs_statfs = vfs_stdstatfs;
318 if (vfsops->vfs_sync == NULL) {
320 * Flush dirty buffers. File systems can use vfs_stdsync()
321 * by explicitly setting it in the vfsops->vfs_sync vector
322 * entry.
324 vfsops->vfs_sync = vfs_stdnosync;
326 if (vfsops->vfs_vget == NULL) {
327 /* convert an inode number to a vnode */
328 vfsops->vfs_vget = vfs_stdvget;
330 if (vfsops->vfs_fhtovp == NULL) {
331 /* turn an NFS file handle into a vnode */
332 vfsops->vfs_fhtovp = vfs_stdfhtovp;
334 if (vfsops->vfs_checkexp == NULL) {
335 /* check if file system is exported */
336 vfsops->vfs_checkexp = vfs_stdcheckexp;
338 if (vfsops->vfs_vptofh == NULL) {
339 /* turn a vnode into an NFS file handle */
340 vfsops->vfs_vptofh = vfs_stdvptofh;
342 if (vfsops->vfs_init == NULL) {
343 /* file system specific initialisation */
344 vfsops->vfs_init = vfs_stdinit;
346 if (vfsops->vfs_uninit == NULL) {
347 /* file system specific uninitialisation */
348 vfsops->vfs_uninit = vfs_stduninit;
350 if (vfsops->vfs_extattrctl == NULL) {
351 /* extended attribute control */
352 vfsops->vfs_extattrctl = vfs_stdextattrctl;
356 * Call init function for this VFS...
358 (*(vfc->vfc_vfsops->vfs_init))(vfc);
360 return 0;
365 * Remove previously registered VFS.
367 * After doing general de-registration like removing sysctl
368 * nodes etc, it will call the filesystem specific vector
369 * op, i.e. vfsops->vfs_uninit().
373 vfs_unregister(struct vfsconf *vfc)
375 struct vfsconf *vfsp, *prev_vfsp;
376 int error, i, maxtypenum;
378 i = vfc->vfc_typenum;
380 prev_vfsp = NULL;
381 for (vfsp = vfsconf; vfsp;
382 prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
383 if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
384 break;
386 if (vfsp == NULL)
387 return EINVAL;
388 if (vfsp->vfc_refcount)
389 return EBUSY;
390 if (vfc->vfc_vfsops->vfs_uninit != NULL) {
391 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
392 if (error)
393 return (error);
395 if (prev_vfsp)
396 prev_vfsp->vfc_next = vfsp->vfc_next;
397 else
398 vfsconf = vfsp->vfc_next;
399 maxtypenum = VFS_GENERIC;
400 for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
401 if (maxtypenum < vfsp->vfc_typenum)
402 maxtypenum = vfsp->vfc_typenum;
403 maxvfsconf = maxtypenum + 1;
404 return 0;
408 vfs_modevent(module_t mod, int type, void *data)
410 struct vfsconf *vfc;
411 int error = 0;
413 vfc = (struct vfsconf *)data;
415 switch (type) {
416 case MOD_LOAD:
417 if (vfc)
418 error = vfs_register(vfc);
419 break;
421 case MOD_UNLOAD:
422 if (vfc)
423 error = vfs_unregister(vfc);
424 break;
425 default: /* including MOD_SHUTDOWN */
426 break;
428 return (error);