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. Neither the name of the University nor the names of its contributors 52 * may be used to endorse or promote products derived from this software 53 * without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 * 67 * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 68 * $FreeBSD: src/sys/kern/vfs_init.c,v 1.59 2002/04/30 18:44:32 dillon Exp $ 69 * $DragonFly: src/sys/kern/vfs_init.c,v 1.15 2008/06/01 19:27:35 dillon Exp $ 70 */ 71 /* 72 * Manage vnode VOP operations vectors 73 */ 74 #include <sys/param.h> 75 #include <sys/systm.h> 76 #include <sys/kernel.h> 77 #include <sys/mount.h> 78 #include <sys/sysctl.h> 79 #include <sys/vnode.h> 80 #include <sys/malloc.h> 81 #include <sys/objcache.h> 82 83 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors"); 84 static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers"); 85 86 /* 87 * Zone for namei 88 */ 89 struct objcache *namei_oc; 90 91 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list; 92 static void vfs_calc_vnodeops(struct vop_ops *ops); 93 94 95 /* 96 * Add a vnode operations (vnops) vector to the global list. 97 */ 98 void 99 vfs_nadd_vnodeops_sysinit(void *data) 100 { 101 struct vop_ops *ops = data; 102 103 vfs_add_vnodeops(NULL, ops, NULL); /* mount, template, newcopy */ 104 } 105 106 /* 107 * Unlink previously added vnode operations vector. 108 */ 109 void 110 vfs_nrm_vnodeops_sysinit(void *data) 111 { 112 struct vop_ops *ops = data; 113 114 vfs_rm_vnodeops(NULL, ops, NULL); 115 } 116 117 void 118 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template, 119 struct vop_ops **ops_pp) 120 { 121 struct vop_ops *ops; 122 123 if (ops_pp) { 124 KKASSERT(*ops_pp == NULL); 125 *ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK); 126 ops = *ops_pp; 127 bcopy(template, ops, sizeof(*ops)); 128 } else { 129 ops = template; 130 } 131 132 vfs_calc_vnodeops(ops); 133 ops->head.vv_mount = mp; 134 135 if (mp) { 136 if (mp->mnt_vn_coherency_ops) 137 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 138 else if (mp->mnt_vn_journal_ops) 139 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 140 else 141 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 142 } 143 } 144 145 /* 146 * Remove a previously installed operations vector. 147 * 148 * NOTE: Either template or ops_pp may be NULL, but not both. 149 */ 150 void 151 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template, 152 struct vop_ops **ops_pp) 153 { 154 struct vop_ops *ops; 155 156 if (ops_pp) { 157 ops = *ops_pp; 158 *ops_pp = NULL; 159 } else { 160 ops = template; 161 } 162 if (ops == NULL) 163 return; 164 KKASSERT(mp == ops->head.vv_mount); 165 if (mp) { 166 if (mp->mnt_vn_coherency_ops) 167 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 168 else if (mp->mnt_vn_journal_ops) 169 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 170 else 171 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 172 } 173 if (ops_pp) 174 kfree(ops, M_VNODEOP); 175 } 176 177 /* 178 * Calculate the VFS operations vector array. This function basically 179 * replaces any NULL entry with the default entry. 180 */ 181 static void 182 vfs_calc_vnodeops(struct vop_ops *ops) 183 { 184 int off; 185 186 for (off = __offsetof(struct vop_ops, vop_ops_first_field); 187 off <= __offsetof(struct vop_ops, vop_ops_last_field); 188 off += sizeof(void *) 189 ) { 190 if (*(void **)((char *)ops + off) == NULL) 191 *(void **)((char *)ops + off) = ops->vop_default; 192 } 193 } 194 195 /* 196 * Routines having to do with the management of the vnode table. 197 */ 198 struct vattr va_null; 199 200 /* 201 * Initialize the vnode structures and initialize each file system type. 202 */ 203 /* ARGSUSED*/ 204 static void 205 vfsinit(void *dummy) 206 { 207 TAILQ_INIT(&vnodeopv_list); 208 namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN); 209 210 /* 211 * Initialize the vnode table 212 */ 213 vfs_subr_init(); 214 vfs_mount_init(); 215 vfs_lock_init(); 216 vfs_sync_init(); 217 /* 218 * Initialize the vnode name cache 219 */ 220 nchinit(); 221 /* 222 * Initialize each file system type. 223 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF). 224 */ 225 vattr_null(&va_null); 226 } 227 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 228 229 /* 230 * vfsconf related functions/data. 231 */ 232 233 /* highest defined filesystem type */ 234 static int vfsconf_maxtypenum = VFS_GENERIC + 1; 235 236 /* head of list of filesystem types */ 237 static STAILQ_HEAD(, vfsconf) vfsconf_list = 238 STAILQ_HEAD_INITIALIZER(vfsconf_list); 239 240 struct vfsconf * 241 vfsconf_find_by_name(const char *name) 242 { 243 struct vfsconf *vfsp; 244 245 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) { 246 if (strcmp(name, vfsp->vfc_name) == 0) 247 break; 248 } 249 return vfsp; 250 } 251 252 struct vfsconf * 253 vfsconf_find_by_typenum(int typenum) 254 { 255 struct vfsconf *vfsp; 256 257 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) { 258 if (typenum == vfsp->vfc_typenum) 259 break; 260 } 261 return vfsp; 262 } 263 264 static void 265 vfsconf_add(struct vfsconf *vfc) 266 { 267 vfc->vfc_typenum = vfsconf_maxtypenum++; 268 STAILQ_INSERT_TAIL(&vfsconf_list, vfc, vfc_next); 269 } 270 271 static void 272 vfsconf_remove(struct vfsconf *vfc) 273 { 274 int maxtypenum; 275 276 STAILQ_REMOVE(&vfsconf_list, vfc, vfsconf, vfc_next); 277 278 maxtypenum = VFS_GENERIC; 279 STAILQ_FOREACH(vfc, &vfsconf_list, vfc_next) { 280 if (maxtypenum < vfc->vfc_typenum) 281 maxtypenum = vfc->vfc_typenum; 282 } 283 vfsconf_maxtypenum = maxtypenum + 1; 284 } 285 286 int 287 vfsconf_get_maxtypenum(void) 288 { 289 return vfsconf_maxtypenum; 290 } 291 292 /* 293 * Iterate over all vfsconf entries. Break out of the iterator 294 * by returning != 0. 295 */ 296 int 297 vfsconf_each(int (*iter)(struct vfsconf *element, void *data), void *data) 298 { 299 int error; 300 struct vfsconf *vfsp; 301 302 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) { 303 error = iter(vfsp, data); 304 if (error) 305 return (error); 306 } 307 return (0); 308 } 309 310 /* 311 * Register a VFS. 312 * 313 * After doing general initialisation, this function will 314 * call the filesystem specific initialisation vector op, 315 * i.e. vfsops->vfs_init(). 316 */ 317 int 318 vfs_register(struct vfsconf *vfc) 319 { 320 struct sysctl_oid *oidp; 321 struct vfsops *vfsops = NULL; 322 323 if (vfsconf_find_by_name(vfc->vfc_name) != NULL) 324 return EEXIST; 325 326 vfsconf_add(vfc); 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_statvfs == NULL) { 380 /* return file system's status */ 381 vfsops->vfs_statvfs = vfs_stdstatvfs; 382 } 383 if (vfsops->vfs_sync == NULL) { 384 /* 385 * Flush dirty buffers. File systems can use vfs_stdsync() 386 * by explicitly setting it in the vfsops->vfs_sync vector 387 * entry. 388 */ 389 vfsops->vfs_sync = vfs_stdnosync; 390 } 391 if (vfsops->vfs_vget == NULL) { 392 /* convert an inode number to a vnode */ 393 vfsops->vfs_vget = vfs_stdvget; 394 } 395 if (vfsops->vfs_fhtovp == NULL) { 396 /* turn an NFS file handle into a vnode */ 397 vfsops->vfs_fhtovp = vfs_stdfhtovp; 398 } 399 if (vfsops->vfs_checkexp == NULL) { 400 /* check if file system is exported */ 401 vfsops->vfs_checkexp = vfs_stdcheckexp; 402 } 403 if (vfsops->vfs_vptofh == NULL) { 404 /* turn a vnode into an NFS file handle */ 405 vfsops->vfs_vptofh = vfs_stdvptofh; 406 } 407 if (vfsops->vfs_init == NULL) { 408 /* file system specific initialisation */ 409 vfsops->vfs_init = vfs_stdinit; 410 } 411 if (vfsops->vfs_uninit == NULL) { 412 /* file system specific uninitialisation */ 413 vfsops->vfs_uninit = vfs_stduninit; 414 } 415 if (vfsops->vfs_extattrctl == NULL) { 416 /* extended attribute control */ 417 vfsops->vfs_extattrctl = vfs_stdextattrctl; 418 } 419 420 if (vfsops->vfs_ncpgen_set == NULL) { 421 /* namecache generation number */ 422 vfsops->vfs_ncpgen_set = vfs_stdncpgen_set; 423 } 424 425 if (vfsops->vfs_ncpgen_test == NULL) { 426 /* check namecache generation */ 427 vfsops->vfs_ncpgen_test = vfs_stdncpgen_test; 428 } 429 430 /* VFS quota uid and gid accounting */ 431 if (vfs_quota_enabled && vfsops->vfs_acinit == NULL) { 432 vfsops->vfs_acinit = vfs_stdac_init; 433 } 434 if (vfs_quota_enabled && vfsops->vfs_acdone == NULL) { 435 vfsops->vfs_acdone = vfs_stdac_done; 436 } 437 438 /* 439 * Call init function for this VFS... 440 */ 441 vfs_init(vfc); 442 return 0; 443 } 444 445 446 /* 447 * Remove previously registered VFS. 448 * 449 * After doing general de-registration like removing sysctl 450 * nodes etc, it will call the filesystem specific vector 451 * op, i.e. vfsops->vfs_uninit(). 452 * 453 */ 454 int 455 vfs_unregister(struct vfsconf *vfc) 456 { 457 struct vfsconf *vfsp; 458 int error; 459 460 vfsp = vfsconf_find_by_name(vfc->vfc_name); 461 462 if (vfsp == NULL) 463 return EINVAL; 464 465 if (vfsp->vfc_refcount != 0) 466 return EBUSY; 467 468 if (vfc->vfc_vfsops->vfs_uninit != NULL) { 469 error = vfs_uninit(vfc, vfsp); 470 if (error) 471 return (error); 472 } 473 474 vfsconf_remove(vfsp); 475 return 0; 476 } 477 478 int 479 vfs_modevent(module_t mod, int type, void *data) 480 { 481 struct vfsconf *vfc; 482 int error = 0; 483 484 vfc = (struct vfsconf *)data; 485 486 switch (type) { 487 case MOD_LOAD: 488 if (vfc) 489 error = vfs_register(vfc); 490 break; 491 492 case MOD_UNLOAD: 493 if (vfc) 494 error = vfs_unregister(vfc); 495 break; 496 default: /* including MOD_SHUTDOWN */ 497 break; 498 } 499 return (error); 500 } 501