vfs_init.c revision 138290
1105197Ssam/* 2105197Ssam * Copyright (c) 1989, 1993 3105197Ssam * The Regents of the University of California. All rights reserved. 4139823Simp * 5105197Ssam * This code is derived from software contributed 6105197Ssam * to Berkeley by John Heidemann of the UCLA Ficus project. 7105197Ssam * 8105197Ssam * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 9105197Ssam * 10105197Ssam * Redistribution and use in source and binary forms, with or without 11105197Ssam * modification, are permitted provided that the following conditions 12105197Ssam * are met: 13105197Ssam * 1. Redistributions of source code must retain the above copyright 14105197Ssam * notice, this list of conditions and the following disclaimer. 15105197Ssam * 2. Redistributions in binary form must reproduce the above copyright 16105197Ssam * notice, this list of conditions and the following disclaimer in the 17105197Ssam * documentation and/or other materials provided with the distribution. 18105197Ssam * 4. Neither the name of the University nor the names of its contributors 19105197Ssam * may be used to endorse or promote products derived from this software 20105197Ssam * without specific prior written permission. 21105197Ssam * 22105197Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23105197Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24105197Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25105197Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26105197Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27105197Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28105197Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29105197Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30105197Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31105197Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32105197Ssam * SUCH DAMAGE. 33105197Ssam * 34105197Ssam * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 35105197Ssam */ 36105197Ssam 37105197Ssam#include <sys/cdefs.h> 38105197Ssam__FBSDID("$FreeBSD: head/sys/kern/vfs_init.c 138290 2004-12-01 23:16:38Z phk $"); 39105197Ssam 40105197Ssam#include <sys/param.h> 41105197Ssam#include <sys/systm.h> 42105197Ssam#include <sys/kernel.h> 43105197Ssam#include <sys/mount.h> 44105197Ssam#include <sys/sysctl.h> 45105197Ssam#include <sys/vnode.h> 46105197Ssam#include <sys/malloc.h> 47105197Ssam 48105197Ssam 49105197SsamMALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); 50105197Ssam 51105197Ssam/* 52105197Ssam * The highest defined VFS number. 53157123Sgnn */ 54157123Sgnnint maxvfsconf = VFS_GENERIC + 1; 55105197Ssam 56105197Ssam/* 57105197Ssam * Single-linked list of configured VFSes. 58105197Ssam * New entries are added/deleted by vfs_register()/vfs_unregister() 59 */ 60struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf); 61 62/* 63 * A Zen vnode attribute structure. 64 * 65 * Initialized when the first filesystem registers by vfs_register(). 66 */ 67struct vattr va_null; 68 69/* 70 * vfs_init.c 71 * 72 * Allocate and fill in operations vectors. 73 * 74 * An undocumented feature of this approach to defining operations is that 75 * there can be multiple entries in vfs_opv_descs for the same operations 76 * vector. This allows third parties to extend the set of operations 77 * supported by another layer in a binary compatibile way. For example, 78 * assume that NFS needed to be modified to support Ficus. NFS has an entry 79 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 80 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 81 * listing those new operations Ficus adds to NFS, all without modifying the 82 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 83 * that is a(whole)nother story.) This is a feature. 84 */ 85 86/* 87 * Routines having to do with the management of the vnode table. 88 */ 89 90/* 91 * XXX: hack alert 92 */ 93int 94vcall(struct vnode *vp, u_int off, void *ap) 95{ 96 struct vop_vector *vop = vp->v_op; 97 vop_bypass_t **bpt; 98 int rc; 99 100 for(;;) { 101 bpt = (void *)((u_char *)vop + off); 102 if (vop != NULL && *bpt == NULL && vop->vop_bypass == NULL) { 103 vop = vop->vop_default; 104 continue; 105 } 106 break; 107 } 108 KASSERT(vop != NULL, ("No VCALL(%p...)", vp)); 109 if (*bpt != NULL) 110 rc = (*bpt)(ap); 111 else 112 rc = vop->vop_bypass(ap); 113 return (rc); 114} 115 116struct vfsconf * 117vfs_byname(const char *name) 118{ 119 struct vfsconf *vfsp; 120 121 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 122 if (!strcmp(name, vfsp->vfc_name)) 123 return (vfsp); 124 return (NULL); 125} 126 127/* Register a new filesystem type in the global table */ 128int 129vfs_register(struct vfsconf *vfc) 130{ 131 struct sysctl_oid *oidp; 132 struct vfsops *vfsops; 133 static int once; 134 135 if (!once) { 136 vattr_null(&va_null); 137 once = 1; 138 } 139 140 if (vfc->vfc_version != VFS_VERSION) { 141 printf("ERROR: filesystem %s, unsupported ABI version %x\n", 142 vfc->vfc_name, vfc->vfc_version); 143 return (EINVAL); 144 } 145 if (vfs_byname(vfc->vfc_name) != NULL) 146 return EEXIST; 147 148 vfc->vfc_typenum = maxvfsconf++; 149 TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); 150 151 /* 152 * If this filesystem has a sysctl node under vfs 153 * (i.e. vfs.xxfs), then change the oid number of that node to 154 * match the filesystem's type number. This allows user code 155 * which uses the type number to read sysctl variables defined 156 * by the filesystem to continue working. Since the oids are 157 * in a sorted list, we need to make sure the order is 158 * preserved by re-registering the oid after modifying its 159 * number. 160 */ 161 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 162 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 163 sysctl_unregister_oid(oidp); 164 oidp->oid_number = vfc->vfc_typenum; 165 sysctl_register_oid(oidp); 166 } 167 168 /* 169 * Initialise unused ``struct vfsops'' fields, to use 170 * the vfs_std*() functions. Note, we need the mount 171 * and unmount operations, at the least. The check 172 * for vfsops available is just a debugging aid. 173 */ 174 KASSERT(vfc->vfc_vfsops != NULL, 175 ("Filesystem %s has no vfsops", vfc->vfc_name)); 176 /* 177 * Check the mount and unmount operations. 178 */ 179 vfsops = vfc->vfc_vfsops; 180 KASSERT(vfsops->vfs_mount != NULL || vfsops->vfs_omount != NULL, 181 ("Filesystem %s has no (o)mount op", vfc->vfc_name)); 182 KASSERT(vfsops->vfs_unmount != NULL, 183 ("Filesystem %s has no unmount op", vfc->vfc_name)); 184 185 if (vfsops->vfs_start == NULL) 186 /* make a file system operational */ 187 vfsops->vfs_start = vfs_stdstart; 188 if (vfsops->vfs_root == NULL) 189 /* return file system's root vnode */ 190 vfsops->vfs_root = vfs_stdroot; 191 if (vfsops->vfs_quotactl == NULL) 192 /* quota control */ 193 vfsops->vfs_quotactl = vfs_stdquotactl; 194 if (vfsops->vfs_statfs == NULL) 195 /* return file system's status */ 196 vfsops->vfs_statfs = vfs_stdstatfs; 197 if (vfsops->vfs_sync == NULL) 198 /* 199 * flush unwritten data (nosync) 200 * file systems can use vfs_stdsync 201 * explicitly by setting it in the 202 * vfsop vector. 203 */ 204 vfsops->vfs_sync = vfs_stdnosync; 205 if (vfsops->vfs_vget == NULL) 206 /* convert an inode number to a vnode */ 207 vfsops->vfs_vget = vfs_stdvget; 208 if (vfsops->vfs_fhtovp == NULL) 209 /* turn an NFS file handle into a vnode */ 210 vfsops->vfs_fhtovp = vfs_stdfhtovp; 211 if (vfsops->vfs_checkexp == NULL) 212 /* check if file system is exported */ 213 vfsops->vfs_checkexp = vfs_stdcheckexp; 214 if (vfsops->vfs_vptofh == NULL) 215 /* turn a vnode into an NFS file handle */ 216 vfsops->vfs_vptofh = vfs_stdvptofh; 217 if (vfsops->vfs_init == NULL) 218 /* file system specific initialisation */ 219 vfsops->vfs_init = vfs_stdinit; 220 if (vfsops->vfs_uninit == NULL) 221 /* file system specific uninitialisation */ 222 vfsops->vfs_uninit = vfs_stduninit; 223 if (vfsops->vfs_extattrctl == NULL) 224 /* extended attribute control */ 225 vfsops->vfs_extattrctl = vfs_stdextattrctl; 226 if (vfsops->vfs_sysctl == NULL) 227 vfsops->vfs_sysctl = vfs_stdsysctl; 228 229 /* 230 * Call init function for this VFS... 231 */ 232 (*(vfc->vfc_vfsops->vfs_init))(vfc); 233 234 return 0; 235} 236 237 238/* Remove registration of a filesystem type */ 239int 240vfs_unregister(struct vfsconf *vfc) 241{ 242 struct vfsconf *vfsp; 243 int error, i, maxtypenum; 244 245 i = vfc->vfc_typenum; 246 247 vfsp = vfs_byname(vfc->vfc_name); 248 if (vfsp == NULL) 249 return EINVAL; 250 if (vfsp->vfc_refcount) 251 return EBUSY; 252 if (vfc->vfc_vfsops->vfs_uninit != NULL) { 253 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 254 if (error) 255 return (error); 256 } 257 TAILQ_REMOVE(&vfsconf, vfsp, vfc_list); 258 maxtypenum = VFS_GENERIC; 259 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 260 if (maxtypenum < vfsp->vfc_typenum) 261 maxtypenum = vfsp->vfc_typenum; 262 maxvfsconf = maxtypenum + 1; 263 return 0; 264} 265 266/* 267 * Standard kernel module handling code for filesystem modules. 268 * Referenced from VFS_SET(). 269 */ 270int 271vfs_modevent(module_t mod, int type, void *data) 272{ 273 struct vfsconf *vfc; 274 int error = 0; 275 276 vfc = (struct vfsconf *)data; 277 278 switch (type) { 279 case MOD_LOAD: 280 if (vfc) 281 error = vfs_register(vfc); 282 break; 283 284 case MOD_UNLOAD: 285 if (vfc) 286 error = vfs_unregister(vfc); 287 break; 288 default: 289 error = EOPNOTSUPP; 290 break; 291 } 292 return (error); 293} 294