c85aea63b4f1ec077537cc1ac325ceb4154304c1
[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.15 2008/06/01 19:27:35 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 <sys/objcache.h>
86
87 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors");
88 static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers");
89
90 /*
91  * Zone for namei
92  */
93 struct objcache *namei_oc;
94
95 /*
96  * vfs_init() will set maxvfsconf
97  * to the highest defined type number.
98  */
99 int maxvfsconf;
100 struct vfsconf *vfsconf;
101
102 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
103 static void vfs_calc_vnodeops(struct vop_ops *ops);
104
105 /*
106  * Add a vnode operations (vnops) vector to the global list.
107  */
108 void
109 vfs_nadd_vnodeops_sysinit(void *data)
110 {
111         struct vop_ops *ops = data;
112
113         vfs_add_vnodeops(NULL, ops, NULL);      /* mount, template, newcopy */
114 }
115
116 /*
117  * Unlink previously added vnode operations vector.
118  */
119 void
120 vfs_nrm_vnodeops_sysinit(void *data)
121 {
122         struct vop_ops *ops = data;
123
124         vfs_rm_vnodeops(NULL, ops, NULL);
125 }
126
127 void
128 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template,
129                  struct vop_ops **ops_pp)
130 {
131         struct vop_ops *ops;
132
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;
140         }
141
142         vfs_calc_vnodeops(ops);
143         ops->head.vv_mount = mp;
144
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;
152         }
153 }
154
155 /*
156  * Remove a previously installed operations vector.
157  *
158  * NOTE: Either template or ops_pp may be NULL, but not both.
159  */
160 void
161 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template,
162                 struct vop_ops **ops_pp)
163 {
164         struct vop_ops *ops;
165
166         if (ops_pp) {
167                 ops = *ops_pp;
168                 *ops_pp = NULL;
169         } else {
170                 ops = template;
171         }
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;
182         }
183         if (ops_pp)
184                 kfree(ops, M_VNODEOP);
185 }
186
187 /*
188  * Calculate the VFS operations vector array.  This function basically
189  * replaces any NULL entry with the default entry.
190  */
191 static void
192 vfs_calc_vnodeops(struct vop_ops *ops)
193 {
194         int off;
195
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 *)
199         ) {
200                 if (*(void **)((char *)ops + off) == NULL)
201                     *(void **)((char *)ops + off) = ops->vop_default;
202         }
203 }
204
205 /*
206  * Routines having to do with the management of the vnode table.
207  */
208 struct vattr va_null;
209
210 /*
211  * Initialize the vnode structures and initialize each file system type.
212  */
213 /* ARGSUSED*/
214 static void
215 vfsinit(void *dummy)
216 {
217         TAILQ_INIT(&vnodeopv_list);
218         namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN);
219
220         /*
221          * Initialize the vnode table
222          */
223         vfs_subr_init();
224         vfs_mount_init();
225         vfs_lock_init();
226         vfs_sync_init();
227         /*
228          * Initialize the vnode name cache
229          */
230         nchinit();
231         /*
232          * Initialize each file system type.
233          * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
234          */
235         vattr_null(&va_null);
236         maxvfsconf = VFS_GENERIC + 1;
237 }
238 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
239
240 /*
241  * Register a VFS.
242  *
243  * After doing general initialisation, this function will
244  * call the filesystem specific initialisation vector op,
245  * i.e. vfsops->vfs_init().
246  */
247 int
248 vfs_register(struct vfsconf *vfc)
249 {
250         struct sysctl_oid *oidp;
251         struct vfsconf *vfsp;
252         struct vfsops *vfsops = NULL;
253
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;
259
260         vfc->vfc_typenum = maxvfsconf++;
261         if (vfsp)
262                 vfsp->vfc_next = vfc;
263         else
264                 vfsconf = vfc;
265         vfc->vfc_next = NULL;
266
267         /*
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.
276          */
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);
282                 }
283         
284         /*
285          * Initialise unused fields in the file system's vfsops vector.
286          *
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.
291          */
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);
297
298         if (vfsops->vfs_root == NULL) {
299                 /* return file system's root vnode */
300                 vfsops->vfs_root = vfs_stdroot;
301         }
302         if (vfsops->vfs_start == NULL) {
303                 /* 
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.
307                  */
308                 vfsops->vfs_start = vfs_stdstart;
309         }
310         if (vfsops->vfs_quotactl == NULL) {
311                 /* quota control */
312                 vfsops->vfs_quotactl = vfs_stdquotactl;
313         }
314         if (vfsops->vfs_statfs == NULL) {
315                 /* return file system's status */
316                 vfsops->vfs_statfs = vfs_stdstatfs;
317         }
318         if (vfsops->vfs_statvfs == NULL) {
319                 /* return file system's status */
320                 vfsops->vfs_statvfs = vfs_stdstatvfs;
321         }
322         if (vfsops->vfs_sync == NULL) {
323                 /*
324                  * Flush dirty buffers.  File systems can use vfs_stdsync()
325                  * by explicitly setting it in the vfsops->vfs_sync vector
326                  * entry.
327                  */
328                 vfsops->vfs_sync = vfs_stdnosync;
329         }
330         if (vfsops->vfs_vget == NULL) {
331                 /* convert an inode number to a vnode */
332                 vfsops->vfs_vget = vfs_stdvget;
333         }
334         if (vfsops->vfs_fhtovp == NULL) {
335                 /* turn an NFS file handle into a vnode */
336                 vfsops->vfs_fhtovp = vfs_stdfhtovp;
337         }
338         if (vfsops->vfs_checkexp == NULL) {
339                 /* check if file system is exported */
340                 vfsops->vfs_checkexp = vfs_stdcheckexp;
341         }
342         if (vfsops->vfs_vptofh == NULL) {
343                 /* turn a vnode into an NFS file handle */
344                 vfsops->vfs_vptofh = vfs_stdvptofh;
345         }
346         if (vfsops->vfs_init == NULL) {
347                 /* file system specific initialisation */
348                 vfsops->vfs_init = vfs_stdinit;
349         }
350         if (vfsops->vfs_uninit == NULL) {
351                 /* file system specific uninitialisation */
352                 vfsops->vfs_uninit = vfs_stduninit;
353         }
354         if (vfsops->vfs_extattrctl == NULL) {
355                 /* extended attribute control */
356                 vfsops->vfs_extattrctl = vfs_stdextattrctl;
357         }
358
359         /*
360          * Call init function for this VFS...
361          */
362         (*(vfc->vfc_vfsops->vfs_init))(vfc);
363
364         return 0;
365 }
366
367
368 /*
369  * Remove previously registered VFS.
370  *
371  * After doing general de-registration like removing sysctl
372  * nodes etc, it will call the filesystem specific vector
373  * op, i.e. vfsops->vfs_uninit().
374  * 
375  */
376 int
377 vfs_unregister(struct vfsconf *vfc)
378 {
379         struct vfsconf *vfsp, *prev_vfsp;
380         int error, i, maxtypenum;
381
382         i = vfc->vfc_typenum;
383
384         prev_vfsp = NULL;
385         for (vfsp = vfsconf; vfsp;
386                         prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
387                 if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
388                         break;
389         }
390         if (vfsp == NULL)
391                 return EINVAL;
392         if (vfsp->vfc_refcount)
393                 return EBUSY;
394         if (vfc->vfc_vfsops->vfs_uninit != NULL) {
395                 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
396                 if (error)
397                         return (error);
398         }
399         if (prev_vfsp)
400                 prev_vfsp->vfc_next = vfsp->vfc_next;
401         else
402                 vfsconf = vfsp->vfc_next;
403         maxtypenum = VFS_GENERIC;
404         for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
405                 if (maxtypenum < vfsp->vfc_typenum)
406                         maxtypenum = vfsp->vfc_typenum;
407         maxvfsconf = maxtypenum + 1;
408         return 0;
409 }
410
411 int
412 vfs_modevent(module_t mod, int type, void *data)
413 {
414         struct vfsconf *vfc;
415         int error = 0;
416
417         vfc = (struct vfsconf *)data;
418
419         switch (type) {
420         case MOD_LOAD:
421                 if (vfc)
422                         error = vfs_register(vfc);
423                 break;
424
425         case MOD_UNLOAD:
426                 if (vfc)
427                         error = vfs_unregister(vfc);
428                 break;
429         default:        /* including MOD_SHUTDOWN */
430                 break;
431         }
432         return (error);
433 }