19454b2d8SWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1989, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * This code is derived from software contributed 6df8bae1dSRodney W. Grimes * to Berkeley by John Heidemann of the UCLA Ficus project. 7df8bae1dSRodney W. Grimes * 8df8bae1dSRodney W. Grimes * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 19df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 20df8bae1dSRodney W. Grimes * without specific prior written permission. 21df8bae1dSRodney W. Grimes * 22df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32df8bae1dSRodney W. Grimes * SUCH DAMAGE. 33df8bae1dSRodney W. Grimes * 34df8bae1dSRodney W. Grimes * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37677b542eSDavid E. O'Brien #include <sys/cdefs.h> 38677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 39df8bae1dSRodney W. Grimes 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41f23b4c91SGarrett Wollman #include <sys/systm.h> 42c901836cSGarrett Wollman #include <sys/kernel.h> 4332ba8e93SPoul-Henning Kamp #include <sys/linker.h> 44df8bae1dSRodney W. Grimes #include <sys/mount.h> 4532ba8e93SPoul-Henning Kamp #include <sys/proc.h> 46e99ea9ecSBruce Evans #include <sys/sysctl.h> 47df8bae1dSRodney W. Grimes #include <sys/vnode.h> 48df8bae1dSRodney W. Grimes #include <sys/malloc.h> 49df8bae1dSRodney W. Grimes 50ebbfc2f8SPoul-Henning Kamp static int vfs_register(struct vfsconf *); 51ebbfc2f8SPoul-Henning Kamp static int vfs_unregister(struct vfsconf *); 522b14f991SJulian Elischer 53a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); 54a1c995b6SPoul-Henning Kamp 552b14f991SJulian Elischer /* 56138e514cSPeter Wemm * The highest defined VFS number. 5799448ed1SJohn Dyson */ 58138e514cSPeter Wemm int maxvfsconf = VFS_GENERIC + 1; 59eb8e6d52SEivind Eklund 60eb8e6d52SEivind Eklund /* 61eb8e6d52SEivind Eklund * Single-linked list of configured VFSes. 62eb8e6d52SEivind Eklund * New entries are added/deleted by vfs_register()/vfs_unregister() 63eb8e6d52SEivind Eklund */ 643dfe213eSPoul-Henning Kamp struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf); 65b676e48cSMike Smith 66b676e48cSMike Smith /* 67273350adSPoul-Henning Kamp * A Zen vnode attribute structure. 68273350adSPoul-Henning Kamp * 69273350adSPoul-Henning Kamp * Initialized when the first filesystem registers by vfs_register(). 70273350adSPoul-Henning Kamp */ 71273350adSPoul-Henning Kamp struct vattr va_null; 72273350adSPoul-Henning Kamp 73273350adSPoul-Henning Kamp /* 74df8bae1dSRodney W. Grimes * vfs_init.c 75df8bae1dSRodney W. Grimes * 76df8bae1dSRodney W. Grimes * Allocate and fill in operations vectors. 77df8bae1dSRodney W. Grimes * 78df8bae1dSRodney W. Grimes * An undocumented feature of this approach to defining operations is that 79df8bae1dSRodney W. Grimes * there can be multiple entries in vfs_opv_descs for the same operations 80df8bae1dSRodney W. Grimes * vector. This allows third parties to extend the set of operations 81df8bae1dSRodney W. Grimes * supported by another layer in a binary compatibile way. For example, 82df8bae1dSRodney W. Grimes * assume that NFS needed to be modified to support Ficus. NFS has an entry 83df8bae1dSRodney W. Grimes * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 84df8bae1dSRodney W. Grimes * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 85df8bae1dSRodney W. Grimes * listing those new operations Ficus adds to NFS, all without modifying the 86df8bae1dSRodney W. Grimes * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 87df8bae1dSRodney W. Grimes * that is a(whole)nother story.) This is a feature. 88df8bae1dSRodney W. Grimes */ 894e61198eSPeter Wemm 90df8bae1dSRodney W. Grimes /* 91df8bae1dSRodney W. Grimes * Routines having to do with the management of the vnode table. 92df8bae1dSRodney W. Grimes */ 93df8bae1dSRodney W. Grimes 943dfe213eSPoul-Henning Kamp struct vfsconf * 953dfe213eSPoul-Henning Kamp vfs_byname(const char *name) 963dfe213eSPoul-Henning Kamp { 973dfe213eSPoul-Henning Kamp struct vfsconf *vfsp; 983dfe213eSPoul-Henning Kamp 998d8883caSPoul-Henning Kamp if (!strcmp(name, "ffs")) 1008d8883caSPoul-Henning Kamp name = "ufs"; 1013dfe213eSPoul-Henning Kamp TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 1023dfe213eSPoul-Henning Kamp if (!strcmp(name, vfsp->vfc_name)) 1033dfe213eSPoul-Henning Kamp return (vfsp); 1043dfe213eSPoul-Henning Kamp return (NULL); 1053dfe213eSPoul-Henning Kamp } 1063dfe213eSPoul-Henning Kamp 10732ba8e93SPoul-Henning Kamp struct vfsconf * 10832ba8e93SPoul-Henning Kamp vfs_byname_kld(const char *fstype, struct thread *td, int *error) 10932ba8e93SPoul-Henning Kamp { 11032ba8e93SPoul-Henning Kamp struct vfsconf *vfsp; 11132ba8e93SPoul-Henning Kamp linker_file_t lf; 11232ba8e93SPoul-Henning Kamp 11332ba8e93SPoul-Henning Kamp vfsp = vfs_byname(fstype); 11432ba8e93SPoul-Henning Kamp if (vfsp != NULL) 11532ba8e93SPoul-Henning Kamp return (vfsp); 11632ba8e93SPoul-Henning Kamp 11732ba8e93SPoul-Henning Kamp /* Only load modules for root (very important!). */ 11832ba8e93SPoul-Henning Kamp *error = suser(td); 11932ba8e93SPoul-Henning Kamp if (*error) 12032ba8e93SPoul-Henning Kamp return (NULL); 12132ba8e93SPoul-Henning Kamp *error = securelevel_gt(td->td_ucred, 0); 12232ba8e93SPoul-Henning Kamp if (*error) 12332ba8e93SPoul-Henning Kamp return (NULL); 12432ba8e93SPoul-Henning Kamp *error = linker_load_module(NULL, fstype, NULL, NULL, &lf); 12532ba8e93SPoul-Henning Kamp if (lf == NULL) 12632ba8e93SPoul-Henning Kamp *error = ENODEV; 12732ba8e93SPoul-Henning Kamp if (*error) 12832ba8e93SPoul-Henning Kamp return (NULL); 12932ba8e93SPoul-Henning Kamp lf->userrefs++; 13032ba8e93SPoul-Henning Kamp /* Look up again to see if the VFS was loaded. */ 13132ba8e93SPoul-Henning Kamp vfsp = vfs_byname(fstype); 13232ba8e93SPoul-Henning Kamp if (vfsp == NULL) { 13332ba8e93SPoul-Henning Kamp lf->userrefs--; 13432ba8e93SPoul-Henning Kamp linker_file_unload(lf, LINKER_UNLOAD_FORCE); 13532ba8e93SPoul-Henning Kamp *error = ENODEV; 13632ba8e93SPoul-Henning Kamp return (NULL); 13732ba8e93SPoul-Henning Kamp } 13832ba8e93SPoul-Henning Kamp return (vfsp); 13932ba8e93SPoul-Henning Kamp } 14032ba8e93SPoul-Henning Kamp 14132ba8e93SPoul-Henning Kamp 142eb8e6d52SEivind Eklund /* Register a new filesystem type in the global table */ 143ebbfc2f8SPoul-Henning Kamp static int 1444e61198eSPeter Wemm vfs_register(struct vfsconf *vfc) 145aa855a59SPeter Wemm { 146a199ed3cSDoug Rabson struct sysctl_oid *oidp; 1477652131bSPoul-Henning Kamp struct vfsops *vfsops; 148273350adSPoul-Henning Kamp static int once; 149273350adSPoul-Henning Kamp 150273350adSPoul-Henning Kamp if (!once) { 151273350adSPoul-Henning Kamp vattr_null(&va_null); 152273350adSPoul-Henning Kamp once = 1; 153273350adSPoul-Henning Kamp } 1547652131bSPoul-Henning Kamp 1555e8c582aSPoul-Henning Kamp if (vfc->vfc_version != VFS_VERSION) { 1565e8c582aSPoul-Henning Kamp printf("ERROR: filesystem %s, unsupported ABI version %x\n", 1575e8c582aSPoul-Henning Kamp vfc->vfc_name, vfc->vfc_version); 1585e8c582aSPoul-Henning Kamp return (EINVAL); 1595e8c582aSPoul-Henning Kamp } 1603dfe213eSPoul-Henning Kamp if (vfs_byname(vfc->vfc_name) != NULL) 161aa855a59SPeter Wemm return EEXIST; 162aa855a59SPeter Wemm 163aa855a59SPeter Wemm vfc->vfc_typenum = maxvfsconf++; 1643dfe213eSPoul-Henning Kamp TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); 165aa855a59SPeter Wemm 166aa855a59SPeter Wemm /* 167a199ed3cSDoug Rabson * If this filesystem has a sysctl node under vfs 168a199ed3cSDoug Rabson * (i.e. vfs.xxfs), then change the oid number of that node to 169a199ed3cSDoug Rabson * match the filesystem's type number. This allows user code 170a199ed3cSDoug Rabson * which uses the type number to read sysctl variables defined 171a199ed3cSDoug Rabson * by the filesystem to continue working. Since the oids are 172a199ed3cSDoug Rabson * in a sorted list, we need to make sure the order is 173a199ed3cSDoug Rabson * preserved by re-registering the oid after modifying its 174a199ed3cSDoug Rabson * number. 175a199ed3cSDoug Rabson */ 17637d40066SPoul-Henning Kamp SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 177a199ed3cSDoug Rabson if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 178a199ed3cSDoug Rabson sysctl_unregister_oid(oidp); 179a199ed3cSDoug Rabson oidp->oid_number = vfc->vfc_typenum; 180a199ed3cSDoug Rabson sysctl_register_oid(oidp); 181a199ed3cSDoug Rabson } 182a199ed3cSDoug Rabson 183a199ed3cSDoug Rabson /* 1847652131bSPoul-Henning Kamp * Initialise unused ``struct vfsops'' fields, to use 1857652131bSPoul-Henning Kamp * the vfs_std*() functions. Note, we need the mount 1867652131bSPoul-Henning Kamp * and unmount operations, at the least. The check 1877652131bSPoul-Henning Kamp * for vfsops available is just a debugging aid. 1887652131bSPoul-Henning Kamp */ 1897652131bSPoul-Henning Kamp KASSERT(vfc->vfc_vfsops != NULL, 1907652131bSPoul-Henning Kamp ("Filesystem %s has no vfsops", vfc->vfc_name)); 1917652131bSPoul-Henning Kamp /* 1927652131bSPoul-Henning Kamp * Check the mount and unmount operations. 1937652131bSPoul-Henning Kamp */ 1947652131bSPoul-Henning Kamp vfsops = vfc->vfc_vfsops; 19520a92a18SPoul-Henning Kamp KASSERT(vfsops->vfs_mount != NULL, 19620a92a18SPoul-Henning Kamp ("Filesystem %s has no mount op", vfc->vfc_name)); 1977652131bSPoul-Henning Kamp KASSERT(vfsops->vfs_unmount != NULL, 1987652131bSPoul-Henning Kamp ("Filesystem %s has no unmount op", vfc->vfc_name)); 1997652131bSPoul-Henning Kamp 2007652131bSPoul-Henning Kamp if (vfsops->vfs_start == NULL) 2017652131bSPoul-Henning Kamp /* make a file system operational */ 2027652131bSPoul-Henning Kamp vfsops->vfs_start = vfs_stdstart; 2037652131bSPoul-Henning Kamp if (vfsops->vfs_root == NULL) 2047652131bSPoul-Henning Kamp /* return file system's root vnode */ 2057652131bSPoul-Henning Kamp vfsops->vfs_root = vfs_stdroot; 2067652131bSPoul-Henning Kamp if (vfsops->vfs_quotactl == NULL) 2077652131bSPoul-Henning Kamp /* quota control */ 2087652131bSPoul-Henning Kamp vfsops->vfs_quotactl = vfs_stdquotactl; 2097652131bSPoul-Henning Kamp if (vfsops->vfs_statfs == NULL) 2107652131bSPoul-Henning Kamp /* return file system's status */ 2117652131bSPoul-Henning Kamp vfsops->vfs_statfs = vfs_stdstatfs; 2127652131bSPoul-Henning Kamp if (vfsops->vfs_sync == NULL) 2137652131bSPoul-Henning Kamp /* 2147652131bSPoul-Henning Kamp * flush unwritten data (nosync) 2157652131bSPoul-Henning Kamp * file systems can use vfs_stdsync 2167652131bSPoul-Henning Kamp * explicitly by setting it in the 2177652131bSPoul-Henning Kamp * vfsop vector. 2187652131bSPoul-Henning Kamp */ 2197652131bSPoul-Henning Kamp vfsops->vfs_sync = vfs_stdnosync; 2207652131bSPoul-Henning Kamp if (vfsops->vfs_vget == NULL) 2217652131bSPoul-Henning Kamp /* convert an inode number to a vnode */ 2227652131bSPoul-Henning Kamp vfsops->vfs_vget = vfs_stdvget; 2237652131bSPoul-Henning Kamp if (vfsops->vfs_fhtovp == NULL) 2247652131bSPoul-Henning Kamp /* turn an NFS file handle into a vnode */ 2257652131bSPoul-Henning Kamp vfsops->vfs_fhtovp = vfs_stdfhtovp; 2267652131bSPoul-Henning Kamp if (vfsops->vfs_checkexp == NULL) 2277652131bSPoul-Henning Kamp /* check if file system is exported */ 2287652131bSPoul-Henning Kamp vfsops->vfs_checkexp = vfs_stdcheckexp; 2297652131bSPoul-Henning Kamp if (vfsops->vfs_vptofh == NULL) 2307652131bSPoul-Henning Kamp /* turn a vnode into an NFS file handle */ 2317652131bSPoul-Henning Kamp vfsops->vfs_vptofh = vfs_stdvptofh; 2327652131bSPoul-Henning Kamp if (vfsops->vfs_init == NULL) 2337652131bSPoul-Henning Kamp /* file system specific initialisation */ 2347652131bSPoul-Henning Kamp vfsops->vfs_init = vfs_stdinit; 2357652131bSPoul-Henning Kamp if (vfsops->vfs_uninit == NULL) 2367652131bSPoul-Henning Kamp /* file system specific uninitialisation */ 2377652131bSPoul-Henning Kamp vfsops->vfs_uninit = vfs_stduninit; 2387652131bSPoul-Henning Kamp if (vfsops->vfs_extattrctl == NULL) 2397652131bSPoul-Henning Kamp /* extended attribute control */ 2407652131bSPoul-Henning Kamp vfsops->vfs_extattrctl = vfs_stdextattrctl; 24181d16e2dSAlfred Perlstein if (vfsops->vfs_sysctl == NULL) 24281d16e2dSAlfred Perlstein vfsops->vfs_sysctl = vfs_stdsysctl; 2437652131bSPoul-Henning Kamp 2447652131bSPoul-Henning Kamp /* 245aa855a59SPeter Wemm * Call init function for this VFS... 246aa855a59SPeter Wemm */ 247aa855a59SPeter Wemm (*(vfc->vfc_vfsops->vfs_init))(vfc); 248aa855a59SPeter Wemm 249aa855a59SPeter Wemm return 0; 250aa855a59SPeter Wemm } 251aa855a59SPeter Wemm 252aa855a59SPeter Wemm 253eb8e6d52SEivind Eklund /* Remove registration of a filesystem type */ 254ebbfc2f8SPoul-Henning Kamp static int 2554e61198eSPeter Wemm vfs_unregister(struct vfsconf *vfc) 256aa855a59SPeter Wemm { 2573dfe213eSPoul-Henning Kamp struct vfsconf *vfsp; 258aa855a59SPeter Wemm int error, i, maxtypenum; 259aa855a59SPeter Wemm 260aa855a59SPeter Wemm i = vfc->vfc_typenum; 261aa855a59SPeter Wemm 2623dfe213eSPoul-Henning Kamp vfsp = vfs_byname(vfc->vfc_name); 263aa855a59SPeter Wemm if (vfsp == NULL) 264aa855a59SPeter Wemm return EINVAL; 265aa855a59SPeter Wemm if (vfsp->vfc_refcount) 266aa855a59SPeter Wemm return EBUSY; 267aa855a59SPeter Wemm if (vfc->vfc_vfsops->vfs_uninit != NULL) { 268aa855a59SPeter Wemm error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 269aa855a59SPeter Wemm if (error) 270aa855a59SPeter Wemm return (error); 271aa855a59SPeter Wemm } 2723dfe213eSPoul-Henning Kamp TAILQ_REMOVE(&vfsconf, vfsp, vfc_list); 273aa855a59SPeter Wemm maxtypenum = VFS_GENERIC; 2743dfe213eSPoul-Henning Kamp TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 275aa855a59SPeter Wemm if (maxtypenum < vfsp->vfc_typenum) 276aa855a59SPeter Wemm maxtypenum = vfsp->vfc_typenum; 277aa855a59SPeter Wemm maxvfsconf = maxtypenum + 1; 278aa855a59SPeter Wemm return 0; 279aa855a59SPeter Wemm } 2804e61198eSPeter Wemm 281eb8e6d52SEivind Eklund /* 282eb8e6d52SEivind Eklund * Standard kernel module handling code for filesystem modules. 283eb8e6d52SEivind Eklund * Referenced from VFS_SET(). 284eb8e6d52SEivind Eklund */ 2854e61198eSPeter Wemm int 2864ae860afSBruce Evans vfs_modevent(module_t mod, int type, void *data) 2874e61198eSPeter Wemm { 2884e61198eSPeter Wemm struct vfsconf *vfc; 2894e61198eSPeter Wemm int error = 0; 2904e61198eSPeter Wemm 2914e61198eSPeter Wemm vfc = (struct vfsconf *)data; 2924e61198eSPeter Wemm 2934e61198eSPeter Wemm switch (type) { 2944e61198eSPeter Wemm case MOD_LOAD: 2954e61198eSPeter Wemm if (vfc) 2964e61198eSPeter Wemm error = vfs_register(vfc); 2974e61198eSPeter Wemm break; 2984e61198eSPeter Wemm 2994e61198eSPeter Wemm case MOD_UNLOAD: 3004e61198eSPeter Wemm if (vfc) 3014e61198eSPeter Wemm error = vfs_unregister(vfc); 3024e61198eSPeter Wemm break; 3033e019deaSPoul-Henning Kamp default: 3043e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 3054e61198eSPeter Wemm break; 3064e61198eSPeter Wemm } 3074e61198eSPeter Wemm return (error); 3084e61198eSPeter Wemm } 309