Merge branch 'vendor/XZ'
[dragonfly.git] / sys / kern / vfs_init.c
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  * $DragonFly: src/sys/kern/vfs_init.c,v 1.15 2008/06/01 19:27:35 dillon Exp $
70  */
71 /*
72  * Manage vnode VOP operations vectors
73  */
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/kernel.h>
77 #include <sys/mount.h>
78 #include <sys/sysctl.h>
79 #include <sys/vnode.h>
80 #include <sys/malloc.h>
81 #include <sys/objcache.h>
82
83 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors");
84 static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers");
85
86 /*
87  * Zone for namei
88  */
89 struct objcache *namei_oc;
90
91 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
92 static void vfs_calc_vnodeops(struct vop_ops *ops);
93
94
95 /*
96  * Add a vnode operations (vnops) vector to the global list.
97  */
98 void
99 vfs_nadd_vnodeops_sysinit(void *data)
100 {
101         struct vop_ops *ops = data;
102
103         vfs_add_vnodeops(NULL, ops, NULL);      /* mount, template, newcopy */
104 }
105
106 /*
107  * Unlink previously added vnode operations vector.
108  */
109 void
110 vfs_nrm_vnodeops_sysinit(void *data)
111 {
112         struct vop_ops *ops = data;
113
114         vfs_rm_vnodeops(NULL, ops, NULL);
115 }
116
117 void
118 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template,
119                  struct vop_ops **ops_pp)
120 {
121         struct vop_ops *ops;
122
123         if (ops_pp) {
124                 KKASSERT(*ops_pp == NULL);
125                 *ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK);
126                 ops = *ops_pp;
127                 bcopy(template, ops, sizeof(*ops));
128         } else {
129                 ops = template;
130         }
131
132         vfs_calc_vnodeops(ops);
133         ops->head.vv_mount = mp;
134
135         if (mp) {
136                 if (mp->mnt_vn_coherency_ops)
137                         mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
138                 else if (mp->mnt_vn_journal_ops)
139                         mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
140                 else
141                         mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
142         }
143 }
144
145 /*
146  * Remove a previously installed operations vector.
147  *
148  * NOTE: Either template or ops_pp may be NULL, but not both.
149  */
150 void
151 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template,
152                 struct vop_ops **ops_pp)
153 {
154         struct vop_ops *ops;
155
156         if (ops_pp) {
157                 ops = *ops_pp;
158                 *ops_pp = NULL;
159         } else {
160                 ops = template;
161         }
162         if (ops == NULL)
163                 return;
164         KKASSERT(mp == ops->head.vv_mount);
165         if (mp) {
166                 if (mp->mnt_vn_coherency_ops)
167                         mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
168                 else if (mp->mnt_vn_journal_ops)
169                         mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
170                 else
171                         mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
172         }
173         if (ops_pp)
174                 kfree(ops, M_VNODEOP);
175 }
176
177 /*
178  * Calculate the VFS operations vector array.  This function basically
179  * replaces any NULL entry with the default entry.
180  */
181 static void
182 vfs_calc_vnodeops(struct vop_ops *ops)
183 {
184         int off;
185
186         for (off = __offsetof(struct vop_ops, vop_ops_first_field);
187              off <= __offsetof(struct vop_ops, vop_ops_last_field);
188              off += sizeof(void *)
189         ) {
190                 if (*(void **)((char *)ops + off) == NULL)
191                     *(void **)((char *)ops + off) = ops->vop_default;
192         }
193 }
194
195 /*
196  * Routines having to do with the management of the vnode table.
197  */
198 struct vattr va_null;
199
200 /*
201  * Initialize the vnode structures and initialize each file system type.
202  */
203 /* ARGSUSED*/
204 static void
205 vfsinit(void *dummy)
206 {
207         TAILQ_INIT(&vnodeopv_list);
208         namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN);
209
210         /*
211          * Initialize the vnode table
212          */
213         vfs_subr_init();
214         vfs_mount_init();
215         vfs_lock_init();
216
217         /*
218          * Initialize the vnode name cache
219          */
220         nchinit();
221
222         /*
223          * Initialize each file system type.
224          * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
225          */
226         vattr_null(&va_null);
227 }
228 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
229
230 /*
231  * vfsconf related functions/data.
232  */
233
234 /* highest defined filesystem type */
235 static int vfsconf_maxtypenum = VFS_GENERIC + 1; 
236
237 /* head of list of filesystem types */
238 static STAILQ_HEAD(, vfsconf) vfsconf_list = 
239         STAILQ_HEAD_INITIALIZER(vfsconf_list);
240
241 struct vfsconf *
242 vfsconf_find_by_name(const char *name) 
243 {
244         struct vfsconf *vfsp;
245
246         STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
247                 if (strcmp(name, vfsp->vfc_name) == 0)
248                         break;
249         }
250         return vfsp;
251 }
252
253 struct vfsconf *
254 vfsconf_find_by_typenum(int typenum) 
255 {
256         struct vfsconf *vfsp;
257
258         STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
259                 if (typenum == vfsp->vfc_typenum)
260                         break;
261         }
262         return vfsp;
263 }
264
265 static void
266 vfsconf_add(struct vfsconf *vfc)
267 {
268         vfc->vfc_typenum = vfsconf_maxtypenum++;
269         STAILQ_INSERT_TAIL(&vfsconf_list, vfc, vfc_next);
270 }
271
272 static void
273 vfsconf_remove(struct vfsconf *vfc)
274 {
275         int maxtypenum;
276
277         STAILQ_REMOVE(&vfsconf_list, vfc, vfsconf, vfc_next); 
278
279         maxtypenum = VFS_GENERIC;
280         STAILQ_FOREACH(vfc, &vfsconf_list, vfc_next) {
281                 if (maxtypenum < vfc->vfc_typenum)
282                         maxtypenum = vfc->vfc_typenum;
283         }
284         vfsconf_maxtypenum = maxtypenum + 1;
285 }
286
287 int
288 vfsconf_get_maxtypenum(void)
289 {
290         return vfsconf_maxtypenum;
291 }
292
293 /*
294  * Iterate over all vfsconf entries. Break out of the iterator
295  * by returning != 0.
296  */
297 int
298 vfsconf_each(int (*iter)(struct vfsconf *element, void *data), void *data)
299 {
300         int error;
301         struct vfsconf *vfsp;
302
303         STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
304                 error = iter(vfsp, data);
305                 if (error)
306                         return (error);
307         }
308         return (0);
309 }
310
311 /*
312  * Register a VFS.
313  *
314  * After doing general initialisation, this function will
315  * call the filesystem specific initialisation vector op,
316  * i.e. vfsops->vfs_init().
317  */
318 int
319 vfs_register(struct vfsconf *vfc)
320 {
321         struct sysctl_oid *oidp;
322         struct vfsops *vfsops = NULL;
323
324         if (vfsconf_find_by_name(vfc->vfc_name) != NULL)
325                 return EEXIST;
326
327         vfsconf_add(vfc);
328
329         /*
330          * If this filesystem has a sysctl node under vfs
331          * (i.e. vfs.xxfs), then change the oid number of that node to 
332          * match the filesystem's type number.  This allows user code
333          * which uses the type number to read sysctl variables defined
334          * by the filesystem to continue working. Since the oids are
335          * in a sorted list, we need to make sure the order is
336          * preserved by re-registering the oid after modifying its
337          * number.
338          */
339         SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
340                 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
341                         sysctl_unregister_oid(oidp);
342                         oidp->oid_number = vfc->vfc_typenum;
343                         sysctl_register_oid(oidp);
344                 }
345         
346         /*
347          * Initialise unused fields in the file system's vfsops vector.
348          *
349          * NOTE the file system should provide the mount and unmount ops
350          * at the least.  In order for unmount to succeed, we also need
351          * the file system to provide us with vfsops->vfs_root otherwise
352          * the unmount(2) operation will not succeed.
353          */
354         vfsops = vfc->vfc_vfsops;
355         KKASSERT(vfc->vfc_vfsops != NULL);
356         KKASSERT(vfsops->vfs_mount != NULL);
357         KKASSERT(vfsops->vfs_root != NULL);
358         KKASSERT(vfsops->vfs_unmount != NULL);
359
360         if (vfsops->vfs_root == NULL) {
361                 /* return file system's root vnode */
362                 vfsops->vfs_root = vfs_stdroot;
363         }
364         if (vfsops->vfs_start == NULL) {
365                 /* 
366                  * Make file system operational before first use.  This
367                  * routine is called at mount-time for initialising MFS,
368                  * not used by other file systems.
369                  */
370                 vfsops->vfs_start = vfs_stdstart;
371         }
372         if (vfsops->vfs_quotactl == NULL) {
373                 /* quota control */
374                 vfsops->vfs_quotactl = vfs_stdquotactl;
375         }
376         if (vfsops->vfs_statfs == NULL) {
377                 /* return file system's status */
378                 vfsops->vfs_statfs = vfs_stdstatfs;
379         }
380         if (vfsops->vfs_statvfs == NULL) {
381                 /* return file system's status */
382                 vfsops->vfs_statvfs = vfs_stdstatvfs;
383         }
384         if (vfsops->vfs_sync == NULL) {
385                 /*
386                  * Flush dirty buffers.  File systems can use vfs_stdsync()
387                  * by explicitly setting it in the vfsops->vfs_sync vector
388                  * entry.
389                  */
390                 vfsops->vfs_sync = vfs_stdnosync;
391         }
392         if (vfsops->vfs_vget == NULL) {
393                 /* convert an inode number to a vnode */
394                 vfsops->vfs_vget = vfs_stdvget;
395         }
396         if (vfsops->vfs_fhtovp == NULL) {
397                 /* turn an NFS file handle into a vnode */
398                 vfsops->vfs_fhtovp = vfs_stdfhtovp;
399         }
400         if (vfsops->vfs_checkexp == NULL) {
401                 /* check if file system is exported */
402                 vfsops->vfs_checkexp = vfs_stdcheckexp;
403         }
404         if (vfsops->vfs_vptofh == NULL) {
405                 /* turn a vnode into an NFS file handle */
406                 vfsops->vfs_vptofh = vfs_stdvptofh;
407         }
408         if (vfsops->vfs_init == NULL) {
409                 /* file system specific initialisation */
410                 vfsops->vfs_init = vfs_stdinit;
411         }
412         if (vfsops->vfs_uninit == NULL) {
413                 /* file system specific uninitialisation */
414                 vfsops->vfs_uninit = vfs_stduninit;
415         }
416         if (vfsops->vfs_extattrctl == NULL) {
417                 /* extended attribute control */
418                 vfsops->vfs_extattrctl = vfs_stdextattrctl;
419         }
420
421         if (vfsops->vfs_ncpgen_set == NULL) {
422                 /* namecache generation number */
423                 vfsops->vfs_ncpgen_set = vfs_stdncpgen_set;
424         }
425
426         if (vfsops->vfs_ncpgen_test == NULL) {
427                 /* check namecache generation */
428                 vfsops->vfs_ncpgen_test = vfs_stdncpgen_test;
429         }
430
431         /* VFS quota uid and gid accounting */
432         if (vfs_quota_enabled && vfsops->vfs_acinit == NULL) {
433                 vfsops->vfs_acinit = vfs_stdac_init;
434         }
435         if (vfs_quota_enabled && vfsops->vfs_acdone == NULL) {
436                 vfsops->vfs_acdone = vfs_stdac_done;
437         }
438
439         /*
440          * Call init function for this VFS...
441          */
442         vfs_init(vfc);
443         return 0;
444 }
445
446
447 /*
448  * Remove previously registered VFS.
449  *
450  * After doing general de-registration like removing sysctl
451  * nodes etc, it will call the filesystem specific vector
452  * op, i.e. vfsops->vfs_uninit().
453  * 
454  */
455 int
456 vfs_unregister(struct vfsconf *vfc)
457 {
458         struct vfsconf *vfsp;
459         int error;
460
461         vfsp = vfsconf_find_by_name(vfc->vfc_name);
462
463         if (vfsp == NULL)
464                 return EINVAL;
465
466         if (vfsp->vfc_refcount != 0)
467                 return EBUSY;
468
469         if (vfc->vfc_vfsops->vfs_uninit != NULL) {
470                 error = vfs_uninit(vfc, vfsp);
471                 if (error)
472                         return (error);
473         }
474
475         vfsconf_remove(vfsp);
476         return 0;
477 }
478
479 int
480 vfs_modevent(module_t mod, int type, void *data)
481 {
482         struct vfsconf *vfc;
483         int error = 0;
484
485         vfc = (struct vfsconf *)data;
486
487         switch (type) {
488         case MOD_LOAD:
489                 if (vfc)
490                         error = vfs_register(vfc);
491                 break;
492
493         case MOD_UNLOAD:
494                 if (vfc)
495                         error = vfs_unregister(vfc);
496                 break;
497         default:        /* including MOD_SHUTDOWN */
498                 break;
499         }
500         return (error);
501 }