903212dd633eb516918920a8e37fc7d2adef5c25
[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. 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.
58  *
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.
70  *
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 $
74  */
75 /*
76  * Manage vnode VOP operations vectors
77  */
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>
86
87 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors");
88
89 /*
90  * Zone for namei
91  */
92 struct vm_zone *namei_zone;
93
94 /*
95  * vfs_init() will set maxvfsconf
96  * to the highest defined type number.
97  */
98 int maxvfsconf;
99 struct vfsconf *vfsconf;
100
101 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
102 static void vfs_recalc_vnodeops(void);
103
104 /*
105  * Add a vnode operations (vnops) vector to the global list.
106  */
107 void
108 vfs_add_vnodeops_sysinit(const void *data)
109 {
110         const struct vnodeopv_desc *vdesc = data;
111
112         vfs_add_vnodeops(NULL, vdesc->opv_desc_vector, 
113                          vdesc->opv_desc_ops, vdesc->opv_flags);
114 }
115
116 /*
117  * Unlink previously added vnode operations vector.
118  */
119 void
120 vfs_rm_vnodeops_sysinit(const void *data)
121 {
122         const struct vnodeopv_desc *vdesc = data;
123
124         vfs_rm_vnodeops(vdesc->opv_desc_vector);
125 }
126
127 void
128 vfs_add_vnodeops(struct mount *mp, struct vop_ops **vops_pp,
129                 struct vnodeopv_entry_desc *descs, int flags)
130 {
131         struct vnodeopv_node *node;
132         struct vop_ops *ops;
133
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);
138                 *vops_pp = ops;
139         }
140         node->ops = ops;
141         node->descs = descs;
142         ops->vv_mount = mp;
143         ops->vv_flags |= flags;
144
145         /*
146          * Journal and coherency ops inherit normal ops flags
147          */
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;
152
153         ++ops->vv_refs;
154         TAILQ_INSERT_TAIL(&vnodeopv_list, node, entry);
155
156         vfs_recalc_vnodeops();
157
158         if (mp) {
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;
163                 else
164                         mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
165         }
166 }
167
168 void
169 vfs_rm_vnodeops(struct vop_ops **vops_pp)
170 {
171         struct vop_ops *ops = *vops_pp;
172         struct vnodeopv_node *node;
173         struct mount *mp;
174
175         if (ops == NULL)
176                 return;
177
178         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
179                 if (node->ops == ops)
180                         break;
181         }
182         if (node == NULL) {
183                 printf("vfs_rm_vnodeops: unable to find ops: %p\n", ops);
184                 return;
185         }
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) {
190                 *vops_pp = NULL;
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;
196                         else
197                                 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
198                 }
199                 free(ops, M_VNODEOP);
200         }
201         vfs_recalc_vnodeops();
202 }
203
204 /*
205  * Recalculate VFS operations vectors
206  */
207 static void
208 vfs_recalc_vnodeops(void)
209 {
210         struct vnodeopv_node *node;
211         struct vnodeopv_entry_desc *desc;
212         struct vop_ops *ops;
213         struct vop_ops *vnew;
214         int off;
215
216         /*
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
221          * to vop_eopnotsupp.
222          */
223         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
224                 ops = node->ops;
225                 if ((vnew = ops->vv_new) == NULL) {
226                         vnew = malloc(sizeof(struct vop_ops),
227                                         M_VNODEOP, M_ZERO|M_WAITOK);
228                         ops->vv_new = vnew;
229                         vnew->vop_default = vop_eopnotsupp;
230                 }
231                 for (desc = node->descs; desc->opve_op; ++desc) {
232                         off = desc->opve_op->vdesc_offset;
233                         *(void **)((char *)vnew + off) = desc->opve_func;
234                 }
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 **)
238                 ) {
239                         if (*(void **)((char *)vnew + off) == NULL)
240                             *(void **)((char *)vnew + off) = vnew->vop_default;
241                 }
242         }
243
244         /*
245          * Copy the temporary ops into the running configuration and then
246          * delete them.
247          */
248         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
249                 ops = node->ops;
250                 if ((vnew = ops->vv_new) == NULL)
251                         continue;
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 **)
255                 ) {
256                         *(void **)((char *)ops + off) = 
257                                 *(void **)((char *)vnew + off);
258                 }
259                 ops->vv_new = NULL;
260                 free(vnew, M_VNODEOP);
261         }
262 }
263
264 /*
265  * Routines having to do with the management of the vnode table.
266  */
267 struct vattr va_null;
268
269 /*
270  * Initialize the vnode structures and initialize each file system type.
271  */
272 /* ARGSUSED*/
273 static void
274 vfsinit(void *dummy)
275 {
276         TAILQ_INIT(&vnodeopv_list);
277         namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2);
278
279         /*
280          * Initialize the vnode table
281          */
282         vfs_subr_init();
283         vfs_mount_init();
284         vfs_lock_init();
285         vfs_sync_init();
286         /*
287          * Initialize the vnode name cache
288          */
289         nchinit();
290         /*
291          * Initialize each file system type.
292          * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
293          */
294         vattr_null(&va_null);
295         maxvfsconf = VFS_GENERIC + 1;
296 }
297 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
298
299 /*
300  * Register a VFS.
301  *
302  * After doing general initialisation, this function will
303  * call the filesystem specific initialisation vector op,
304  * i.e. vfsops->vfs_init().
305  */
306 int
307 vfs_register(struct vfsconf *vfc)
308 {
309         struct sysctl_oid *oidp;
310         struct vfsconf *vfsp;
311         struct vfsops *vfsops = NULL;
312
313         vfsp = NULL;
314         if (vfsconf)
315                 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
316                         if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
317                                 return EEXIST;
318
319         vfc->vfc_typenum = maxvfsconf++;
320         if (vfsp)
321                 vfsp->vfc_next = vfc;
322         else
323                 vfsconf = vfc;
324         vfc->vfc_next = NULL;
325
326         /*
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
334          * number.
335          */
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);
341                 }
342         
343         /*
344          * Initialise unused fields in the file system's vfsops vector.
345          *
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.
350          */
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);
356
357         if (vfsops->vfs_root == NULL) {
358                 /* return file system's root vnode */
359                 vfsops->vfs_root = vfs_stdroot;
360         }
361         if (vfsops->vfs_start == NULL) {
362                 /* 
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.
366                  */
367                 vfsops->vfs_start = vfs_stdstart;
368         }
369         if (vfsops->vfs_quotactl == NULL) {
370                 /* quota control */
371                 vfsops->vfs_quotactl = vfs_stdquotactl;
372         }
373         if (vfsops->vfs_statfs == NULL) {
374                 /* return file system's status */
375                 vfsops->vfs_statfs = vfs_stdstatfs;
376         }
377         if (vfsops->vfs_sync == NULL) {
378                 /*
379                  * Flush dirty buffers.  File systems can use vfs_stdsync()
380                  * by explicitly setting it in the vfsops->vfs_sync vector
381                  * entry.
382                  */
383                 vfsops->vfs_sync = vfs_stdnosync;
384         }
385         if (vfsops->vfs_vget == NULL) {
386                 /* convert an inode number to a vnode */
387                 vfsops->vfs_vget = vfs_stdvget;
388         }
389         if (vfsops->vfs_fhtovp == NULL) {
390                 /* turn an NFS file handle into a vnode */
391                 vfsops->vfs_fhtovp = vfs_stdfhtovp;
392         }
393         if (vfsops->vfs_checkexp == NULL) {
394                 /* check if file system is exported */
395                 vfsops->vfs_checkexp = vfs_stdcheckexp;
396         }
397         if (vfsops->vfs_vptofh == NULL) {
398                 /* turn a vnode into an NFS file handle */
399                 vfsops->vfs_vptofh = vfs_stdvptofh;
400         }
401         if (vfsops->vfs_init == NULL) {
402                 /* file system specific initialisation */
403                 vfsops->vfs_init = vfs_stdinit;
404         }
405         if (vfsops->vfs_uninit == NULL) {
406                 /* file system specific uninitialisation */
407                 vfsops->vfs_uninit = vfs_stduninit;
408         }
409         if (vfsops->vfs_extattrctl == NULL) {
410                 /* extended attribute control */
411                 vfsops->vfs_extattrctl = vfs_stdextattrctl;
412         }
413
414         /*
415          * Call init function for this VFS...
416          */
417         (*(vfc->vfc_vfsops->vfs_init))(vfc);
418
419         return 0;
420 }
421
422
423 /*
424  * Remove previously registered VFS.
425  *
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().
429  * 
430  */
431 int
432 vfs_unregister(struct vfsconf *vfc)
433 {
434         struct vfsconf *vfsp, *prev_vfsp;
435         int error, i, maxtypenum;
436
437         i = vfc->vfc_typenum;
438
439         prev_vfsp = NULL;
440         for (vfsp = vfsconf; vfsp;
441                         prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
442                 if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
443                         break;
444         }
445         if (vfsp == NULL)
446                 return EINVAL;
447         if (vfsp->vfc_refcount)
448                 return EBUSY;
449         if (vfc->vfc_vfsops->vfs_uninit != NULL) {
450                 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
451                 if (error)
452                         return (error);
453         }
454         if (prev_vfsp)
455                 prev_vfsp->vfc_next = vfsp->vfc_next;
456         else
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;
463         return 0;
464 }
465
466 int
467 vfs_modevent(module_t mod, int type, void *data)
468 {
469         struct vfsconf *vfc;
470         int error = 0;
471
472         vfc = (struct vfsconf *)data;
473
474         switch (type) {
475         case MOD_LOAD:
476                 if (vfc)
477                         error = vfs_register(vfc);
478                 break;
479
480         case MOD_UNLOAD:
481                 if (vfc)
482                         error = vfs_unregister(vfc);
483                 break;
484         default:        /* including MOD_SHUTDOWN */
485                 break;
486         }
487         return (error);
488 }