kernel - Add trigger_syncer(), VFS_MODIFYING()
[dragonfly.git] / sys / kern / vfs_init.c
... / ...
CommitLineData
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:
10 *
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.
20 *
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.
33 *
34 *
35 * Copyright (c) 1989, 1993
36 * The Regents of the University of California. All rights reserved.
37 *
38 * This code is derived from software contributed
39 * to Berkeley by John Heidemann of the UCLA Ficus project.
40 *
41 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
42 *
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. 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.
54 *
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
65 * SUCH DAMAGE.
66 *
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 */
70/*
71 * Manage vnode VOP operations vectors
72 */
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>
81
82static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors");
83static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers");
84
85/*
86 * Zone for namei
87 */
88struct objcache *namei_oc;
89
90static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
91static void vfs_calc_vnodeops(struct vop_ops *ops);
92
93
94/*
95 * Add a vnode operations (vnops) vector to the global list.
96 */
97void
98vfs_nadd_vnodeops_sysinit(void *data)
99{
100 struct vop_ops *ops = data;
101
102 vfs_add_vnodeops(NULL, ops, NULL); /* mount, template, newcopy */
103}
104
105/*
106 * Unlink previously added vnode operations vector.
107 */
108void
109vfs_nrm_vnodeops_sysinit(void *data)
110{
111 struct vop_ops *ops = data;
112
113 vfs_rm_vnodeops(NULL, ops, NULL);
114}
115
116void
117vfs_add_vnodeops(struct mount *mp, struct vop_ops *template,
118 struct vop_ops **ops_pp)
119{
120 struct vop_ops *ops;
121
122 if (ops_pp) {
123 KKASSERT(*ops_pp == NULL);
124 *ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK);
125 ops = *ops_pp;
126 bcopy(template, ops, sizeof(*ops));
127 } else {
128 ops = template;
129 }
130
131 vfs_calc_vnodeops(ops);
132 ops->head.vv_mount = mp;
133
134 if (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;
139 else
140 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
141 }
142}
143
144/*
145 * Remove a previously installed operations vector.
146 *
147 * NOTE: Either template or ops_pp may be NULL, but not both.
148 */
149void
150vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template,
151 struct vop_ops **ops_pp)
152{
153 struct vop_ops *ops;
154
155 if (ops_pp) {
156 ops = *ops_pp;
157 *ops_pp = NULL;
158 } else {
159 ops = template;
160 }
161 if (ops == NULL)
162 return;
163 KKASSERT(mp == ops->head.vv_mount);
164 if (mp) {
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;
169 else
170 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
171 }
172 if (ops_pp)
173 kfree(ops, M_VNODEOP);
174}
175
176/*
177 * Calculate the VFS operations vector array. This function basically
178 * replaces any NULL entry with the default entry.
179 */
180static void
181vfs_calc_vnodeops(struct vop_ops *ops)
182{
183 int off;
184
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 *)
188 ) {
189 if (*(void **)((char *)ops + off) == NULL)
190 *(void **)((char *)ops + off) = ops->vop_default;
191 }
192}
193
194/*
195 * Routines having to do with the management of the vnode table.
196 */
197struct vattr va_null;
198
199/*
200 * Initialize the vnode structures and initialize each file system type.
201 */
202/* ARGSUSED*/
203static void
204vfsinit(void *dummy)
205{
206 TAILQ_INIT(&vnodeopv_list);
207 namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN);
208
209 /*
210 * Initialize the vnode table
211 */
212 vfs_subr_init();
213 vfs_mount_init();
214 vfs_lock_init();
215
216 /*
217 * Initialize the vnode name cache
218 */
219 nchinit();
220
221 /*
222 * Initialize each file system type.
223 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
224 */
225 vattr_null(&va_null);
226}
227SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL);
228
229/*
230 * vfsconf related functions/data.
231 */
232
233/* highest defined filesystem type */
234static int vfsconf_maxtypenum = VFS_GENERIC + 1;
235
236/* head of list of filesystem types */
237static STAILQ_HEAD(, vfsconf) vfsconf_list =
238 STAILQ_HEAD_INITIALIZER(vfsconf_list);
239
240struct vfsconf *
241vfsconf_find_by_name(const char *name)
242{
243 struct vfsconf *vfsp;
244
245 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
246 if (strcmp(name, vfsp->vfc_name) == 0)
247 break;
248 }
249 return vfsp;
250}
251
252struct vfsconf *
253vfsconf_find_by_typenum(int typenum)
254{
255 struct vfsconf *vfsp;
256
257 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
258 if (typenum == vfsp->vfc_typenum)
259 break;
260 }
261 return vfsp;
262}
263
264static void
265vfsconf_add(struct vfsconf *vfc)
266{
267 vfc->vfc_typenum = vfsconf_maxtypenum++;
268 STAILQ_INSERT_TAIL(&vfsconf_list, vfc, vfc_next);
269}
270
271static void
272vfsconf_remove(struct vfsconf *vfc)
273{
274 int maxtypenum;
275
276 STAILQ_REMOVE(&vfsconf_list, vfc, vfsconf, vfc_next);
277
278 maxtypenum = VFS_GENERIC;
279 STAILQ_FOREACH(vfc, &vfsconf_list, vfc_next) {
280 if (maxtypenum < vfc->vfc_typenum)
281 maxtypenum = vfc->vfc_typenum;
282 }
283 vfsconf_maxtypenum = maxtypenum + 1;
284}
285
286int
287vfsconf_get_maxtypenum(void)
288{
289 return vfsconf_maxtypenum;
290}
291
292/*
293 * Iterate over all vfsconf entries. Break out of the iterator
294 * by returning != 0.
295 */
296int
297vfsconf_each(int (*iter)(struct vfsconf *element, void *data), void *data)
298{
299 int error;
300 struct vfsconf *vfsp;
301
302 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
303 error = iter(vfsp, data);
304 if (error)
305 return (error);
306 }
307 return (0);
308}
309
310/*
311 * Register a VFS.
312 *
313 * After doing general initialisation, this function will
314 * call the filesystem specific initialisation vector op,
315 * i.e. vfsops->vfs_init().
316 */
317int
318vfs_register(struct vfsconf *vfc)
319{
320 struct sysctl_oid *oidp;
321 struct vfsops *vfsops = NULL;
322
323 if (vfsconf_find_by_name(vfc->vfc_name) != NULL)
324 return EEXIST;
325
326 vfsconf_add(vfc);
327
328 /*
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
336 * number.
337 */
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);
343 }
344
345 /*
346 * Initialise unused fields in the file system's vfsops vector.
347 *
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.
352 */
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);
358
359 if (vfsops->vfs_root == NULL) {
360 /* return file system's root vnode */
361 vfsops->vfs_root = vfs_stdroot;
362 }
363 if (vfsops->vfs_start == NULL) {
364 /*
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.
368 */
369 vfsops->vfs_start = vfs_stdstart;
370 }
371 if (vfsops->vfs_quotactl == NULL) {
372 /* quota control */
373 vfsops->vfs_quotactl = vfs_stdquotactl;
374 }
375 if (vfsops->vfs_statfs == NULL) {
376 /* return file system's status */
377 vfsops->vfs_statfs = vfs_stdstatfs;
378 }
379 if (vfsops->vfs_statvfs == NULL) {
380 /* return file system's status */
381 vfsops->vfs_statvfs = vfs_stdstatvfs;
382 }
383 if (vfsops->vfs_sync == NULL) {
384 /*
385 * Flush dirty buffers. File systems can use vfs_stdsync()
386 * by explicitly setting it in the vfsops->vfs_sync vector
387 * entry.
388 */
389 vfsops->vfs_sync = vfs_stdnosync;
390 }
391 if (vfsops->vfs_vget == NULL) {
392 /* convert an inode number to a vnode */
393 vfsops->vfs_vget = vfs_stdvget;
394 }
395 if (vfsops->vfs_fhtovp == NULL) {
396 /* turn an NFS file handle into a vnode */
397 vfsops->vfs_fhtovp = vfs_stdfhtovp;
398 }
399 if (vfsops->vfs_checkexp == NULL) {
400 /* check if file system is exported */
401 vfsops->vfs_checkexp = vfs_stdcheckexp;
402 }
403 if (vfsops->vfs_vptofh == NULL) {
404 /* turn a vnode into an NFS file handle */
405 vfsops->vfs_vptofh = vfs_stdvptofh;
406 }
407 if (vfsops->vfs_init == NULL) {
408 /* file system specific initialisation */
409 vfsops->vfs_init = vfs_stdinit;
410 }
411 if (vfsops->vfs_uninit == NULL) {
412 /* file system specific uninitialisation */
413 vfsops->vfs_uninit = vfs_stduninit;
414 }
415 if (vfsops->vfs_extattrctl == NULL) {
416 /* extended attribute control */
417 vfsops->vfs_extattrctl = vfs_stdextattrctl;
418 }
419
420 if (vfsops->vfs_ncpgen_set == NULL) {
421 /* namecache generation number */
422 vfsops->vfs_ncpgen_set = vfs_stdncpgen_set;
423 }
424
425 if (vfsops->vfs_ncpgen_test == NULL) {
426 /* check namecache generation */
427 vfsops->vfs_ncpgen_test = vfs_stdncpgen_test;
428 }
429
430 /* VFS quota uid and gid accounting */
431 if (vfs_quota_enabled && vfsops->vfs_acinit == NULL) {
432 vfsops->vfs_acinit = vfs_stdac_init;
433 }
434 if (vfs_quota_enabled && vfsops->vfs_acdone == NULL) {
435 vfsops->vfs_acdone = vfs_stdac_done;
436 }
437
438 if (vfsops->vfs_modifying == NULL) {
439 vfsops->vfs_modifying = vfs_stdmodifying;
440 }
441
442 /*
443 * Call init function for this VFS...
444 */
445 vfs_init(vfc);
446 return 0;
447}
448
449
450/*
451 * Remove previously registered VFS.
452 *
453 * After doing general de-registration like removing sysctl
454 * nodes etc, it will call the filesystem specific vector
455 * op, i.e. vfsops->vfs_uninit().
456 *
457 */
458int
459vfs_unregister(struct vfsconf *vfc)
460{
461 struct vfsconf *vfsp;
462 int error;
463
464 vfsp = vfsconf_find_by_name(vfc->vfc_name);
465
466 if (vfsp == NULL)
467 return EINVAL;
468
469 if (vfsp->vfc_refcount != 0)
470 return EBUSY;
471
472 if (vfc->vfc_vfsops->vfs_uninit != NULL) {
473 error = vfs_uninit(vfc, vfsp);
474 if (error)
475 return (error);
476 }
477
478 vfsconf_remove(vfsp);
479 return 0;
480}
481
482int
483vfs_modevent(module_t mod, int type, void *data)
484{
485 struct vfsconf *vfc;
486 int error = 0;
487
488 vfc = (struct vfsconf *)data;
489
490 switch (type) {
491 case MOD_LOAD:
492 if (vfc)
493 error = vfs_register(vfc);
494 break;
495
496 case MOD_UNLOAD:
497 if (vfc)
498 error = vfs_unregister(vfc);
499 break;
500 default: /* including MOD_SHUTDOWN */
501 break;
502 }
503 return (error);
504}