9b6c2aa62c3848e6ca889637cc1b6ef2d3236340
[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.11 2006/03/24 18:35:33 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         KKASSERT(*vops_pp == NULL);
136         if ((ops = *vops_pp) == NULL) {
137                 ops = malloc(sizeof(struct vop_ops),
138                                 M_VNODEOP, M_ZERO|M_WAITOK);
139                 *vops_pp = ops;
140         }
141         node->ops = ops;
142         node->descs = descs;
143         ops->vv_mount = mp;
144         ops->vv_flags |= flags;
145
146         /*
147          * Journal and coherency ops inherit normal ops flags
148          */
149         if (vops_pp == &mp->mnt_vn_coherency_ops && mp->mnt_vn_norm_ops)
150             ops->vv_flags |= mp->mnt_vn_norm_ops->vv_flags;
151         if (vops_pp == &mp->mnt_vn_journal_ops && mp->mnt_vn_norm_ops)
152             ops->vv_flags |= mp->mnt_vn_norm_ops->vv_flags;
153
154         ++ops->vv_refs;
155         TAILQ_INSERT_TAIL(&vnodeopv_list, node, entry);
156
157         vfs_recalc_vnodeops();
158
159         if (mp) {
160                 if (mp->mnt_vn_coherency_ops)
161                         mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
162                 else if (mp->mnt_vn_journal_ops)
163                         mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
164                 else
165                         mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
166         }
167 }
168
169 void
170 vfs_rm_vnodeops(struct vop_ops **vops_pp)
171 {
172         struct vop_ops *ops = *vops_pp;
173         struct vnodeopv_node *node;
174         struct mount *mp;
175
176         if (ops == NULL)
177                 return;
178
179         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
180                 if (node->ops == ops)
181                         break;
182         }
183         if (node == NULL) {
184                 printf("vfs_rm_vnodeops: unable to find ops: %p\n", ops);
185                 return;
186         }
187         TAILQ_REMOVE(&vnodeopv_list, node, entry);
188         free(node, M_VNODEOP);
189         KKASSERT(ops != NULL && ops->vv_refs > 0);
190         if (--ops->vv_refs == 0) {
191                 *vops_pp = NULL;
192                 if ((mp = ops->vv_mount) != NULL) {
193                         if (mp->mnt_vn_coherency_ops)
194                                 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops;
195                         else if (mp->mnt_vn_journal_ops)
196                                 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops;
197                         else
198                                 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops;
199                 }
200                 free(ops, M_VNODEOP);
201         }
202         vfs_recalc_vnodeops();
203 }
204
205 /*
206  * Recalculate VFS operations vectors
207  */
208 static void
209 vfs_recalc_vnodeops(void)
210 {
211         struct vnodeopv_node *node;
212         struct vnodeopv_entry_desc *desc;
213         struct vop_ops *ops;
214         struct vop_ops *vnew;
215         int off;
216
217         /*
218          * Because vop_ops may be active we can't just blow them away, we
219          * have to generate new vop_ops and then copy them into the running
220          * vop_ops.  Any missing entries will be assigned to the default
221          * entry.  If the default entry itself is missing it will be assigned
222          * to vop_eopnotsupp.
223          */
224         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
225                 ops = node->ops;
226                 if ((vnew = ops->vv_new) == NULL) {
227                         vnew = malloc(sizeof(struct vop_ops),
228                                         M_VNODEOP, M_ZERO|M_WAITOK);
229                         ops->vv_new = vnew;
230                         vnew->vop_default = vop_eopnotsupp;
231                 }
232                 for (desc = node->descs; desc->opve_op; ++desc) {
233                         off = desc->opve_op->vdesc_offset;
234                         *(void **)((char *)vnew + off) = desc->opve_func;
235                 }
236                 for (off = __offsetof(struct vop_ops, vop_ops_first_field);
237                      off <= __offsetof(struct vop_ops, vop_ops_last_field);
238                      off += sizeof(void **)
239                 ) {
240                         if (*(void **)((char *)vnew + off) == NULL)
241                             *(void **)((char *)vnew + off) = vnew->vop_default;
242                 }
243         }
244
245         /*
246          * Copy the temporary ops into the running configuration and then
247          * delete them.
248          */
249         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
250                 ops = node->ops;
251                 if ((vnew = ops->vv_new) == NULL)
252                         continue;
253                 for (off = __offsetof(struct vop_ops, vop_ops_first_field);
254                      off <= __offsetof(struct vop_ops, vop_ops_last_field);
255                      off += sizeof(void **)
256                 ) {
257                         *(void **)((char *)ops + off) = 
258                                 *(void **)((char *)vnew + off);
259                 }
260                 ops->vv_new = NULL;
261                 free(vnew, M_VNODEOP);
262         }
263 }
264
265 /*
266  * Routines having to do with the management of the vnode table.
267  */
268 struct vattr va_null;
269
270 /*
271  * Initialize the vnode structures and initialize each file system type.
272  */
273 /* ARGSUSED*/
274 static void
275 vfsinit(void *dummy)
276 {
277         TAILQ_INIT(&vnodeopv_list);
278         namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2);
279
280         /*
281          * Initialize the vnode table
282          */
283         vfs_subr_init();
284         vfs_mount_init();
285         vfs_lock_init();
286         vfs_sync_init();
287         /*
288          * Initialize the vnode name cache
289          */
290         nchinit();
291         /*
292          * Initialize each file system type.
293          * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
294          */
295         vattr_null(&va_null);
296         maxvfsconf = VFS_GENERIC + 1;
297 }
298 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
299
300 /*
301  * Register a VFS.
302  *
303  * After doing general initialisation, this function will
304  * call the filesystem specific initialisation vector op,
305  * i.e. vfsops->vfs_init().
306  */
307 int
308 vfs_register(struct vfsconf *vfc)
309 {
310         struct sysctl_oid *oidp;
311         struct vfsconf *vfsp;
312         struct vfsops *vfsops = NULL;
313
314         vfsp = NULL;
315         if (vfsconf)
316                 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
317                         if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
318                                 return EEXIST;
319
320         vfc->vfc_typenum = maxvfsconf++;
321         if (vfsp)
322                 vfsp->vfc_next = vfc;
323         else
324                 vfsconf = vfc;
325         vfc->vfc_next = NULL;
326
327         /*
328          * If this filesystem has a sysctl node under vfs
329          * (i.e. vfs.xxfs), then change the oid number of that node to 
330          * match the filesystem's type number.  This allows user code
331          * which uses the type number to read sysctl variables defined
332          * by the filesystem to continue working. Since the oids are
333          * in a sorted list, we need to make sure the order is
334          * preserved by re-registering the oid after modifying its
335          * number.
336          */
337         SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
338                 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
339                         sysctl_unregister_oid(oidp);
340                         oidp->oid_number = vfc->vfc_typenum;
341                         sysctl_register_oid(oidp);
342                 }
343         
344         /*
345          * Initialise unused fields in the file system's vfsops vector.
346          *
347          * NOTE the file system should provide the mount and unmount ops
348          * at the least.  In order for unmount to succeed, we also need
349          * the file system to provide us with vfsops->vfs_root otherwise
350          * the unmount(2) operation will not succeed.
351          */
352         vfsops = vfc->vfc_vfsops;
353         KKASSERT(vfc->vfc_vfsops != NULL);
354         KKASSERT(vfsops->vfs_mount != NULL);
355         KKASSERT(vfsops->vfs_root != NULL);
356         KKASSERT(vfsops->vfs_unmount != NULL);
357
358         if (vfsops->vfs_root == NULL) {
359                 /* return file system's root vnode */
360                 vfsops->vfs_root = vfs_stdroot;
361         }
362         if (vfsops->vfs_start == NULL) {
363                 /* 
364                  * Make file system operational before first use.  This
365                  * routine is called at mount-time for initialising MFS,
366                  * not used by other file systems.
367                  */
368                 vfsops->vfs_start = vfs_stdstart;
369         }
370         if (vfsops->vfs_quotactl == NULL) {
371                 /* quota control */
372                 vfsops->vfs_quotactl = vfs_stdquotactl;
373         }
374         if (vfsops->vfs_statfs == NULL) {
375                 /* return file system's status */
376                 vfsops->vfs_statfs = vfs_stdstatfs;
377         }
378         if (vfsops->vfs_sync == NULL) {
379                 /*
380                  * Flush dirty buffers.  File systems can use vfs_stdsync()
381                  * by explicitly setting it in the vfsops->vfs_sync vector
382                  * entry.
383                  */
384                 vfsops->vfs_sync = vfs_stdnosync;
385         }
386         if (vfsops->vfs_vget == NULL) {
387                 /* convert an inode number to a vnode */
388                 vfsops->vfs_vget = vfs_stdvget;
389         }
390         if (vfsops->vfs_fhtovp == NULL) {
391                 /* turn an NFS file handle into a vnode */
392                 vfsops->vfs_fhtovp = vfs_stdfhtovp;
393         }
394         if (vfsops->vfs_checkexp == NULL) {
395                 /* check if file system is exported */
396                 vfsops->vfs_checkexp = vfs_stdcheckexp;
397         }
398         if (vfsops->vfs_vptofh == NULL) {
399                 /* turn a vnode into an NFS file handle */
400                 vfsops->vfs_vptofh = vfs_stdvptofh;
401         }
402         if (vfsops->vfs_init == NULL) {
403                 /* file system specific initialisation */
404                 vfsops->vfs_init = vfs_stdinit;
405         }
406         if (vfsops->vfs_uninit == NULL) {
407                 /* file system specific uninitialisation */
408                 vfsops->vfs_uninit = vfs_stduninit;
409         }
410         if (vfsops->vfs_extattrctl == NULL) {
411                 /* extended attribute control */
412                 vfsops->vfs_extattrctl = vfs_stdextattrctl;
413         }
414
415         /*
416          * Call init function for this VFS...
417          */
418         (*(vfc->vfc_vfsops->vfs_init))(vfc);
419
420         return 0;
421 }
422
423
424 /*
425  * Remove previously registered VFS.
426  *
427  * After doing general de-registration like removing sysctl
428  * nodes etc, it will call the filesystem specific vector
429  * op, i.e. vfsops->vfs_uninit().
430  * 
431  */
432 int
433 vfs_unregister(struct vfsconf *vfc)
434 {
435         struct vfsconf *vfsp, *prev_vfsp;
436         int error, i, maxtypenum;
437
438         i = vfc->vfc_typenum;
439
440         prev_vfsp = NULL;
441         for (vfsp = vfsconf; vfsp;
442                         prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
443                 if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
444                         break;
445         }
446         if (vfsp == NULL)
447                 return EINVAL;
448         if (vfsp->vfc_refcount)
449                 return EBUSY;
450         if (vfc->vfc_vfsops->vfs_uninit != NULL) {
451                 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
452                 if (error)
453                         return (error);
454         }
455         if (prev_vfsp)
456                 prev_vfsp->vfc_next = vfsp->vfc_next;
457         else
458                 vfsconf = vfsp->vfc_next;
459         maxtypenum = VFS_GENERIC;
460         for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
461                 if (maxtypenum < vfsp->vfc_typenum)
462                         maxtypenum = vfsp->vfc_typenum;
463         maxvfsconf = maxtypenum + 1;
464         return 0;
465 }
466
467 int
468 vfs_modevent(module_t mod, int type, void *data)
469 {
470         struct vfsconf *vfc;
471         int error = 0;
472
473         vfc = (struct vfsconf *)data;
474
475         switch (type) {
476         case MOD_LOAD:
477                 if (vfc)
478                         error = vfs_register(vfc);
479                 break;
480
481         case MOD_UNLOAD:
482                 if (vfc)
483                         error = vfs_unregister(vfc);
484                 break;
485         default:        /* including MOD_SHUTDOWN */
486                 break;
487         }
488         return (error);
489 }