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