VFS messaging/interfacing work stage 1/99. This stage replaces the old
[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.5 2004/08/13 17:51:09 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 MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
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(const void *data)
109 {
110         struct vnodeopv_node *node;
111         struct vop_ops *vops;
112
113         node = malloc(sizeof(struct vnodeopv_node), M_VNODE, M_ZERO|M_WAITOK);
114         node->vdesc = data;
115         if ((vops = *node->vdesc->opv_desc_vector) == NULL) {
116                 vops = malloc(sizeof(struct vop_ops), M_VNODE, M_ZERO|M_WAITOK);
117                 *node->vdesc->opv_desc_vector = vops;
118         }
119         ++vops->vv_refs;
120         TAILQ_INSERT_TAIL(&vnodeopv_list, node, entry);
121         vfs_recalc_vnodeops();
122 }
123
124 /*
125  * Unlink previously added vnode operations vector.
126  */
127 void
128 vfs_rm_vnodeops(const void *data)
129 {
130         struct vnodeopv_node *node;
131         struct vop_ops *vops;
132
133         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
134                 if ((const void *)node->vdesc == data)
135                         break;
136         }
137         if (node == NULL) {
138                 printf("vfs_rm_vnodeops: unable to find vnodeopv_desc: %p\n",
139                         data);
140                 return;
141         }
142         TAILQ_REMOVE(&vnodeopv_list, node, entry);
143         vops = *node->vdesc->opv_desc_vector;
144         KKASSERT(vops != NULL && vops->vv_refs > 0);
145         if (--vops->vv_refs == 0) {
146                 *node->vdesc->opv_desc_vector = NULL;
147                 free(vops, M_VNODE);
148         }
149         free(node, M_VNODE);
150         vfs_recalc_vnodeops();
151 }
152
153 /*
154  * Recalculate VFS operations vectors
155  */
156 static void
157 vfs_recalc_vnodeops(void)
158 {
159         struct vnodeopv_node *node;
160         struct vnodeopv_entry_desc *desc;
161         struct vop_ops *vops;
162         struct vop_ops *vnew;
163         int off;
164
165         /*
166          * Because vop_ops may be active we can't just blow them away, we
167          * have to generate new vop_ops and then copy them into the running
168          * vop_ops.  Any missing entries will be assigned to the default
169          * entry.  If the default entry itself is missing it will be assigned
170          * to vop_eopnotsupp.
171          */
172         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
173                 vops = *node->vdesc->opv_desc_vector;
174                 if ((vnew = vops->vv_new) == NULL) {
175                         vnew = malloc(sizeof(struct vop_ops),
176                                         M_VNODE, M_ZERO|M_WAITOK);
177                         vops->vv_new = vnew;
178                         vnew->vop_default = vop_eopnotsupp;
179                 }
180                 for (desc = node->vdesc->opv_desc_ops; desc->opve_op; ++desc) {
181                         off = desc->opve_op->vdesc_offset;
182                         *(void **)((char *)vnew + off) = desc->opve_func;
183                 }
184                 for (off = __offsetof(struct vop_ops, vop_ops_first_field);
185                      off <= __offsetof(struct vop_ops, vop_ops_last_field);
186                      off += sizeof(void **)
187                 ) {
188                         if (*(void **)((char *)vnew + off) == NULL)
189                             *(void **)((char *)vnew + off) = vnew->vop_default;
190                 }
191         }
192
193         /*
194          * Copy the temporary vops into the running configuration and then
195          * delete them.
196          */
197         TAILQ_FOREACH(node, &vnodeopv_list, entry) {
198                 vops = *node->vdesc->opv_desc_vector;
199                 if ((vnew = vops->vv_new) == NULL)
200                         continue;
201                 for (off = __offsetof(struct vop_ops, vop_ops_first_field);
202                      off <= __offsetof(struct vop_ops, vop_ops_last_field);
203                      off += sizeof(void **)
204                 ) {
205                         *(void **)((char *)vops + off) = 
206                                 *(void **)((char *)vnew + off);
207                 }
208                 vops->vv_new = NULL;
209                 free(vnew, M_VNODE);
210         }
211 }
212
213 /*
214  * Routines having to do with the management of the vnode table.
215  */
216 struct vattr va_null;
217
218 /*
219  * Initialize the vnode structures and initialize each file system type.
220  */
221 /* ARGSUSED*/
222 static void
223 vfsinit(void *dummy)
224 {
225         TAILQ_INIT(&vnodeopv_list);
226         namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2);
227
228         /*
229          * Initialize the vnode table
230          */
231         vntblinit();
232         /*
233          * Initialize the vnode name cache
234          */
235         nchinit();
236         /*
237          * Initialize each file system type.
238          * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
239          */
240         vattr_null(&va_null);
241         maxvfsconf = VFS_GENERIC + 1;
242 }
243 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
244
245 /*
246  * Register a VFS.
247  *
248  * After doing general initialisation, this function will
249  * call the filesystem specific initialisation vector op,
250  * i.e. vfsops->vfs_init().
251  */
252 int
253 vfs_register(struct vfsconf *vfc)
254 {
255         struct sysctl_oid *oidp;
256         struct vfsconf *vfsp;
257
258         vfsp = NULL;
259         if (vfsconf)
260                 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
261                         if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
262                                 return EEXIST;
263
264         vfc->vfc_typenum = maxvfsconf++;
265         if (vfsp)
266                 vfsp->vfc_next = vfc;
267         else
268                 vfsconf = vfc;
269         vfc->vfc_next = NULL;
270
271         /*
272          * If this filesystem has a sysctl node under vfs
273          * (i.e. vfs.xxfs), then change the oid number of that node to 
274          * match the filesystem's type number.  This allows user code
275          * which uses the type number to read sysctl variables defined
276          * by the filesystem to continue working. Since the oids are
277          * in a sorted list, we need to make sure the order is
278          * preserved by re-registering the oid after modifying its
279          * number.
280          */
281         SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
282                 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
283                         sysctl_unregister_oid(oidp);
284                         oidp->oid_number = vfc->vfc_typenum;
285                         sysctl_register_oid(oidp);
286                 }
287
288         /*
289          * Call init function for this VFS...
290          */
291         (*(vfc->vfc_vfsops->vfs_init))(vfc);
292
293         return 0;
294 }
295
296
297 /*
298  * Remove previously registered VFS.
299  *
300  * After doing general de-registration like removing sysctl
301  * nodes etc, it will call the filesystem specific vector
302  * op, i.e. vfsops->vfs_uninit().
303  * 
304  */
305 int
306 vfs_unregister(struct vfsconf *vfc)
307 {
308         struct vfsconf *vfsp, *prev_vfsp;
309         int error, i, maxtypenum;
310
311         i = vfc->vfc_typenum;
312
313         prev_vfsp = NULL;
314         for (vfsp = vfsconf; vfsp;
315                         prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
316                 if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
317                         break;
318         }
319         if (vfsp == NULL)
320                 return EINVAL;
321         if (vfsp->vfc_refcount)
322                 return EBUSY;
323         if (vfc->vfc_vfsops->vfs_uninit != NULL) {
324                 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
325                 if (error)
326                         return (error);
327         }
328         if (prev_vfsp)
329                 prev_vfsp->vfc_next = vfsp->vfc_next;
330         else
331                 vfsconf = vfsp->vfc_next;
332         maxtypenum = VFS_GENERIC;
333         for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
334                 if (maxtypenum < vfsp->vfc_typenum)
335                         maxtypenum = vfsp->vfc_typenum;
336         maxvfsconf = maxtypenum + 1;
337         return 0;
338 }
339
340 int
341 vfs_modevent(module_t mod, int type, void *data)
342 {
343         struct vfsconf *vfc;
344         int error = 0;
345
346         vfc = (struct vfsconf *)data;
347
348         switch (type) {
349         case MOD_LOAD:
350                 if (vfc)
351                         error = vfs_register(vfc);
352                 break;
353
354         case MOD_UNLOAD:
355                 if (vfc)
356                         error = vfs_unregister(vfc);
357                 break;
358         default:        /* including MOD_SHUTDOWN */
359                 break;
360         }
361         return (error);
362 }