19454b2d8SWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1989, 1993 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * This code is derived from software contributed 8df8bae1dSRodney W. Grimes * to Berkeley by John Heidemann of the UCLA Ficus project. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 11df8bae1dSRodney W. Grimes * 12df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 13df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 14df8bae1dSRodney W. Grimes * are met: 15df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 17df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 18df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 19df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 2069a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 21df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 22df8bae1dSRodney W. Grimes * without specific prior written permission. 23df8bae1dSRodney W. Grimes * 24df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df8bae1dSRodney W. Grimes * SUCH DAMAGE. 35df8bae1dSRodney W. Grimes * 36df8bae1dSRodney W. Grimes * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 37df8bae1dSRodney W. Grimes */ 38df8bae1dSRodney W. Grimes 39677b542eSDavid E. O'Brien #include <sys/cdefs.h> 40677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 41df8bae1dSRodney W. Grimes 42df8bae1dSRodney W. Grimes #include <sys/param.h> 43f23b4c91SGarrett Wollman #include <sys/systm.h> 444d30adc4SRick Macklem #include <sys/fnv_hash.h> 450e5c6bd4SJamie Gritton #include <sys/jail.h> 46c901836cSGarrett Wollman #include <sys/kernel.h> 4732ba8e93SPoul-Henning Kamp #include <sys/linker.h> 48df8bae1dSRodney W. Grimes #include <sys/mount.h> 4932ba8e93SPoul-Henning Kamp #include <sys/proc.h> 50168f4ee0SKonstantin Belousov #include <sys/sx.h> 51edd32c2dSJohn Baldwin #include <sys/syscallsubr.h> 52e99ea9ecSBruce Evans #include <sys/sysctl.h> 53df8bae1dSRodney W. Grimes #include <sys/vnode.h> 54df8bae1dSRodney W. Grimes #include <sys/malloc.h> 55df8bae1dSRodney W. Grimes 56ebbfc2f8SPoul-Henning Kamp static int vfs_register(struct vfsconf *); 57ebbfc2f8SPoul-Henning Kamp static int vfs_unregister(struct vfsconf *); 582b14f991SJulian Elischer 59a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); 60a1c995b6SPoul-Henning Kamp 612b14f991SJulian Elischer /* 62138e514cSPeter Wemm * The highest defined VFS number. 6399448ed1SJohn Dyson */ 64138e514cSPeter Wemm int maxvfsconf = VFS_GENERIC + 1; 65eb8e6d52SEivind Eklund 66eb8e6d52SEivind Eklund /* 67eb8e6d52SEivind Eklund * Single-linked list of configured VFSes. 68eb8e6d52SEivind Eklund * New entries are added/deleted by vfs_register()/vfs_unregister() 69eb8e6d52SEivind Eklund */ 703dfe213eSPoul-Henning Kamp struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf); 71168f4ee0SKonstantin Belousov struct sx vfsconf_sx; 72168f4ee0SKonstantin Belousov SX_SYSINIT(vfsconf, &vfsconf_sx, "vfsconf"); 73b676e48cSMike Smith 74b676e48cSMike Smith /* 754d30adc4SRick Macklem * Loader.conf variable vfs.typenumhash enables setting vfc_typenum using a hash 764d30adc4SRick Macklem * calculation on vfc_name, so that it doesn't change when file systems are 774d30adc4SRick Macklem * loaded in a different order. This will avoid the NFS server file handles from 784d30adc4SRick Macklem * changing for file systems that use vfc_typenum in their fsid. 794d30adc4SRick Macklem */ 804d30adc4SRick Macklem static int vfs_typenumhash = 1; 814d30adc4SRick Macklem SYSCTL_INT(_vfs, OID_AUTO, typenumhash, CTLFLAG_RDTUN, &vfs_typenumhash, 0, 824d30adc4SRick Macklem "Set vfc_typenum using a hash calculation on vfc_name, so that it does not" 834d30adc4SRick Macklem "change when file systems are loaded in a different order."); 844d30adc4SRick Macklem 854d30adc4SRick Macklem /* 86273350adSPoul-Henning Kamp * A Zen vnode attribute structure. 87273350adSPoul-Henning Kamp * 88273350adSPoul-Henning Kamp * Initialized when the first filesystem registers by vfs_register(). 89273350adSPoul-Henning Kamp */ 90273350adSPoul-Henning Kamp struct vattr va_null; 91273350adSPoul-Henning Kamp 92273350adSPoul-Henning Kamp /* 93df8bae1dSRodney W. Grimes * vfs_init.c 94df8bae1dSRodney W. Grimes * 95df8bae1dSRodney W. Grimes * Allocate and fill in operations vectors. 96df8bae1dSRodney W. Grimes * 97df8bae1dSRodney W. Grimes * An undocumented feature of this approach to defining operations is that 98df8bae1dSRodney W. Grimes * there can be multiple entries in vfs_opv_descs for the same operations 99df8bae1dSRodney W. Grimes * vector. This allows third parties to extend the set of operations 100df8bae1dSRodney W. Grimes * supported by another layer in a binary compatibile way. For example, 101df8bae1dSRodney W. Grimes * assume that NFS needed to be modified to support Ficus. NFS has an entry 102df8bae1dSRodney W. Grimes * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 103df8bae1dSRodney W. Grimes * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 104df8bae1dSRodney W. Grimes * listing those new operations Ficus adds to NFS, all without modifying the 105df8bae1dSRodney W. Grimes * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 106df8bae1dSRodney W. Grimes * that is a(whole)nother story.) This is a feature. 107df8bae1dSRodney W. Grimes */ 1084e61198eSPeter Wemm 109df8bae1dSRodney W. Grimes /* 110df8bae1dSRodney W. Grimes * Routines having to do with the management of the vnode table. 111df8bae1dSRodney W. Grimes */ 112df8bae1dSRodney W. Grimes 113168f4ee0SKonstantin Belousov static struct vfsconf * 114168f4ee0SKonstantin Belousov vfs_byname_locked(const char *name) 115168f4ee0SKonstantin Belousov { 116168f4ee0SKonstantin Belousov struct vfsconf *vfsp; 117168f4ee0SKonstantin Belousov 118168f4ee0SKonstantin Belousov sx_assert(&vfsconf_sx, SA_LOCKED); 119168f4ee0SKonstantin Belousov if (!strcmp(name, "ffs")) 120168f4ee0SKonstantin Belousov name = "ufs"; 121168f4ee0SKonstantin Belousov TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 122168f4ee0SKonstantin Belousov if (!strcmp(name, vfsp->vfc_name)) 123168f4ee0SKonstantin Belousov return (vfsp); 124168f4ee0SKonstantin Belousov } 125168f4ee0SKonstantin Belousov return (NULL); 126168f4ee0SKonstantin Belousov } 127168f4ee0SKonstantin Belousov 1283dfe213eSPoul-Henning Kamp struct vfsconf * 1293dfe213eSPoul-Henning Kamp vfs_byname(const char *name) 1303dfe213eSPoul-Henning Kamp { 1313dfe213eSPoul-Henning Kamp struct vfsconf *vfsp; 1323dfe213eSPoul-Henning Kamp 133168f4ee0SKonstantin Belousov vfsconf_slock(); 134168f4ee0SKonstantin Belousov vfsp = vfs_byname_locked(name); 135168f4ee0SKonstantin Belousov vfsconf_sunlock(); 1363dfe213eSPoul-Henning Kamp return (vfsp); 1373dfe213eSPoul-Henning Kamp } 1383dfe213eSPoul-Henning Kamp 13932ba8e93SPoul-Henning Kamp struct vfsconf * 14032ba8e93SPoul-Henning Kamp vfs_byname_kld(const char *fstype, struct thread *td, int *error) 14132ba8e93SPoul-Henning Kamp { 14232ba8e93SPoul-Henning Kamp struct vfsconf *vfsp; 143ffc72591SJamie Gritton int fileid, loaded; 14432ba8e93SPoul-Henning Kamp 14532ba8e93SPoul-Henning Kamp vfsp = vfs_byname(fstype); 14632ba8e93SPoul-Henning Kamp if (vfsp != NULL) 14732ba8e93SPoul-Henning Kamp return (vfsp); 14832ba8e93SPoul-Henning Kamp 149322fb40cSJohn Baldwin /* Try to load the respective module. */ 150edd32c2dSJohn Baldwin *error = kern_kldload(td, fstype, &fileid); 151ffc72591SJamie Gritton loaded = (*error == 0); 152ffc72591SJamie Gritton if (*error == EEXIST) 153ffc72591SJamie Gritton *error = 0; 15432ba8e93SPoul-Henning Kamp if (*error) 15532ba8e93SPoul-Henning Kamp return (NULL); 156edd32c2dSJohn Baldwin 15732ba8e93SPoul-Henning Kamp /* Look up again to see if the VFS was loaded. */ 15832ba8e93SPoul-Henning Kamp vfsp = vfs_byname(fstype); 15932ba8e93SPoul-Henning Kamp if (vfsp == NULL) { 160ffc72591SJamie Gritton if (loaded) 161edd32c2dSJohn Baldwin (void)kern_kldunload(td, fileid, LINKER_UNLOAD_FORCE); 16232ba8e93SPoul-Henning Kamp *error = ENODEV; 16332ba8e93SPoul-Henning Kamp return (NULL); 16432ba8e93SPoul-Henning Kamp } 16532ba8e93SPoul-Henning Kamp return (vfsp); 16632ba8e93SPoul-Henning Kamp } 16732ba8e93SPoul-Henning Kamp 1688ff7fad1SKonstantin Belousov static int 1698ff7fad1SKonstantin Belousov vfs_mount_sigdefer(struct mount *mp) 1708ff7fad1SKonstantin Belousov { 1718ff7fad1SKonstantin Belousov int prev_stops, rc; 1728ff7fad1SKonstantin Belousov 1738ff7fad1SKonstantin Belousov TSRAW(curthread, TS_ENTER, "VFS_MOUNT", mp->mnt_vfc->vfc_name); 1748ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 1758ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_mount)(mp); 1768ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 1778ff7fad1SKonstantin Belousov TSRAW(curthread, TS_EXIT, "VFS_MOUNT", mp->mnt_vfc->vfc_name); 1788ff7fad1SKonstantin Belousov return (rc); 1798ff7fad1SKonstantin Belousov } 1808ff7fad1SKonstantin Belousov 1818ff7fad1SKonstantin Belousov static int 1828ff7fad1SKonstantin Belousov vfs_unmount_sigdefer(struct mount *mp, int mntflags) 1838ff7fad1SKonstantin Belousov { 1848ff7fad1SKonstantin Belousov int prev_stops, rc; 1858ff7fad1SKonstantin Belousov 1868ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 1878ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_unmount)(mp, mntflags); 1888ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 1898ff7fad1SKonstantin Belousov return (rc); 1908ff7fad1SKonstantin Belousov } 1918ff7fad1SKonstantin Belousov 1928ff7fad1SKonstantin Belousov static int 1938ff7fad1SKonstantin Belousov vfs_root_sigdefer(struct mount *mp, int flags, struct vnode **vpp) 1948ff7fad1SKonstantin Belousov { 1958ff7fad1SKonstantin Belousov int prev_stops, rc; 1968ff7fad1SKonstantin Belousov 1978ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 1988ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_root)(mp, flags, vpp); 1998ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2008ff7fad1SKonstantin Belousov return (rc); 2018ff7fad1SKonstantin Belousov } 2028ff7fad1SKonstantin Belousov 2038ff7fad1SKonstantin Belousov static int 204*dc20b834SMateusz Guzik vfs_cachedroot_sigdefer(struct mount *mp, int flags, struct vnode **vpp) 205*dc20b834SMateusz Guzik { 206*dc20b834SMateusz Guzik int prev_stops, rc; 207*dc20b834SMateusz Guzik 208*dc20b834SMateusz Guzik prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 209*dc20b834SMateusz Guzik rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_cachedroot)(mp, flags, vpp); 210*dc20b834SMateusz Guzik sigallowstop(prev_stops); 211*dc20b834SMateusz Guzik return (rc); 212*dc20b834SMateusz Guzik } 213*dc20b834SMateusz Guzik 214*dc20b834SMateusz Guzik static int 2158ff7fad1SKonstantin Belousov vfs_quotactl_sigdefer(struct mount *mp, int cmd, uid_t uid, void *arg) 2168ff7fad1SKonstantin Belousov { 2178ff7fad1SKonstantin Belousov int prev_stops, rc; 2188ff7fad1SKonstantin Belousov 2198ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2208ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_quotactl)(mp, cmd, uid, arg); 2218ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2228ff7fad1SKonstantin Belousov return (rc); 2238ff7fad1SKonstantin Belousov } 2248ff7fad1SKonstantin Belousov 2258ff7fad1SKonstantin Belousov static int 2268ff7fad1SKonstantin Belousov vfs_statfs_sigdefer(struct mount *mp, struct statfs *sbp) 2278ff7fad1SKonstantin Belousov { 2288ff7fad1SKonstantin Belousov int prev_stops, rc; 2298ff7fad1SKonstantin Belousov 2308ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2318ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_statfs)(mp, sbp); 2328ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2338ff7fad1SKonstantin Belousov return (rc); 2348ff7fad1SKonstantin Belousov } 2358ff7fad1SKonstantin Belousov 2368ff7fad1SKonstantin Belousov static int 2378ff7fad1SKonstantin Belousov vfs_sync_sigdefer(struct mount *mp, int waitfor) 2388ff7fad1SKonstantin Belousov { 2398ff7fad1SKonstantin Belousov int prev_stops, rc; 2408ff7fad1SKonstantin Belousov 2418ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2428ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_sync)(mp, waitfor); 2438ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2448ff7fad1SKonstantin Belousov return (rc); 2458ff7fad1SKonstantin Belousov } 2468ff7fad1SKonstantin Belousov 2478ff7fad1SKonstantin Belousov static int 2488ff7fad1SKonstantin Belousov vfs_vget_sigdefer(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) 2498ff7fad1SKonstantin Belousov { 2508ff7fad1SKonstantin Belousov int prev_stops, rc; 2518ff7fad1SKonstantin Belousov 2528ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2538ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_vget)(mp, ino, flags, vpp); 2548ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2558ff7fad1SKonstantin Belousov return (rc); 2568ff7fad1SKonstantin Belousov } 2578ff7fad1SKonstantin Belousov 2588ff7fad1SKonstantin Belousov static int 2598ff7fad1SKonstantin Belousov vfs_fhtovp_sigdefer(struct mount *mp, struct fid *fidp, int flags, 2608ff7fad1SKonstantin Belousov struct vnode **vpp) 2618ff7fad1SKonstantin Belousov { 2628ff7fad1SKonstantin Belousov int prev_stops, rc; 2638ff7fad1SKonstantin Belousov 2648ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2658ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_fhtovp)(mp, fidp, flags, vpp); 2668ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2678ff7fad1SKonstantin Belousov return (rc); 2688ff7fad1SKonstantin Belousov } 2698ff7fad1SKonstantin Belousov 2708ff7fad1SKonstantin Belousov static int 2718ff7fad1SKonstantin Belousov vfs_checkexp_sigdefer(struct mount *mp, struct sockaddr *nam, int *exflg, 2728ff7fad1SKonstantin Belousov struct ucred **credp, int *numsecflavors, int **secflavors) 2738ff7fad1SKonstantin Belousov { 2748ff7fad1SKonstantin Belousov int prev_stops, rc; 2758ff7fad1SKonstantin Belousov 2768ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2778ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_checkexp)(mp, nam, exflg, credp, 2788ff7fad1SKonstantin Belousov numsecflavors, secflavors); 2798ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2808ff7fad1SKonstantin Belousov return (rc); 2818ff7fad1SKonstantin Belousov } 2828ff7fad1SKonstantin Belousov 2838ff7fad1SKonstantin Belousov static int 2848ff7fad1SKonstantin Belousov vfs_extattrctl_sigdefer(struct mount *mp, int cmd, struct vnode *filename_vp, 2858ff7fad1SKonstantin Belousov int attrnamespace, const char *attrname) 2868ff7fad1SKonstantin Belousov { 2878ff7fad1SKonstantin Belousov int prev_stops, rc; 2888ff7fad1SKonstantin Belousov 2898ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2908ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_extattrctl)(mp, cmd, 2918ff7fad1SKonstantin Belousov filename_vp, attrnamespace, attrname); 2928ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2938ff7fad1SKonstantin Belousov return (rc); 2948ff7fad1SKonstantin Belousov } 2958ff7fad1SKonstantin Belousov 2968ff7fad1SKonstantin Belousov static int 2978ff7fad1SKonstantin Belousov vfs_sysctl_sigdefer(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 2988ff7fad1SKonstantin Belousov { 2998ff7fad1SKonstantin Belousov int prev_stops, rc; 3008ff7fad1SKonstantin Belousov 3018ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3028ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_sysctl)(mp, op, req); 3038ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3048ff7fad1SKonstantin Belousov return (rc); 3058ff7fad1SKonstantin Belousov } 3068ff7fad1SKonstantin Belousov 3078ff7fad1SKonstantin Belousov static void 3088ff7fad1SKonstantin Belousov vfs_susp_clean_sigdefer(struct mount *mp) 3098ff7fad1SKonstantin Belousov { 3108ff7fad1SKonstantin Belousov int prev_stops; 3118ff7fad1SKonstantin Belousov 3128ff7fad1SKonstantin Belousov if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_susp_clean == NULL) 3138ff7fad1SKonstantin Belousov return; 3148ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3158ff7fad1SKonstantin Belousov (*mp->mnt_vfc->vfc_vfsops_sd->vfs_susp_clean)(mp); 3168ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3178ff7fad1SKonstantin Belousov } 3188ff7fad1SKonstantin Belousov 3198ff7fad1SKonstantin Belousov static void 3208ff7fad1SKonstantin Belousov vfs_reclaim_lowervp_sigdefer(struct mount *mp, struct vnode *vp) 3218ff7fad1SKonstantin Belousov { 3228ff7fad1SKonstantin Belousov int prev_stops; 3238ff7fad1SKonstantin Belousov 3248ff7fad1SKonstantin Belousov if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_reclaim_lowervp == NULL) 3258ff7fad1SKonstantin Belousov return; 3268ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3278ff7fad1SKonstantin Belousov (*mp->mnt_vfc->vfc_vfsops_sd->vfs_reclaim_lowervp)(mp, vp); 3288ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3298ff7fad1SKonstantin Belousov } 3308ff7fad1SKonstantin Belousov 3318ff7fad1SKonstantin Belousov static void 3328ff7fad1SKonstantin Belousov vfs_unlink_lowervp_sigdefer(struct mount *mp, struct vnode *vp) 3338ff7fad1SKonstantin Belousov { 3348ff7fad1SKonstantin Belousov int prev_stops; 3358ff7fad1SKonstantin Belousov 3368ff7fad1SKonstantin Belousov if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_unlink_lowervp == NULL) 3378ff7fad1SKonstantin Belousov return; 3388ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3398ff7fad1SKonstantin Belousov (*(mp)->mnt_vfc->vfc_vfsops_sd->vfs_unlink_lowervp)(mp, vp); 3408ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3418ff7fad1SKonstantin Belousov } 3428ff7fad1SKonstantin Belousov 3438ff7fad1SKonstantin Belousov static void 3448ff7fad1SKonstantin Belousov vfs_purge_sigdefer(struct mount *mp) 3458ff7fad1SKonstantin Belousov { 3468ff7fad1SKonstantin Belousov int prev_stops; 3478ff7fad1SKonstantin Belousov 3488ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3498ff7fad1SKonstantin Belousov (*mp->mnt_vfc->vfc_vfsops_sd->vfs_purge)(mp); 3508ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3518ff7fad1SKonstantin Belousov } 3528ff7fad1SKonstantin Belousov 3538ff7fad1SKonstantin Belousov static struct vfsops vfsops_sigdefer = { 3548ff7fad1SKonstantin Belousov .vfs_mount = vfs_mount_sigdefer, 3558ff7fad1SKonstantin Belousov .vfs_unmount = vfs_unmount_sigdefer, 3568ff7fad1SKonstantin Belousov .vfs_root = vfs_root_sigdefer, 357*dc20b834SMateusz Guzik .vfs_cachedroot = vfs_cachedroot_sigdefer, 3588ff7fad1SKonstantin Belousov .vfs_quotactl = vfs_quotactl_sigdefer, 3598ff7fad1SKonstantin Belousov .vfs_statfs = vfs_statfs_sigdefer, 3608ff7fad1SKonstantin Belousov .vfs_sync = vfs_sync_sigdefer, 3618ff7fad1SKonstantin Belousov .vfs_vget = vfs_vget_sigdefer, 3628ff7fad1SKonstantin Belousov .vfs_fhtovp = vfs_fhtovp_sigdefer, 3638ff7fad1SKonstantin Belousov .vfs_checkexp = vfs_checkexp_sigdefer, 3648ff7fad1SKonstantin Belousov .vfs_extattrctl = vfs_extattrctl_sigdefer, 3658ff7fad1SKonstantin Belousov .vfs_sysctl = vfs_sysctl_sigdefer, 3668ff7fad1SKonstantin Belousov .vfs_susp_clean = vfs_susp_clean_sigdefer, 3678ff7fad1SKonstantin Belousov .vfs_reclaim_lowervp = vfs_reclaim_lowervp_sigdefer, 3688ff7fad1SKonstantin Belousov .vfs_unlink_lowervp = vfs_unlink_lowervp_sigdefer, 3698ff7fad1SKonstantin Belousov .vfs_purge = vfs_purge_sigdefer, 3708ff7fad1SKonstantin Belousov 3718ff7fad1SKonstantin Belousov }; 37232ba8e93SPoul-Henning Kamp 373eb8e6d52SEivind Eklund /* Register a new filesystem type in the global table */ 374ebbfc2f8SPoul-Henning Kamp static int 3754e61198eSPeter Wemm vfs_register(struct vfsconf *vfc) 376aa855a59SPeter Wemm { 377a199ed3cSDoug Rabson struct sysctl_oid *oidp; 3787652131bSPoul-Henning Kamp struct vfsops *vfsops; 379273350adSPoul-Henning Kamp static int once; 3804d30adc4SRick Macklem struct vfsconf *tvfc; 3814d30adc4SRick Macklem uint32_t hashval; 3824d30adc4SRick Macklem int secondpass; 383273350adSPoul-Henning Kamp 384273350adSPoul-Henning Kamp if (!once) { 385273350adSPoul-Henning Kamp vattr_null(&va_null); 386273350adSPoul-Henning Kamp once = 1; 387273350adSPoul-Henning Kamp } 3887652131bSPoul-Henning Kamp 3895e8c582aSPoul-Henning Kamp if (vfc->vfc_version != VFS_VERSION) { 3905e8c582aSPoul-Henning Kamp printf("ERROR: filesystem %s, unsupported ABI version %x\n", 3915e8c582aSPoul-Henning Kamp vfc->vfc_name, vfc->vfc_version); 3925e8c582aSPoul-Henning Kamp return (EINVAL); 3935e8c582aSPoul-Henning Kamp } 394168f4ee0SKonstantin Belousov vfsconf_lock(); 395168f4ee0SKonstantin Belousov if (vfs_byname_locked(vfc->vfc_name) != NULL) { 396168f4ee0SKonstantin Belousov vfsconf_unlock(); 3975050aa86SKonstantin Belousov return (EEXIST); 398168f4ee0SKonstantin Belousov } 399aa855a59SPeter Wemm 4004d30adc4SRick Macklem if (vfs_typenumhash != 0) { 4014d30adc4SRick Macklem /* 4024d30adc4SRick Macklem * Calculate a hash on vfc_name to use for vfc_typenum. Unless 4034d30adc4SRick Macklem * all of 1<->255 are assigned, it is limited to 8bits since 4044d30adc4SRick Macklem * that is what ZFS uses from vfc_typenum and is also the 4054d30adc4SRick Macklem * preferred range for vfs_getnewfsid(). 4064d30adc4SRick Macklem */ 4074d30adc4SRick Macklem hashval = fnv_32_str(vfc->vfc_name, FNV1_32_INIT); 4084d30adc4SRick Macklem hashval &= 0xff; 4094d30adc4SRick Macklem secondpass = 0; 4104d30adc4SRick Macklem do { 4114d30adc4SRick Macklem /* Look for and fix any collision. */ 4124d30adc4SRick Macklem TAILQ_FOREACH(tvfc, &vfsconf, vfc_list) { 4134d30adc4SRick Macklem if (hashval == tvfc->vfc_typenum) { 4144d30adc4SRick Macklem if (hashval == 255 && secondpass == 0) { 4154d30adc4SRick Macklem hashval = 1; 4164d30adc4SRick Macklem secondpass = 1; 4174d30adc4SRick Macklem } else 4184d30adc4SRick Macklem hashval++; 4194d30adc4SRick Macklem break; 4204d30adc4SRick Macklem } 4214d30adc4SRick Macklem } 4224d30adc4SRick Macklem } while (tvfc != NULL); 4234d30adc4SRick Macklem vfc->vfc_typenum = hashval; 4244d30adc4SRick Macklem if (vfc->vfc_typenum >= maxvfsconf) 4254d30adc4SRick Macklem maxvfsconf = vfc->vfc_typenum + 1; 4264d30adc4SRick Macklem } else 427aa855a59SPeter Wemm vfc->vfc_typenum = maxvfsconf++; 4283dfe213eSPoul-Henning Kamp TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); 429aa855a59SPeter Wemm 430aa855a59SPeter Wemm /* 4317652131bSPoul-Henning Kamp * Initialise unused ``struct vfsops'' fields, to use 4327652131bSPoul-Henning Kamp * the vfs_std*() functions. Note, we need the mount 4337652131bSPoul-Henning Kamp * and unmount operations, at the least. The check 4347652131bSPoul-Henning Kamp * for vfsops available is just a debugging aid. 4357652131bSPoul-Henning Kamp */ 4367652131bSPoul-Henning Kamp KASSERT(vfc->vfc_vfsops != NULL, 4377652131bSPoul-Henning Kamp ("Filesystem %s has no vfsops", vfc->vfc_name)); 4387652131bSPoul-Henning Kamp /* 4397652131bSPoul-Henning Kamp * Check the mount and unmount operations. 4407652131bSPoul-Henning Kamp */ 4417652131bSPoul-Henning Kamp vfsops = vfc->vfc_vfsops; 44220a92a18SPoul-Henning Kamp KASSERT(vfsops->vfs_mount != NULL, 44320a92a18SPoul-Henning Kamp ("Filesystem %s has no mount op", vfc->vfc_name)); 4447652131bSPoul-Henning Kamp KASSERT(vfsops->vfs_unmount != NULL, 4457652131bSPoul-Henning Kamp ("Filesystem %s has no unmount op", vfc->vfc_name)); 4467652131bSPoul-Henning Kamp 4477652131bSPoul-Henning Kamp if (vfsops->vfs_root == NULL) 4487652131bSPoul-Henning Kamp /* return file system's root vnode */ 4497652131bSPoul-Henning Kamp vfsops->vfs_root = vfs_stdroot; 4507652131bSPoul-Henning Kamp if (vfsops->vfs_quotactl == NULL) 4517652131bSPoul-Henning Kamp /* quota control */ 4527652131bSPoul-Henning Kamp vfsops->vfs_quotactl = vfs_stdquotactl; 4537652131bSPoul-Henning Kamp if (vfsops->vfs_statfs == NULL) 4547652131bSPoul-Henning Kamp /* return file system's status */ 4557652131bSPoul-Henning Kamp vfsops->vfs_statfs = vfs_stdstatfs; 4567652131bSPoul-Henning Kamp if (vfsops->vfs_sync == NULL) 4577652131bSPoul-Henning Kamp /* 4587652131bSPoul-Henning Kamp * flush unwritten data (nosync) 4597652131bSPoul-Henning Kamp * file systems can use vfs_stdsync 4607652131bSPoul-Henning Kamp * explicitly by setting it in the 4617652131bSPoul-Henning Kamp * vfsop vector. 4627652131bSPoul-Henning Kamp */ 4637652131bSPoul-Henning Kamp vfsops->vfs_sync = vfs_stdnosync; 4647652131bSPoul-Henning Kamp if (vfsops->vfs_vget == NULL) 4657652131bSPoul-Henning Kamp /* convert an inode number to a vnode */ 4667652131bSPoul-Henning Kamp vfsops->vfs_vget = vfs_stdvget; 4677652131bSPoul-Henning Kamp if (vfsops->vfs_fhtovp == NULL) 4687652131bSPoul-Henning Kamp /* turn an NFS file handle into a vnode */ 4697652131bSPoul-Henning Kamp vfsops->vfs_fhtovp = vfs_stdfhtovp; 4707652131bSPoul-Henning Kamp if (vfsops->vfs_checkexp == NULL) 4717652131bSPoul-Henning Kamp /* check if file system is exported */ 4727652131bSPoul-Henning Kamp vfsops->vfs_checkexp = vfs_stdcheckexp; 4737652131bSPoul-Henning Kamp if (vfsops->vfs_init == NULL) 4747652131bSPoul-Henning Kamp /* file system specific initialisation */ 4757652131bSPoul-Henning Kamp vfsops->vfs_init = vfs_stdinit; 4767652131bSPoul-Henning Kamp if (vfsops->vfs_uninit == NULL) 4777652131bSPoul-Henning Kamp /* file system specific uninitialisation */ 4787652131bSPoul-Henning Kamp vfsops->vfs_uninit = vfs_stduninit; 4797652131bSPoul-Henning Kamp if (vfsops->vfs_extattrctl == NULL) 4807652131bSPoul-Henning Kamp /* extended attribute control */ 4817652131bSPoul-Henning Kamp vfsops->vfs_extattrctl = vfs_stdextattrctl; 48281d16e2dSAlfred Perlstein if (vfsops->vfs_sysctl == NULL) 48381d16e2dSAlfred Perlstein vfsops->vfs_sysctl = vfs_stdsysctl; 4847652131bSPoul-Henning Kamp 4858ff7fad1SKonstantin Belousov if ((vfc->vfc_flags & VFCF_SBDRY) != 0) { 4868ff7fad1SKonstantin Belousov vfc->vfc_vfsops_sd = vfc->vfc_vfsops; 4878ff7fad1SKonstantin Belousov vfc->vfc_vfsops = &vfsops_sigdefer; 4888ff7fad1SKonstantin Belousov } 4898ff7fad1SKonstantin Belousov 4900e5c6bd4SJamie Gritton if (vfc->vfc_flags & VFCF_JAIL) 4910e5c6bd4SJamie Gritton prison_add_vfs(vfc); 4920e5c6bd4SJamie Gritton 4937652131bSPoul-Henning Kamp /* 494aa855a59SPeter Wemm * Call init function for this VFS... 495aa855a59SPeter Wemm */ 4968ff7fad1SKonstantin Belousov if ((vfc->vfc_flags & VFCF_SBDRY) != 0) 4978ff7fad1SKonstantin Belousov vfc->vfc_vfsops_sd->vfs_init(vfc); 4988ff7fad1SKonstantin Belousov else 4998ff7fad1SKonstantin Belousov vfc->vfc_vfsops->vfs_init(vfc); 500168f4ee0SKonstantin Belousov vfsconf_unlock(); 501aa855a59SPeter Wemm 502168f4ee0SKonstantin Belousov /* 503168f4ee0SKonstantin Belousov * If this filesystem has a sysctl node under vfs 504168f4ee0SKonstantin Belousov * (i.e. vfs.xxfs), then change the oid number of that node to 505168f4ee0SKonstantin Belousov * match the filesystem's type number. This allows user code 506168f4ee0SKonstantin Belousov * which uses the type number to read sysctl variables defined 507168f4ee0SKonstantin Belousov * by the filesystem to continue working. Since the oids are 508168f4ee0SKonstantin Belousov * in a sorted list, we need to make sure the order is 509168f4ee0SKonstantin Belousov * preserved by re-registering the oid after modifying its 510168f4ee0SKonstantin Belousov * number. 511168f4ee0SKonstantin Belousov */ 5127665e341SMateusz Guzik sysctl_wlock(); 513168f4ee0SKonstantin Belousov SLIST_FOREACH(oidp, SYSCTL_CHILDREN(&sysctl___vfs), oid_link) { 514168f4ee0SKonstantin Belousov if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 515168f4ee0SKonstantin Belousov sysctl_unregister_oid(oidp); 516168f4ee0SKonstantin Belousov oidp->oid_number = vfc->vfc_typenum; 517168f4ee0SKonstantin Belousov sysctl_register_oid(oidp); 518168f4ee0SKonstantin Belousov break; 519168f4ee0SKonstantin Belousov } 520168f4ee0SKonstantin Belousov } 5217665e341SMateusz Guzik sysctl_wunlock(); 522168f4ee0SKonstantin Belousov 523168f4ee0SKonstantin Belousov return (0); 524aa855a59SPeter Wemm } 525aa855a59SPeter Wemm 526aa855a59SPeter Wemm 527eb8e6d52SEivind Eklund /* Remove registration of a filesystem type */ 528ebbfc2f8SPoul-Henning Kamp static int 5294e61198eSPeter Wemm vfs_unregister(struct vfsconf *vfc) 530aa855a59SPeter Wemm { 5313dfe213eSPoul-Henning Kamp struct vfsconf *vfsp; 53269baeadcSKonstantin Belousov int error, maxtypenum; 533aa855a59SPeter Wemm 534168f4ee0SKonstantin Belousov vfsconf_lock(); 535168f4ee0SKonstantin Belousov vfsp = vfs_byname_locked(vfc->vfc_name); 536168f4ee0SKonstantin Belousov if (vfsp == NULL) { 537168f4ee0SKonstantin Belousov vfsconf_unlock(); 538168f4ee0SKonstantin Belousov return (EINVAL); 539168f4ee0SKonstantin Belousov } 540168f4ee0SKonstantin Belousov if (vfsp->vfc_refcount != 0) { 541168f4ee0SKonstantin Belousov vfsconf_unlock(); 542168f4ee0SKonstantin Belousov return (EBUSY); 543168f4ee0SKonstantin Belousov } 5448ff7fad1SKonstantin Belousov error = 0; 5458ff7fad1SKonstantin Belousov if ((vfc->vfc_flags & VFCF_SBDRY) != 0) { 5468ff7fad1SKonstantin Belousov if (vfc->vfc_vfsops_sd->vfs_uninit != NULL) 5478ff7fad1SKonstantin Belousov error = vfc->vfc_vfsops_sd->vfs_uninit(vfsp); 5488ff7fad1SKonstantin Belousov } else { 549aa855a59SPeter Wemm if (vfc->vfc_vfsops->vfs_uninit != NULL) { 5508ff7fad1SKonstantin Belousov error = vfc->vfc_vfsops->vfs_uninit(vfsp); 5518ff7fad1SKonstantin Belousov } 552168f4ee0SKonstantin Belousov if (error != 0) { 553168f4ee0SKonstantin Belousov vfsconf_unlock(); 554aa855a59SPeter Wemm return (error); 555aa855a59SPeter Wemm } 556168f4ee0SKonstantin Belousov } 5573dfe213eSPoul-Henning Kamp TAILQ_REMOVE(&vfsconf, vfsp, vfc_list); 558aa855a59SPeter Wemm maxtypenum = VFS_GENERIC; 5593dfe213eSPoul-Henning Kamp TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 560aa855a59SPeter Wemm if (maxtypenum < vfsp->vfc_typenum) 561aa855a59SPeter Wemm maxtypenum = vfsp->vfc_typenum; 562aa855a59SPeter Wemm maxvfsconf = maxtypenum + 1; 563168f4ee0SKonstantin Belousov vfsconf_unlock(); 564168f4ee0SKonstantin Belousov return (0); 565aa855a59SPeter Wemm } 5664e61198eSPeter Wemm 567eb8e6d52SEivind Eklund /* 568eb8e6d52SEivind Eklund * Standard kernel module handling code for filesystem modules. 569eb8e6d52SEivind Eklund * Referenced from VFS_SET(). 570eb8e6d52SEivind Eklund */ 5714e61198eSPeter Wemm int 5724ae860afSBruce Evans vfs_modevent(module_t mod, int type, void *data) 5734e61198eSPeter Wemm { 5744e61198eSPeter Wemm struct vfsconf *vfc; 5754e61198eSPeter Wemm int error = 0; 5764e61198eSPeter Wemm 5774e61198eSPeter Wemm vfc = (struct vfsconf *)data; 5784e61198eSPeter Wemm 5794e61198eSPeter Wemm switch (type) { 5804e61198eSPeter Wemm case MOD_LOAD: 5814e61198eSPeter Wemm if (vfc) 5824e61198eSPeter Wemm error = vfs_register(vfc); 5834e61198eSPeter Wemm break; 5844e61198eSPeter Wemm 5854e61198eSPeter Wemm case MOD_UNLOAD: 5864e61198eSPeter Wemm if (vfc) 5874e61198eSPeter Wemm error = vfs_unregister(vfc); 5884e61198eSPeter Wemm break; 5893e019deaSPoul-Henning Kamp default: 5903e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 5914e61198eSPeter Wemm break; 5924e61198eSPeter Wemm } 5934e61198eSPeter Wemm return (error); 5944e61198eSPeter Wemm } 595