1 /* 2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * 35 * Copyright (c) 1989, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This code is derived from software contributed 39 * to Berkeley by John Heidemann of the UCLA Ficus project. 40 * 41 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 72 * $FreeBSD: src/sys/kern/vfs_init.c,v 1.59 2002/04/30 18:44:32 dillon Exp $ 73 * $DragonFly: src/sys/kern/vfs_init.c,v 1.15 2008/06/01 19:27:35 dillon Exp $ 74 */ 75 /* 76 * Manage vnode VOP operations vectors 77 */ 78 #include <sys/param.h> 79 #include <sys/systm.h> 80 #include <sys/kernel.h> 81 #include <sys/mount.h> 82 #include <sys/sysctl.h> 83 #include <sys/vnode.h> 84 #include <sys/malloc.h> 85 #include <sys/objcache.h> 86 87 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors"); 88 static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers"); 89 90 /* 91 * Zone for namei 92 */ 93 struct objcache *namei_oc; 94 95 /* 96 * vfs_init() will set maxvfsconf 97 * to the highest defined type number. 98 */ 99 int maxvfsconf; 100 struct vfsconf *vfsconf; 101 102 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list; 103 static void vfs_calc_vnodeops(struct vop_ops *ops); 104 105 /* 106 * Add a vnode operations (vnops) vector to the global list. 107 */ 108 void 109 vfs_nadd_vnodeops_sysinit(void *data) 110 { 111 struct vop_ops *ops = data; 112 113 vfs_add_vnodeops(NULL, ops, NULL); /* mount, template, newcopy */ 114 } 115 116 /* 117 * Unlink previously added vnode operations vector. 118 */ 119 void 120 vfs_nrm_vnodeops_sysinit(void *data) 121 { 122 struct vop_ops *ops = data; 123 124 vfs_rm_vnodeops(NULL, ops, NULL); 125 } 126 127 void 128 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template, 129 struct vop_ops **ops_pp) 130 { 131 struct vop_ops *ops; 132 133 if (ops_pp) { 134 KKASSERT(*ops_pp == NULL); 135 *ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK); 136 ops = *ops_pp; 137 bcopy(template, ops, sizeof(*ops)); 138 } else { 139 ops = template; 140 } 141 142 vfs_calc_vnodeops(ops); 143 ops->head.vv_mount = mp; 144 145 if (mp) { 146 if (mp->mnt_vn_coherency_ops) 147 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 148 else if (mp->mnt_vn_journal_ops) 149 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 150 else 151 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 152 } 153 } 154 155 /* 156 * Remove a previously installed operations vector. 157 * 158 * NOTE: Either template or ops_pp may be NULL, but not both. 159 */ 160 void 161 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template, 162 struct vop_ops **ops_pp) 163 { 164 struct vop_ops *ops; 165 166 if (ops_pp) { 167 ops = *ops_pp; 168 *ops_pp = NULL; 169 } else { 170 ops = template; 171 } 172 if (ops == NULL) 173 return; 174 KKASSERT(mp == ops->head.vv_mount); 175 if (mp) { 176 if (mp->mnt_vn_coherency_ops) 177 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 178 else if (mp->mnt_vn_journal_ops) 179 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 180 else 181 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 182 } 183 if (ops_pp) 184 kfree(ops, M_VNODEOP); 185 } 186 187 /* 188 * Calculate the VFS operations vector array. This function basically 189 * replaces any NULL entry with the default entry. 190 */ 191 static void 192 vfs_calc_vnodeops(struct vop_ops *ops) 193 { 194 int off; 195 196 for (off = __offsetof(struct vop_ops, vop_ops_first_field); 197 off <= __offsetof(struct vop_ops, vop_ops_last_field); 198 off += sizeof(void *) 199 ) { 200 if (*(void **)((char *)ops + off) == NULL) 201 *(void **)((char *)ops + off) = ops->vop_default; 202 } 203 } 204 205 /* 206 * Routines having to do with the management of the vnode table. 207 */ 208 struct vattr va_null; 209 210 /* 211 * Initialize the vnode structures and initialize each file system type. 212 */ 213 /* ARGSUSED*/ 214 static void 215 vfsinit(void *dummy) 216 { 217 TAILQ_INIT(&vnodeopv_list); 218 namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN); 219 220 /* 221 * Initialize the vnode table 222 */ 223 vfs_subr_init(); 224 vfs_mount_init(); 225 vfs_lock_init(); 226 vfs_sync_init(); 227 /* 228 * Initialize the vnode name cache 229 */ 230 nchinit(); 231 /* 232 * Initialize each file system type. 233 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF). 234 */ 235 vattr_null(&va_null); 236 maxvfsconf = VFS_GENERIC + 1; 237 } 238 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 239 240 /* 241 * Register a VFS. 242 * 243 * After doing general initialisation, this function will 244 * call the filesystem specific initialisation vector op, 245 * i.e. vfsops->vfs_init(). 246 */ 247 int 248 vfs_register(struct vfsconf *vfc) 249 { 250 struct sysctl_oid *oidp; 251 struct vfsconf *vfsp; 252 struct vfsops *vfsops = NULL; 253 254 vfsp = NULL; 255 if (vfsconf) 256 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) 257 if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0) 258 return EEXIST; 259 260 vfc->vfc_typenum = maxvfsconf++; 261 if (vfsp) 262 vfsp->vfc_next = vfc; 263 else 264 vfsconf = vfc; 265 vfc->vfc_next = NULL; 266 267 /* 268 * If this filesystem has a sysctl node under vfs 269 * (i.e. vfs.xxfs), then change the oid number of that node to 270 * match the filesystem's type number. This allows user code 271 * which uses the type number to read sysctl variables defined 272 * by the filesystem to continue working. Since the oids are 273 * in a sorted list, we need to make sure the order is 274 * preserved by re-registering the oid after modifying its 275 * number. 276 */ 277 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 278 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 279 sysctl_unregister_oid(oidp); 280 oidp->oid_number = vfc->vfc_typenum; 281 sysctl_register_oid(oidp); 282 } 283 284 /* 285 * Initialise unused fields in the file system's vfsops vector. 286 * 287 * NOTE the file system should provide the mount and unmount ops 288 * at the least. In order for unmount to succeed, we also need 289 * the file system to provide us with vfsops->vfs_root otherwise 290 * the unmount(2) operation will not succeed. 291 */ 292 vfsops = vfc->vfc_vfsops; 293 KKASSERT(vfc->vfc_vfsops != NULL); 294 KKASSERT(vfsops->vfs_mount != NULL); 295 KKASSERT(vfsops->vfs_root != NULL); 296 KKASSERT(vfsops->vfs_unmount != NULL); 297 298 if (vfsops->vfs_root == NULL) { 299 /* return file system's root vnode */ 300 vfsops->vfs_root = vfs_stdroot; 301 } 302 if (vfsops->vfs_start == NULL) { 303 /* 304 * Make file system operational before first use. This 305 * routine is called at mount-time for initialising MFS, 306 * not used by other file systems. 307 */ 308 vfsops->vfs_start = vfs_stdstart; 309 } 310 if (vfsops->vfs_quotactl == NULL) { 311 /* quota control */ 312 vfsops->vfs_quotactl = vfs_stdquotactl; 313 } 314 if (vfsops->vfs_statfs == NULL) { 315 /* return file system's status */ 316 vfsops->vfs_statfs = vfs_stdstatfs; 317 } 318 if (vfsops->vfs_statvfs == NULL) { 319 /* return file system's status */ 320 vfsops->vfs_statvfs = vfs_stdstatvfs; 321 } 322 if (vfsops->vfs_sync == NULL) { 323 /* 324 * Flush dirty buffers. File systems can use vfs_stdsync() 325 * by explicitly setting it in the vfsops->vfs_sync vector 326 * entry. 327 */ 328 vfsops->vfs_sync = vfs_stdnosync; 329 } 330 if (vfsops->vfs_vget == NULL) { 331 /* convert an inode number to a vnode */ 332 vfsops->vfs_vget = vfs_stdvget; 333 } 334 if (vfsops->vfs_fhtovp == NULL) { 335 /* turn an NFS file handle into a vnode */ 336 vfsops->vfs_fhtovp = vfs_stdfhtovp; 337 } 338 if (vfsops->vfs_checkexp == NULL) { 339 /* check if file system is exported */ 340 vfsops->vfs_checkexp = vfs_stdcheckexp; 341 } 342 if (vfsops->vfs_vptofh == NULL) { 343 /* turn a vnode into an NFS file handle */ 344 vfsops->vfs_vptofh = vfs_stdvptofh; 345 } 346 if (vfsops->vfs_init == NULL) { 347 /* file system specific initialisation */ 348 vfsops->vfs_init = vfs_stdinit; 349 } 350 if (vfsops->vfs_uninit == NULL) { 351 /* file system specific uninitialisation */ 352 vfsops->vfs_uninit = vfs_stduninit; 353 } 354 if (vfsops->vfs_extattrctl == NULL) { 355 /* extended attribute control */ 356 vfsops->vfs_extattrctl = vfs_stdextattrctl; 357 } 358 359 /* 360 * Call init function for this VFS... 361 */ 362 (*(vfc->vfc_vfsops->vfs_init))(vfc); 363 364 return 0; 365 } 366 367 368 /* 369 * Remove previously registered VFS. 370 * 371 * After doing general de-registration like removing sysctl 372 * nodes etc, it will call the filesystem specific vector 373 * op, i.e. vfsops->vfs_uninit(). 374 * 375 */ 376 int 377 vfs_unregister(struct vfsconf *vfc) 378 { 379 struct vfsconf *vfsp, *prev_vfsp; 380 int error, i, maxtypenum; 381 382 i = vfc->vfc_typenum; 383 384 prev_vfsp = NULL; 385 for (vfsp = vfsconf; vfsp; 386 prev_vfsp = vfsp, vfsp = vfsp->vfc_next) { 387 if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) 388 break; 389 } 390 if (vfsp == NULL) 391 return EINVAL; 392 if (vfsp->vfc_refcount) 393 return EBUSY; 394 if (vfc->vfc_vfsops->vfs_uninit != NULL) { 395 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 396 if (error) 397 return (error); 398 } 399 if (prev_vfsp) 400 prev_vfsp->vfc_next = vfsp->vfc_next; 401 else 402 vfsconf = vfsp->vfc_next; 403 maxtypenum = VFS_GENERIC; 404 for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next) 405 if (maxtypenum < vfsp->vfc_typenum) 406 maxtypenum = vfsp->vfc_typenum; 407 maxvfsconf = maxtypenum + 1; 408 return 0; 409 } 410 411 int 412 vfs_modevent(module_t mod, int type, void *data) 413 { 414 struct vfsconf *vfc; 415 int error = 0; 416 417 vfc = (struct vfsconf *)data; 418 419 switch (type) { 420 case MOD_LOAD: 421 if (vfc) 422 error = vfs_register(vfc); 423 break; 424 425 case MOD_UNLOAD: 426 if (vfc) 427 error = vfs_unregister(vfc); 428 break; 429 default: /* including MOD_SHUTDOWN */ 430 break; 431 } 432 return (error); 433 } 434