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> 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41f23b4c91SGarrett Wollman #include <sys/systm.h> 424d30adc4SRick Macklem #include <sys/fnv_hash.h> 430e5c6bd4SJamie Gritton #include <sys/jail.h> 44c901836cSGarrett Wollman #include <sys/kernel.h> 4532ba8e93SPoul-Henning Kamp #include <sys/linker.h> 46df8bae1dSRodney W. Grimes #include <sys/mount.h> 4732ba8e93SPoul-Henning Kamp #include <sys/proc.h> 48168f4ee0SKonstantin Belousov #include <sys/sx.h> 49edd32c2dSJohn Baldwin #include <sys/syscallsubr.h> 50e99ea9ecSBruce Evans #include <sys/sysctl.h> 51df8bae1dSRodney W. Grimes #include <sys/vnode.h> 52df8bae1dSRodney W. Grimes #include <sys/malloc.h> 53df8bae1dSRodney W. Grimes 54ebbfc2f8SPoul-Henning Kamp static int vfs_register(struct vfsconf *); 55ebbfc2f8SPoul-Henning Kamp static int vfs_unregister(struct vfsconf *); 562b14f991SJulian Elischer 57a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); 58a1c995b6SPoul-Henning Kamp 592b14f991SJulian Elischer /* 60138e514cSPeter Wemm * The highest defined VFS number. 6199448ed1SJohn Dyson */ 62138e514cSPeter Wemm int maxvfsconf = VFS_GENERIC + 1; 63eb8e6d52SEivind Eklund 64eb8e6d52SEivind Eklund /* 65eb8e6d52SEivind Eklund * Single-linked list of configured VFSes. 66eb8e6d52SEivind Eklund * New entries are added/deleted by vfs_register()/vfs_unregister() 67eb8e6d52SEivind Eklund */ 683dfe213eSPoul-Henning Kamp struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf); 69168f4ee0SKonstantin Belousov struct sx vfsconf_sx; 70168f4ee0SKonstantin Belousov SX_SYSINIT(vfsconf, &vfsconf_sx, "vfsconf"); 71b676e48cSMike Smith 72b676e48cSMike Smith /* 734d30adc4SRick Macklem * Loader.conf variable vfs.typenumhash enables setting vfc_typenum using a hash 744d30adc4SRick Macklem * calculation on vfc_name, so that it doesn't change when file systems are 754d30adc4SRick Macklem * loaded in a different order. This will avoid the NFS server file handles from 764d30adc4SRick Macklem * changing for file systems that use vfc_typenum in their fsid. 774d30adc4SRick Macklem */ 784d30adc4SRick Macklem static int vfs_typenumhash = 1; 794d30adc4SRick Macklem SYSCTL_INT(_vfs, OID_AUTO, typenumhash, CTLFLAG_RDTUN, &vfs_typenumhash, 0, 804d30adc4SRick Macklem "Set vfc_typenum using a hash calculation on vfc_name, so that it does not" 814d30adc4SRick Macklem " change when file systems are loaded in a different order."); 824d30adc4SRick Macklem 834d30adc4SRick Macklem /* 84273350adSPoul-Henning Kamp * A Zen vnode attribute structure. 85273350adSPoul-Henning Kamp * 86273350adSPoul-Henning Kamp * Initialized when the first filesystem registers by vfs_register(). 87273350adSPoul-Henning Kamp */ 88273350adSPoul-Henning Kamp struct vattr va_null; 89273350adSPoul-Henning Kamp 90273350adSPoul-Henning Kamp /* 91df8bae1dSRodney W. Grimes * vfs_init.c 92df8bae1dSRodney W. Grimes * 93df8bae1dSRodney W. Grimes * Allocate and fill in operations vectors. 94df8bae1dSRodney W. Grimes * 95df8bae1dSRodney W. Grimes * An undocumented feature of this approach to defining operations is that 96df8bae1dSRodney W. Grimes * there can be multiple entries in vfs_opv_descs for the same operations 97df8bae1dSRodney W. Grimes * vector. This allows third parties to extend the set of operations 98df8bae1dSRodney W. Grimes * supported by another layer in a binary compatibile way. For example, 99df8bae1dSRodney W. Grimes * assume that NFS needed to be modified to support Ficus. NFS has an entry 100df8bae1dSRodney W. Grimes * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 101df8bae1dSRodney W. Grimes * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 102df8bae1dSRodney W. Grimes * listing those new operations Ficus adds to NFS, all without modifying the 103df8bae1dSRodney W. Grimes * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 104df8bae1dSRodney W. Grimes * that is a(whole)nother story.) This is a feature. 105df8bae1dSRodney W. Grimes */ 1064e61198eSPeter Wemm 107df8bae1dSRodney W. Grimes /* 108df8bae1dSRodney W. Grimes * Routines having to do with the management of the vnode table. 109df8bae1dSRodney W. Grimes */ 110df8bae1dSRodney W. Grimes 111168f4ee0SKonstantin Belousov static struct vfsconf * 112168f4ee0SKonstantin Belousov vfs_byname_locked(const char *name) 113168f4ee0SKonstantin Belousov { 114168f4ee0SKonstantin Belousov struct vfsconf *vfsp; 115168f4ee0SKonstantin Belousov 116168f4ee0SKonstantin Belousov sx_assert(&vfsconf_sx, SA_LOCKED); 117168f4ee0SKonstantin Belousov if (!strcmp(name, "ffs")) 118168f4ee0SKonstantin Belousov name = "ufs"; 119168f4ee0SKonstantin Belousov TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 120168f4ee0SKonstantin Belousov if (!strcmp(name, vfsp->vfc_name)) 121168f4ee0SKonstantin Belousov return (vfsp); 122168f4ee0SKonstantin Belousov } 123168f4ee0SKonstantin Belousov return (NULL); 124168f4ee0SKonstantin Belousov } 125168f4ee0SKonstantin Belousov 1263dfe213eSPoul-Henning Kamp struct vfsconf * 1273dfe213eSPoul-Henning Kamp vfs_byname(const char *name) 1283dfe213eSPoul-Henning Kamp { 1293dfe213eSPoul-Henning Kamp struct vfsconf *vfsp; 1303dfe213eSPoul-Henning Kamp 131168f4ee0SKonstantin Belousov vfsconf_slock(); 132168f4ee0SKonstantin Belousov vfsp = vfs_byname_locked(name); 133168f4ee0SKonstantin Belousov vfsconf_sunlock(); 1343dfe213eSPoul-Henning Kamp return (vfsp); 1353dfe213eSPoul-Henning Kamp } 1363dfe213eSPoul-Henning Kamp 13732ba8e93SPoul-Henning Kamp struct vfsconf * 13832ba8e93SPoul-Henning Kamp vfs_byname_kld(const char *fstype, struct thread *td, int *error) 13932ba8e93SPoul-Henning Kamp { 14032ba8e93SPoul-Henning Kamp struct vfsconf *vfsp; 141ffc72591SJamie Gritton int fileid, loaded; 14232ba8e93SPoul-Henning Kamp 14332ba8e93SPoul-Henning Kamp vfsp = vfs_byname(fstype); 14432ba8e93SPoul-Henning Kamp if (vfsp != NULL) 14532ba8e93SPoul-Henning Kamp return (vfsp); 14632ba8e93SPoul-Henning Kamp 147322fb40cSJohn Baldwin /* Try to load the respective module. */ 148edd32c2dSJohn Baldwin *error = kern_kldload(td, fstype, &fileid); 149ffc72591SJamie Gritton loaded = (*error == 0); 150ffc72591SJamie Gritton if (*error == EEXIST) 151ffc72591SJamie Gritton *error = 0; 152*3eed4803SJohn Baldwin if (*error) { 153*3eed4803SJohn Baldwin *error = ENODEV; 15432ba8e93SPoul-Henning Kamp return (NULL); 155*3eed4803SJohn Baldwin } 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 204dc20b834SMateusz Guzik vfs_cachedroot_sigdefer(struct mount *mp, int flags, struct vnode **vpp) 205dc20b834SMateusz Guzik { 206dc20b834SMateusz Guzik int prev_stops, rc; 207dc20b834SMateusz Guzik 208dc20b834SMateusz Guzik prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 209dc20b834SMateusz Guzik rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_cachedroot)(mp, flags, vpp); 210dc20b834SMateusz Guzik sigallowstop(prev_stops); 211dc20b834SMateusz Guzik return (rc); 212dc20b834SMateusz Guzik } 213dc20b834SMateusz Guzik 214dc20b834SMateusz Guzik static int 215a4b07a27SJason A. Harmening vfs_quotactl_sigdefer(struct mount *mp, int cmd, uid_t uid, void *arg, 216a4b07a27SJason A. Harmening bool *mp_busy) 2178ff7fad1SKonstantin Belousov { 2188ff7fad1SKonstantin Belousov int prev_stops, rc; 2198ff7fad1SKonstantin Belousov 2208ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 221a4b07a27SJason A. Harmening rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_quotactl)(mp, cmd, uid, arg, 222a4b07a27SJason A. Harmening mp_busy); 2238ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2248ff7fad1SKonstantin Belousov return (rc); 2258ff7fad1SKonstantin Belousov } 2268ff7fad1SKonstantin Belousov 2278ff7fad1SKonstantin Belousov static int 2288ff7fad1SKonstantin Belousov vfs_statfs_sigdefer(struct mount *mp, struct statfs *sbp) 2298ff7fad1SKonstantin Belousov { 2308ff7fad1SKonstantin Belousov int prev_stops, rc; 2318ff7fad1SKonstantin Belousov 2328ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2338ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_statfs)(mp, sbp); 2348ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2358ff7fad1SKonstantin Belousov return (rc); 2368ff7fad1SKonstantin Belousov } 2378ff7fad1SKonstantin Belousov 2388ff7fad1SKonstantin Belousov static int 2398ff7fad1SKonstantin Belousov vfs_sync_sigdefer(struct mount *mp, int waitfor) 2408ff7fad1SKonstantin Belousov { 2418ff7fad1SKonstantin Belousov int prev_stops, rc; 2428ff7fad1SKonstantin Belousov 2438ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2448ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_sync)(mp, waitfor); 2458ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2468ff7fad1SKonstantin Belousov return (rc); 2478ff7fad1SKonstantin Belousov } 2488ff7fad1SKonstantin Belousov 2498ff7fad1SKonstantin Belousov static int 2508ff7fad1SKonstantin Belousov vfs_vget_sigdefer(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) 2518ff7fad1SKonstantin Belousov { 2528ff7fad1SKonstantin Belousov int prev_stops, rc; 2538ff7fad1SKonstantin Belousov 2548ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2558ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_vget)(mp, ino, flags, vpp); 2568ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2578ff7fad1SKonstantin Belousov return (rc); 2588ff7fad1SKonstantin Belousov } 2598ff7fad1SKonstantin Belousov 2608ff7fad1SKonstantin Belousov static int 2618ff7fad1SKonstantin Belousov vfs_fhtovp_sigdefer(struct mount *mp, struct fid *fidp, int flags, 2628ff7fad1SKonstantin Belousov struct vnode **vpp) 2638ff7fad1SKonstantin Belousov { 2648ff7fad1SKonstantin Belousov int prev_stops, rc; 2658ff7fad1SKonstantin Belousov 2668ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2678ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_fhtovp)(mp, fidp, flags, vpp); 2688ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2698ff7fad1SKonstantin Belousov return (rc); 2708ff7fad1SKonstantin Belousov } 2718ff7fad1SKonstantin Belousov 2728ff7fad1SKonstantin Belousov static int 2731f7104d7SRick Macklem vfs_checkexp_sigdefer(struct mount *mp, struct sockaddr *nam, uint64_t *exflg, 2741f7104d7SRick Macklem struct ucred **credp, int *numsecflavors, int *secflavors) 2758ff7fad1SKonstantin Belousov { 2768ff7fad1SKonstantin Belousov int prev_stops, rc; 2778ff7fad1SKonstantin Belousov 2788ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2798ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_checkexp)(mp, nam, exflg, credp, 2808ff7fad1SKonstantin Belousov numsecflavors, secflavors); 2818ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2828ff7fad1SKonstantin Belousov return (rc); 2838ff7fad1SKonstantin Belousov } 2848ff7fad1SKonstantin Belousov 2858ff7fad1SKonstantin Belousov static int 2868ff7fad1SKonstantin Belousov vfs_extattrctl_sigdefer(struct mount *mp, int cmd, struct vnode *filename_vp, 2878ff7fad1SKonstantin Belousov int attrnamespace, const char *attrname) 2888ff7fad1SKonstantin Belousov { 2898ff7fad1SKonstantin Belousov int prev_stops, rc; 2908ff7fad1SKonstantin Belousov 2918ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 2928ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_extattrctl)(mp, cmd, 2938ff7fad1SKonstantin Belousov filename_vp, attrnamespace, attrname); 2948ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 2958ff7fad1SKonstantin Belousov return (rc); 2968ff7fad1SKonstantin Belousov } 2978ff7fad1SKonstantin Belousov 2988ff7fad1SKonstantin Belousov static int 2998ff7fad1SKonstantin Belousov vfs_sysctl_sigdefer(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 3008ff7fad1SKonstantin Belousov { 3018ff7fad1SKonstantin Belousov int prev_stops, rc; 3028ff7fad1SKonstantin Belousov 3038ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3048ff7fad1SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_sysctl)(mp, op, req); 3058ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3068ff7fad1SKonstantin Belousov return (rc); 3078ff7fad1SKonstantin Belousov } 3088ff7fad1SKonstantin Belousov 3098ff7fad1SKonstantin Belousov static void 3108ff7fad1SKonstantin Belousov vfs_susp_clean_sigdefer(struct mount *mp) 3118ff7fad1SKonstantin Belousov { 3128ff7fad1SKonstantin Belousov int prev_stops; 3138ff7fad1SKonstantin Belousov 3148ff7fad1SKonstantin Belousov if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_susp_clean == NULL) 3158ff7fad1SKonstantin Belousov return; 3168ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3178ff7fad1SKonstantin Belousov (*mp->mnt_vfc->vfc_vfsops_sd->vfs_susp_clean)(mp); 3188ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3198ff7fad1SKonstantin Belousov } 3208ff7fad1SKonstantin Belousov 3218ff7fad1SKonstantin Belousov static void 3228ff7fad1SKonstantin Belousov vfs_reclaim_lowervp_sigdefer(struct mount *mp, struct vnode *vp) 3238ff7fad1SKonstantin Belousov { 3248ff7fad1SKonstantin Belousov int prev_stops; 3258ff7fad1SKonstantin Belousov 3268ff7fad1SKonstantin Belousov if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_reclaim_lowervp == NULL) 3278ff7fad1SKonstantin Belousov return; 3288ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3298ff7fad1SKonstantin Belousov (*mp->mnt_vfc->vfc_vfsops_sd->vfs_reclaim_lowervp)(mp, vp); 3308ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3318ff7fad1SKonstantin Belousov } 3328ff7fad1SKonstantin Belousov 3338ff7fad1SKonstantin Belousov static void 3348ff7fad1SKonstantin Belousov vfs_unlink_lowervp_sigdefer(struct mount *mp, struct vnode *vp) 3358ff7fad1SKonstantin Belousov { 3368ff7fad1SKonstantin Belousov int prev_stops; 3378ff7fad1SKonstantin Belousov 3388ff7fad1SKonstantin Belousov if (*mp->mnt_vfc->vfc_vfsops_sd->vfs_unlink_lowervp == NULL) 3398ff7fad1SKonstantin Belousov return; 3408ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3418ff7fad1SKonstantin Belousov (*(mp)->mnt_vfc->vfc_vfsops_sd->vfs_unlink_lowervp)(mp, vp); 3428ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3438ff7fad1SKonstantin Belousov } 3448ff7fad1SKonstantin Belousov 3458ff7fad1SKonstantin Belousov static void 3468ff7fad1SKonstantin Belousov vfs_purge_sigdefer(struct mount *mp) 3478ff7fad1SKonstantin Belousov { 3488ff7fad1SKonstantin Belousov int prev_stops; 3498ff7fad1SKonstantin Belousov 3508ff7fad1SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 3518ff7fad1SKonstantin Belousov (*mp->mnt_vfc->vfc_vfsops_sd->vfs_purge)(mp); 3528ff7fad1SKonstantin Belousov sigallowstop(prev_stops); 3538ff7fad1SKonstantin Belousov } 3548ff7fad1SKonstantin Belousov 355eca39864SKonstantin Belousov static int 356eca39864SKonstantin Belousov vfs_report_lockf_sigdefer(struct mount *mp, struct sbuf *sb) 357eca39864SKonstantin Belousov { 358eca39864SKonstantin Belousov int prev_stops, rc; 359eca39864SKonstantin Belousov 360eca39864SKonstantin Belousov prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); 361eca39864SKonstantin Belousov rc = (*mp->mnt_vfc->vfc_vfsops_sd->vfs_report_lockf)(mp, sb); 362eca39864SKonstantin Belousov sigallowstop(prev_stops); 363eca39864SKonstantin Belousov return (rc); 364eca39864SKonstantin Belousov } 365eca39864SKonstantin Belousov 3668ff7fad1SKonstantin Belousov static struct vfsops vfsops_sigdefer = { 3678ff7fad1SKonstantin Belousov .vfs_mount = vfs_mount_sigdefer, 3688ff7fad1SKonstantin Belousov .vfs_unmount = vfs_unmount_sigdefer, 3698ff7fad1SKonstantin Belousov .vfs_root = vfs_root_sigdefer, 370dc20b834SMateusz Guzik .vfs_cachedroot = vfs_cachedroot_sigdefer, 3718ff7fad1SKonstantin Belousov .vfs_quotactl = vfs_quotactl_sigdefer, 3728ff7fad1SKonstantin Belousov .vfs_statfs = vfs_statfs_sigdefer, 3738ff7fad1SKonstantin Belousov .vfs_sync = vfs_sync_sigdefer, 3748ff7fad1SKonstantin Belousov .vfs_vget = vfs_vget_sigdefer, 3758ff7fad1SKonstantin Belousov .vfs_fhtovp = vfs_fhtovp_sigdefer, 3768ff7fad1SKonstantin Belousov .vfs_checkexp = vfs_checkexp_sigdefer, 3778ff7fad1SKonstantin Belousov .vfs_extattrctl = vfs_extattrctl_sigdefer, 3788ff7fad1SKonstantin Belousov .vfs_sysctl = vfs_sysctl_sigdefer, 3798ff7fad1SKonstantin Belousov .vfs_susp_clean = vfs_susp_clean_sigdefer, 3808ff7fad1SKonstantin Belousov .vfs_reclaim_lowervp = vfs_reclaim_lowervp_sigdefer, 3818ff7fad1SKonstantin Belousov .vfs_unlink_lowervp = vfs_unlink_lowervp_sigdefer, 3828ff7fad1SKonstantin Belousov .vfs_purge = vfs_purge_sigdefer, 383eca39864SKonstantin Belousov .vfs_report_lockf = vfs_report_lockf_sigdefer, 3848ff7fad1SKonstantin Belousov }; 38532ba8e93SPoul-Henning Kamp 386eb8e6d52SEivind Eklund /* Register a new filesystem type in the global table */ 387ebbfc2f8SPoul-Henning Kamp static int 3884e61198eSPeter Wemm vfs_register(struct vfsconf *vfc) 389aa855a59SPeter Wemm { 390a199ed3cSDoug Rabson struct sysctl_oid *oidp; 3917652131bSPoul-Henning Kamp struct vfsops *vfsops; 392273350adSPoul-Henning Kamp static int once; 3934d30adc4SRick Macklem struct vfsconf *tvfc; 3944d30adc4SRick Macklem uint32_t hashval; 3954d30adc4SRick Macklem int secondpass; 396273350adSPoul-Henning Kamp 397273350adSPoul-Henning Kamp if (!once) { 398273350adSPoul-Henning Kamp vattr_null(&va_null); 399273350adSPoul-Henning Kamp once = 1; 400273350adSPoul-Henning Kamp } 4017652131bSPoul-Henning Kamp 4025e8c582aSPoul-Henning Kamp if (vfc->vfc_version != VFS_VERSION) { 4035e8c582aSPoul-Henning Kamp printf("ERROR: filesystem %s, unsupported ABI version %x\n", 4045e8c582aSPoul-Henning Kamp vfc->vfc_name, vfc->vfc_version); 4055e8c582aSPoul-Henning Kamp return (EINVAL); 4065e8c582aSPoul-Henning Kamp } 407168f4ee0SKonstantin Belousov vfsconf_lock(); 408168f4ee0SKonstantin Belousov if (vfs_byname_locked(vfc->vfc_name) != NULL) { 409168f4ee0SKonstantin Belousov vfsconf_unlock(); 4105050aa86SKonstantin Belousov return (EEXIST); 411168f4ee0SKonstantin Belousov } 412aa855a59SPeter Wemm 4134d30adc4SRick Macklem if (vfs_typenumhash != 0) { 4144d30adc4SRick Macklem /* 4154d30adc4SRick Macklem * Calculate a hash on vfc_name to use for vfc_typenum. Unless 4164d30adc4SRick Macklem * all of 1<->255 are assigned, it is limited to 8bits since 4174d30adc4SRick Macklem * that is what ZFS uses from vfc_typenum and is also the 4184d30adc4SRick Macklem * preferred range for vfs_getnewfsid(). 4194d30adc4SRick Macklem */ 4204d30adc4SRick Macklem hashval = fnv_32_str(vfc->vfc_name, FNV1_32_INIT); 4214d30adc4SRick Macklem hashval &= 0xff; 4224d30adc4SRick Macklem secondpass = 0; 4234d30adc4SRick Macklem do { 4244d30adc4SRick Macklem /* Look for and fix any collision. */ 4254d30adc4SRick Macklem TAILQ_FOREACH(tvfc, &vfsconf, vfc_list) { 4264d30adc4SRick Macklem if (hashval == tvfc->vfc_typenum) { 4274d30adc4SRick Macklem if (hashval == 255 && secondpass == 0) { 4284d30adc4SRick Macklem hashval = 1; 4294d30adc4SRick Macklem secondpass = 1; 4304d30adc4SRick Macklem } else 4314d30adc4SRick Macklem hashval++; 4324d30adc4SRick Macklem break; 4334d30adc4SRick Macklem } 4344d30adc4SRick Macklem } 4354d30adc4SRick Macklem } while (tvfc != NULL); 4364d30adc4SRick Macklem vfc->vfc_typenum = hashval; 4374d30adc4SRick Macklem if (vfc->vfc_typenum >= maxvfsconf) 4384d30adc4SRick Macklem maxvfsconf = vfc->vfc_typenum + 1; 4394d30adc4SRick Macklem } else 440aa855a59SPeter Wemm vfc->vfc_typenum = maxvfsconf++; 4413dfe213eSPoul-Henning Kamp TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); 442aa855a59SPeter Wemm 443aa855a59SPeter Wemm /* 4447652131bSPoul-Henning Kamp * Initialise unused ``struct vfsops'' fields, to use 4457652131bSPoul-Henning Kamp * the vfs_std*() functions. Note, we need the mount 4467652131bSPoul-Henning Kamp * and unmount operations, at the least. The check 4477652131bSPoul-Henning Kamp * for vfsops available is just a debugging aid. 4487652131bSPoul-Henning Kamp */ 4497652131bSPoul-Henning Kamp KASSERT(vfc->vfc_vfsops != NULL, 4507652131bSPoul-Henning Kamp ("Filesystem %s has no vfsops", vfc->vfc_name)); 4517652131bSPoul-Henning Kamp /* 4527652131bSPoul-Henning Kamp * Check the mount and unmount operations. 4537652131bSPoul-Henning Kamp */ 4547652131bSPoul-Henning Kamp vfsops = vfc->vfc_vfsops; 45520a92a18SPoul-Henning Kamp KASSERT(vfsops->vfs_mount != NULL, 45620a92a18SPoul-Henning Kamp ("Filesystem %s has no mount op", vfc->vfc_name)); 4577652131bSPoul-Henning Kamp KASSERT(vfsops->vfs_unmount != NULL, 4587652131bSPoul-Henning Kamp ("Filesystem %s has no unmount op", vfc->vfc_name)); 4597652131bSPoul-Henning Kamp 4607652131bSPoul-Henning Kamp if (vfsops->vfs_root == NULL) 4617652131bSPoul-Henning Kamp /* return file system's root vnode */ 4627652131bSPoul-Henning Kamp vfsops->vfs_root = vfs_stdroot; 4637652131bSPoul-Henning Kamp if (vfsops->vfs_quotactl == NULL) 4647652131bSPoul-Henning Kamp /* quota control */ 4657652131bSPoul-Henning Kamp vfsops->vfs_quotactl = vfs_stdquotactl; 4667652131bSPoul-Henning Kamp if (vfsops->vfs_statfs == NULL) 4677652131bSPoul-Henning Kamp /* return file system's status */ 4687652131bSPoul-Henning Kamp vfsops->vfs_statfs = vfs_stdstatfs; 4697652131bSPoul-Henning Kamp if (vfsops->vfs_sync == NULL) 4707652131bSPoul-Henning Kamp /* 4717652131bSPoul-Henning Kamp * flush unwritten data (nosync) 4727652131bSPoul-Henning Kamp * file systems can use vfs_stdsync 4737652131bSPoul-Henning Kamp * explicitly by setting it in the 4747652131bSPoul-Henning Kamp * vfsop vector. 4757652131bSPoul-Henning Kamp */ 4767652131bSPoul-Henning Kamp vfsops->vfs_sync = vfs_stdnosync; 4777652131bSPoul-Henning Kamp if (vfsops->vfs_vget == NULL) 4787652131bSPoul-Henning Kamp /* convert an inode number to a vnode */ 4797652131bSPoul-Henning Kamp vfsops->vfs_vget = vfs_stdvget; 4807652131bSPoul-Henning Kamp if (vfsops->vfs_fhtovp == NULL) 4817652131bSPoul-Henning Kamp /* turn an NFS file handle into a vnode */ 4827652131bSPoul-Henning Kamp vfsops->vfs_fhtovp = vfs_stdfhtovp; 4837652131bSPoul-Henning Kamp if (vfsops->vfs_checkexp == NULL) 4847652131bSPoul-Henning Kamp /* check if file system is exported */ 4857652131bSPoul-Henning Kamp vfsops->vfs_checkexp = vfs_stdcheckexp; 4867652131bSPoul-Henning Kamp if (vfsops->vfs_init == NULL) 4877652131bSPoul-Henning Kamp /* file system specific initialisation */ 4887652131bSPoul-Henning Kamp vfsops->vfs_init = vfs_stdinit; 4897652131bSPoul-Henning Kamp if (vfsops->vfs_uninit == NULL) 4907652131bSPoul-Henning Kamp /* file system specific uninitialisation */ 4917652131bSPoul-Henning Kamp vfsops->vfs_uninit = vfs_stduninit; 4927652131bSPoul-Henning Kamp if (vfsops->vfs_extattrctl == NULL) 4937652131bSPoul-Henning Kamp /* extended attribute control */ 4947652131bSPoul-Henning Kamp vfsops->vfs_extattrctl = vfs_stdextattrctl; 49581d16e2dSAlfred Perlstein if (vfsops->vfs_sysctl == NULL) 49681d16e2dSAlfred Perlstein vfsops->vfs_sysctl = vfs_stdsysctl; 497eca39864SKonstantin Belousov if (vfsops->vfs_report_lockf == NULL) 498eca39864SKonstantin Belousov vfsops->vfs_report_lockf = vfs_report_lockf; 4997652131bSPoul-Henning Kamp 5008ff7fad1SKonstantin Belousov if ((vfc->vfc_flags & VFCF_SBDRY) != 0) { 5018ff7fad1SKonstantin Belousov vfc->vfc_vfsops_sd = vfc->vfc_vfsops; 5028ff7fad1SKonstantin Belousov vfc->vfc_vfsops = &vfsops_sigdefer; 5038ff7fad1SKonstantin Belousov } 5048ff7fad1SKonstantin Belousov 5050e5c6bd4SJamie Gritton if (vfc->vfc_flags & VFCF_JAIL) 5060e5c6bd4SJamie Gritton prison_add_vfs(vfc); 5070e5c6bd4SJamie Gritton 5087652131bSPoul-Henning Kamp /* 509aa855a59SPeter Wemm * Call init function for this VFS... 510aa855a59SPeter Wemm */ 5118ff7fad1SKonstantin Belousov if ((vfc->vfc_flags & VFCF_SBDRY) != 0) 5128ff7fad1SKonstantin Belousov vfc->vfc_vfsops_sd->vfs_init(vfc); 5138ff7fad1SKonstantin Belousov else 5148ff7fad1SKonstantin Belousov vfc->vfc_vfsops->vfs_init(vfc); 515168f4ee0SKonstantin Belousov vfsconf_unlock(); 516aa855a59SPeter Wemm 517168f4ee0SKonstantin Belousov /* 518168f4ee0SKonstantin Belousov * If this filesystem has a sysctl node under vfs 519168f4ee0SKonstantin Belousov * (i.e. vfs.xxfs), then change the oid number of that node to 520168f4ee0SKonstantin Belousov * match the filesystem's type number. This allows user code 521168f4ee0SKonstantin Belousov * which uses the type number to read sysctl variables defined 522168f4ee0SKonstantin Belousov * by the filesystem to continue working. Since the oids are 523168f4ee0SKonstantin Belousov * in a sorted list, we need to make sure the order is 524168f4ee0SKonstantin Belousov * preserved by re-registering the oid after modifying its 525168f4ee0SKonstantin Belousov * number. 526168f4ee0SKonstantin Belousov */ 5277665e341SMateusz Guzik sysctl_wlock(); 528d3f96f66SAlan Somers RB_FOREACH(oidp, sysctl_oid_list, SYSCTL_CHILDREN(&sysctl___vfs)) { 529168f4ee0SKonstantin Belousov if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 530168f4ee0SKonstantin Belousov sysctl_unregister_oid(oidp); 531168f4ee0SKonstantin Belousov oidp->oid_number = vfc->vfc_typenum; 532168f4ee0SKonstantin Belousov sysctl_register_oid(oidp); 533168f4ee0SKonstantin Belousov break; 534168f4ee0SKonstantin Belousov } 535168f4ee0SKonstantin Belousov } 5367665e341SMateusz Guzik sysctl_wunlock(); 537168f4ee0SKonstantin Belousov 538168f4ee0SKonstantin Belousov return (0); 539aa855a59SPeter Wemm } 540aa855a59SPeter Wemm 541eb8e6d52SEivind Eklund /* Remove registration of a filesystem type */ 542ebbfc2f8SPoul-Henning Kamp static int 5434e61198eSPeter Wemm vfs_unregister(struct vfsconf *vfc) 544aa855a59SPeter Wemm { 5453dfe213eSPoul-Henning Kamp struct vfsconf *vfsp; 54669baeadcSKonstantin Belousov int error, maxtypenum; 547aa855a59SPeter Wemm 548168f4ee0SKonstantin Belousov vfsconf_lock(); 549168f4ee0SKonstantin Belousov vfsp = vfs_byname_locked(vfc->vfc_name); 550168f4ee0SKonstantin Belousov if (vfsp == NULL) { 551168f4ee0SKonstantin Belousov vfsconf_unlock(); 552168f4ee0SKonstantin Belousov return (EINVAL); 553168f4ee0SKonstantin Belousov } 554168f4ee0SKonstantin Belousov if (vfsp->vfc_refcount != 0) { 555168f4ee0SKonstantin Belousov vfsconf_unlock(); 556168f4ee0SKonstantin Belousov return (EBUSY); 557168f4ee0SKonstantin Belousov } 5588ff7fad1SKonstantin Belousov error = 0; 5598ff7fad1SKonstantin Belousov if ((vfc->vfc_flags & VFCF_SBDRY) != 0) { 5608ff7fad1SKonstantin Belousov if (vfc->vfc_vfsops_sd->vfs_uninit != NULL) 5618ff7fad1SKonstantin Belousov error = vfc->vfc_vfsops_sd->vfs_uninit(vfsp); 5628ff7fad1SKonstantin Belousov } else { 5631517b8d5SMarvin Ma if (vfc->vfc_vfsops->vfs_uninit != NULL) 5648ff7fad1SKonstantin Belousov error = vfc->vfc_vfsops->vfs_uninit(vfsp); 5658ff7fad1SKonstantin Belousov } 566168f4ee0SKonstantin Belousov if (error != 0) { 567168f4ee0SKonstantin Belousov vfsconf_unlock(); 568aa855a59SPeter Wemm return (error); 569aa855a59SPeter Wemm } 5703dfe213eSPoul-Henning Kamp TAILQ_REMOVE(&vfsconf, vfsp, vfc_list); 571aa855a59SPeter Wemm maxtypenum = VFS_GENERIC; 5723dfe213eSPoul-Henning Kamp TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 573aa855a59SPeter Wemm if (maxtypenum < vfsp->vfc_typenum) 574aa855a59SPeter Wemm maxtypenum = vfsp->vfc_typenum; 575aa855a59SPeter Wemm maxvfsconf = maxtypenum + 1; 576168f4ee0SKonstantin Belousov vfsconf_unlock(); 577168f4ee0SKonstantin Belousov return (0); 578aa855a59SPeter Wemm } 5794e61198eSPeter Wemm 580eb8e6d52SEivind Eklund /* 581eb8e6d52SEivind Eklund * Standard kernel module handling code for filesystem modules. 582eb8e6d52SEivind Eklund * Referenced from VFS_SET(). 583eb8e6d52SEivind Eklund */ 5844e61198eSPeter Wemm int 5854ae860afSBruce Evans vfs_modevent(module_t mod, int type, void *data) 5864e61198eSPeter Wemm { 5874e61198eSPeter Wemm struct vfsconf *vfc; 5884e61198eSPeter Wemm int error = 0; 5894e61198eSPeter Wemm 5904e61198eSPeter Wemm vfc = (struct vfsconf *)data; 5914e61198eSPeter Wemm 5924e61198eSPeter Wemm switch (type) { 5934e61198eSPeter Wemm case MOD_LOAD: 5944e61198eSPeter Wemm if (vfc) 5954e61198eSPeter Wemm error = vfs_register(vfc); 5964e61198eSPeter Wemm break; 5974e61198eSPeter Wemm 5984e61198eSPeter Wemm case MOD_UNLOAD: 5994e61198eSPeter Wemm if (vfc) 6004e61198eSPeter Wemm error = vfs_unregister(vfc); 6014e61198eSPeter Wemm break; 6023e019deaSPoul-Henning Kamp default: 6033e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 6044e61198eSPeter Wemm break; 6054e61198eSPeter Wemm } 6064e61198eSPeter Wemm return (error); 6074e61198eSPeter Wemm } 608