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.12 2006/06/01 06:10:50 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_recalc_vnodeops(void); 104 105 /* 106 * Add a vnode operations (vnops) vector to the global list. 107 */ 108 void 109 vfs_add_vnodeops_sysinit(const void *data) 110 { 111 const struct vnodeopv_desc *vdesc = data; 112 113 vfs_add_vnodeops(NULL, vdesc->opv_desc_vector, 114 vdesc->opv_desc_ops, vdesc->opv_flags); 115 } 116 117 /* 118 * Unlink previously added vnode operations vector. 119 */ 120 void 121 vfs_rm_vnodeops_sysinit(const void *data) 122 { 123 const struct vnodeopv_desc *vdesc = data; 124 125 vfs_rm_vnodeops(vdesc->opv_desc_vector); 126 } 127 128 void 129 vfs_add_vnodeops(struct mount *mp, struct vop_ops **vops_pp, 130 struct vnodeopv_entry_desc *descs, int flags) 131 { 132 struct vnodeopv_node *node; 133 struct vop_ops *ops; 134 135 node = malloc(sizeof(*node), M_VNODEOP, M_ZERO|M_WAITOK); 136 KKASSERT(*vops_pp == NULL); 137 if ((ops = *vops_pp) == NULL) { 138 ops = malloc(sizeof(struct vop_ops), 139 M_VNODEOP, M_ZERO|M_WAITOK); 140 *vops_pp = ops; 141 } 142 node->ops = ops; 143 node->descs = descs; 144 ops->vv_mount = mp; 145 ops->vv_flags |= flags; 146 147 /* 148 * Journal and coherency ops inherit normal ops flags 149 */ 150 if (vops_pp == &mp->mnt_vn_coherency_ops && mp->mnt_vn_norm_ops) 151 ops->vv_flags |= mp->mnt_vn_norm_ops->vv_flags; 152 if (vops_pp == &mp->mnt_vn_journal_ops && mp->mnt_vn_norm_ops) 153 ops->vv_flags |= mp->mnt_vn_norm_ops->vv_flags; 154 155 ++ops->vv_refs; 156 TAILQ_INSERT_TAIL(&vnodeopv_list, node, entry); 157 158 vfs_recalc_vnodeops(); 159 160 if (mp) { 161 if (mp->mnt_vn_coherency_ops) 162 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 163 else if (mp->mnt_vn_journal_ops) 164 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 165 else 166 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 167 } 168 } 169 170 void 171 vfs_rm_vnodeops(struct vop_ops **vops_pp) 172 { 173 struct vop_ops *ops = *vops_pp; 174 struct vnodeopv_node *node; 175 struct mount *mp; 176 177 if (ops == NULL) 178 return; 179 180 TAILQ_FOREACH(node, &vnodeopv_list, entry) { 181 if (node->ops == ops) 182 break; 183 } 184 if (node == NULL) { 185 printf("vfs_rm_vnodeops: unable to find ops: %p\n", ops); 186 return; 187 } 188 TAILQ_REMOVE(&vnodeopv_list, node, entry); 189 free(node, M_VNODEOP); 190 KKASSERT(ops != NULL && ops->vv_refs > 0); 191 if (--ops->vv_refs == 0) { 192 *vops_pp = NULL; 193 if ((mp = ops->vv_mount) != NULL) { 194 if (mp->mnt_vn_coherency_ops) 195 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 196 else if (mp->mnt_vn_journal_ops) 197 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 198 else 199 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 200 } 201 free(ops, M_VNODEOP); 202 } 203 vfs_recalc_vnodeops(); 204 } 205 206 /* 207 * Recalculate VFS operations vectors 208 */ 209 static void 210 vfs_recalc_vnodeops(void) 211 { 212 struct vnodeopv_node *node; 213 struct vnodeopv_entry_desc *desc; 214 struct vop_ops *ops; 215 struct vop_ops *vnew; 216 int off; 217 218 /* 219 * Because vop_ops may be active we can't just blow them away, we 220 * have to generate new vop_ops and then copy them into the running 221 * vop_ops. Any missing entries will be assigned to the default 222 * entry. If the default entry itself is missing it will be assigned 223 * to vop_eopnotsupp. 224 */ 225 TAILQ_FOREACH(node, &vnodeopv_list, entry) { 226 ops = node->ops; 227 if ((vnew = ops->vv_new) == NULL) { 228 vnew = malloc(sizeof(struct vop_ops), 229 M_VNODEOP, M_ZERO|M_WAITOK); 230 ops->vv_new = vnew; 231 vnew->vop_default = vop_eopnotsupp; 232 } 233 for (desc = node->descs; desc->opve_op; ++desc) { 234 off = desc->opve_op->vdesc_offset; 235 *(void **)((char *)vnew + off) = desc->opve_func; 236 } 237 for (off = __offsetof(struct vop_ops, vop_ops_first_field); 238 off <= __offsetof(struct vop_ops, vop_ops_last_field); 239 off += sizeof(void **) 240 ) { 241 if (*(void **)((char *)vnew + off) == NULL) 242 *(void **)((char *)vnew + off) = vnew->vop_default; 243 } 244 } 245 246 /* 247 * Copy the temporary ops into the running configuration and then 248 * delete them. 249 */ 250 TAILQ_FOREACH(node, &vnodeopv_list, entry) { 251 ops = node->ops; 252 if ((vnew = ops->vv_new) == NULL) 253 continue; 254 for (off = __offsetof(struct vop_ops, vop_ops_first_field); 255 off <= __offsetof(struct vop_ops, vop_ops_last_field); 256 off += sizeof(void **) 257 ) { 258 *(void **)((char *)ops + off) = 259 *(void **)((char *)vnew + off); 260 } 261 ops->vv_new = NULL; 262 free(vnew, M_VNODEOP); 263 } 264 } 265 266 /* 267 * Routines having to do with the management of the vnode table. 268 */ 269 struct vattr va_null; 270 271 /* 272 * Initialize the vnode structures and initialize each file system type. 273 */ 274 /* ARGSUSED*/ 275 static void 276 vfsinit(void *dummy) 277 { 278 TAILQ_INIT(&vnodeopv_list); 279 namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN); 280 281 /* 282 * Initialize the vnode table 283 */ 284 vfs_subr_init(); 285 vfs_mount_init(); 286 vfs_lock_init(); 287 vfs_sync_init(); 288 /* 289 * Initialize the vnode name cache 290 */ 291 nchinit(); 292 /* 293 * Initialize each file system type. 294 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF). 295 */ 296 vattr_null(&va_null); 297 maxvfsconf = VFS_GENERIC + 1; 298 } 299 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 300 301 /* 302 * Register a VFS. 303 * 304 * After doing general initialisation, this function will 305 * call the filesystem specific initialisation vector op, 306 * i.e. vfsops->vfs_init(). 307 */ 308 int 309 vfs_register(struct vfsconf *vfc) 310 { 311 struct sysctl_oid *oidp; 312 struct vfsconf *vfsp; 313 struct vfsops *vfsops = NULL; 314 315 vfsp = NULL; 316 if (vfsconf) 317 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) 318 if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0) 319 return EEXIST; 320 321 vfc->vfc_typenum = maxvfsconf++; 322 if (vfsp) 323 vfsp->vfc_next = vfc; 324 else 325 vfsconf = vfc; 326 vfc->vfc_next = NULL; 327 328 /* 329 * If this filesystem has a sysctl node under vfs 330 * (i.e. vfs.xxfs), then change the oid number of that node to 331 * match the filesystem's type number. This allows user code 332 * which uses the type number to read sysctl variables defined 333 * by the filesystem to continue working. Since the oids are 334 * in a sorted list, we need to make sure the order is 335 * preserved by re-registering the oid after modifying its 336 * number. 337 */ 338 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 339 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 340 sysctl_unregister_oid(oidp); 341 oidp->oid_number = vfc->vfc_typenum; 342 sysctl_register_oid(oidp); 343 } 344 345 /* 346 * Initialise unused fields in the file system's vfsops vector. 347 * 348 * NOTE the file system should provide the mount and unmount ops 349 * at the least. In order for unmount to succeed, we also need 350 * the file system to provide us with vfsops->vfs_root otherwise 351 * the unmount(2) operation will not succeed. 352 */ 353 vfsops = vfc->vfc_vfsops; 354 KKASSERT(vfc->vfc_vfsops != NULL); 355 KKASSERT(vfsops->vfs_mount != NULL); 356 KKASSERT(vfsops->vfs_root != NULL); 357 KKASSERT(vfsops->vfs_unmount != NULL); 358 359 if (vfsops->vfs_root == NULL) { 360 /* return file system's root vnode */ 361 vfsops->vfs_root = vfs_stdroot; 362 } 363 if (vfsops->vfs_start == NULL) { 364 /* 365 * Make file system operational before first use. This 366 * routine is called at mount-time for initialising MFS, 367 * not used by other file systems. 368 */ 369 vfsops->vfs_start = vfs_stdstart; 370 } 371 if (vfsops->vfs_quotactl == NULL) { 372 /* quota control */ 373 vfsops->vfs_quotactl = vfs_stdquotactl; 374 } 375 if (vfsops->vfs_statfs == NULL) { 376 /* return file system's status */ 377 vfsops->vfs_statfs = vfs_stdstatfs; 378 } 379 if (vfsops->vfs_sync == NULL) { 380 /* 381 * Flush dirty buffers. File systems can use vfs_stdsync() 382 * by explicitly setting it in the vfsops->vfs_sync vector 383 * entry. 384 */ 385 vfsops->vfs_sync = vfs_stdnosync; 386 } 387 if (vfsops->vfs_vget == NULL) { 388 /* convert an inode number to a vnode */ 389 vfsops->vfs_vget = vfs_stdvget; 390 } 391 if (vfsops->vfs_fhtovp == NULL) { 392 /* turn an NFS file handle into a vnode */ 393 vfsops->vfs_fhtovp = vfs_stdfhtovp; 394 } 395 if (vfsops->vfs_checkexp == NULL) { 396 /* check if file system is exported */ 397 vfsops->vfs_checkexp = vfs_stdcheckexp; 398 } 399 if (vfsops->vfs_vptofh == NULL) { 400 /* turn a vnode into an NFS file handle */ 401 vfsops->vfs_vptofh = vfs_stdvptofh; 402 } 403 if (vfsops->vfs_init == NULL) { 404 /* file system specific initialisation */ 405 vfsops->vfs_init = vfs_stdinit; 406 } 407 if (vfsops->vfs_uninit == NULL) { 408 /* file system specific uninitialisation */ 409 vfsops->vfs_uninit = vfs_stduninit; 410 } 411 if (vfsops->vfs_extattrctl == NULL) { 412 /* extended attribute control */ 413 vfsops->vfs_extattrctl = vfs_stdextattrctl; 414 } 415 416 /* 417 * Call init function for this VFS... 418 */ 419 (*(vfc->vfc_vfsops->vfs_init))(vfc); 420 421 return 0; 422 } 423 424 425 /* 426 * Remove previously registered VFS. 427 * 428 * After doing general de-registration like removing sysctl 429 * nodes etc, it will call the filesystem specific vector 430 * op, i.e. vfsops->vfs_uninit(). 431 * 432 */ 433 int 434 vfs_unregister(struct vfsconf *vfc) 435 { 436 struct vfsconf *vfsp, *prev_vfsp; 437 int error, i, maxtypenum; 438 439 i = vfc->vfc_typenum; 440 441 prev_vfsp = NULL; 442 for (vfsp = vfsconf; vfsp; 443 prev_vfsp = vfsp, vfsp = vfsp->vfc_next) { 444 if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) 445 break; 446 } 447 if (vfsp == NULL) 448 return EINVAL; 449 if (vfsp->vfc_refcount) 450 return EBUSY; 451 if (vfc->vfc_vfsops->vfs_uninit != NULL) { 452 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 453 if (error) 454 return (error); 455 } 456 if (prev_vfsp) 457 prev_vfsp->vfc_next = vfsp->vfc_next; 458 else 459 vfsconf = vfsp->vfc_next; 460 maxtypenum = VFS_GENERIC; 461 for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next) 462 if (maxtypenum < vfsp->vfc_typenum) 463 maxtypenum = vfsp->vfc_typenum; 464 maxvfsconf = maxtypenum + 1; 465 return 0; 466 } 467 468 int 469 vfs_modevent(module_t mod, int type, void *data) 470 { 471 struct vfsconf *vfc; 472 int error = 0; 473 474 vfc = (struct vfsconf *)data; 475 476 switch (type) { 477 case MOD_LOAD: 478 if (vfc) 479 error = vfs_register(vfc); 480 break; 481 482 case MOD_UNLOAD: 483 if (vfc) 484 error = vfs_unregister(vfc); 485 break; 486 default: /* including MOD_SHUTDOWN */ 487 break; 488 } 489 return (error); 490 } 491