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