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 217 /* 218 * Initialize the vnode name cache 219 */ 220 nchinit(); 221 222 /* 223 * Initialize each file system type. 224 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF). 225 */ 226 vattr_null(&va_null); 227 } 228 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 229 230 /* 231 * vfsconf related functions/data. 232 */ 233 234 /* highest defined filesystem type */ 235 static int vfsconf_maxtypenum = VFS_GENERIC + 1; 236 237 /* head of list of filesystem types */ 238 static STAILQ_HEAD(, vfsconf) vfsconf_list = 239 STAILQ_HEAD_INITIALIZER(vfsconf_list); 240 241 struct vfsconf * 242 vfsconf_find_by_name(const char *name) 243 { 244 struct vfsconf *vfsp; 245 246 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) { 247 if (strcmp(name, vfsp->vfc_name) == 0) 248 break; 249 } 250 return vfsp; 251 } 252 253 struct vfsconf * 254 vfsconf_find_by_typenum(int typenum) 255 { 256 struct vfsconf *vfsp; 257 258 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) { 259 if (typenum == vfsp->vfc_typenum) 260 break; 261 } 262 return vfsp; 263 } 264 265 static void 266 vfsconf_add(struct vfsconf *vfc) 267 { 268 vfc->vfc_typenum = vfsconf_maxtypenum++; 269 STAILQ_INSERT_TAIL(&vfsconf_list, vfc, vfc_next); 270 } 271 272 static void 273 vfsconf_remove(struct vfsconf *vfc) 274 { 275 int maxtypenum; 276 277 STAILQ_REMOVE(&vfsconf_list, vfc, vfsconf, vfc_next); 278 279 maxtypenum = VFS_GENERIC; 280 STAILQ_FOREACH(vfc, &vfsconf_list, vfc_next) { 281 if (maxtypenum < vfc->vfc_typenum) 282 maxtypenum = vfc->vfc_typenum; 283 } 284 vfsconf_maxtypenum = maxtypenum + 1; 285 } 286 287 int 288 vfsconf_get_maxtypenum(void) 289 { 290 return vfsconf_maxtypenum; 291 } 292 293 /* 294 * Iterate over all vfsconf entries. Break out of the iterator 295 * by returning != 0. 296 */ 297 int 298 vfsconf_each(int (*iter)(struct vfsconf *element, void *data), void *data) 299 { 300 int error; 301 struct vfsconf *vfsp; 302 303 STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) { 304 error = iter(vfsp, data); 305 if (error) 306 return (error); 307 } 308 return (0); 309 } 310 311 /* 312 * Register a VFS. 313 * 314 * After doing general initialisation, this function will 315 * call the filesystem specific initialisation vector op, 316 * i.e. vfsops->vfs_init(). 317 */ 318 int 319 vfs_register(struct vfsconf *vfc) 320 { 321 struct sysctl_oid *oidp; 322 struct vfsops *vfsops = NULL; 323 324 if (vfsconf_find_by_name(vfc->vfc_name) != NULL) 325 return EEXIST; 326 327 vfsconf_add(vfc); 328 329 /* 330 * If this filesystem has a sysctl node under vfs 331 * (i.e. vfs.xxfs), then change the oid number of that node to 332 * match the filesystem's type number. This allows user code 333 * which uses the type number to read sysctl variables defined 334 * by the filesystem to continue working. Since the oids are 335 * in a sorted list, we need to make sure the order is 336 * preserved by re-registering the oid after modifying its 337 * number. 338 */ 339 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 340 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 341 sysctl_unregister_oid(oidp); 342 oidp->oid_number = vfc->vfc_typenum; 343 sysctl_register_oid(oidp); 344 } 345 346 /* 347 * Initialise unused fields in the file system's vfsops vector. 348 * 349 * NOTE the file system should provide the mount and unmount ops 350 * at the least. In order for unmount to succeed, we also need 351 * the file system to provide us with vfsops->vfs_root otherwise 352 * the unmount(2) operation will not succeed. 353 */ 354 vfsops = vfc->vfc_vfsops; 355 KKASSERT(vfc->vfc_vfsops != NULL); 356 KKASSERT(vfsops->vfs_mount != NULL); 357 KKASSERT(vfsops->vfs_root != NULL); 358 KKASSERT(vfsops->vfs_unmount != NULL); 359 360 if (vfsops->vfs_root == NULL) { 361 /* return file system's root vnode */ 362 vfsops->vfs_root = vfs_stdroot; 363 } 364 if (vfsops->vfs_start == NULL) { 365 /* 366 * Make file system operational before first use. This 367 * routine is called at mount-time for initialising MFS, 368 * not used by other file systems. 369 */ 370 vfsops->vfs_start = vfs_stdstart; 371 } 372 if (vfsops->vfs_quotactl == NULL) { 373 /* quota control */ 374 vfsops->vfs_quotactl = vfs_stdquotactl; 375 } 376 if (vfsops->vfs_statfs == NULL) { 377 /* return file system's status */ 378 vfsops->vfs_statfs = vfs_stdstatfs; 379 } 380 if (vfsops->vfs_statvfs == NULL) { 381 /* return file system's status */ 382 vfsops->vfs_statvfs = vfs_stdstatvfs; 383 } 384 if (vfsops->vfs_sync == NULL) { 385 /* 386 * Flush dirty buffers. File systems can use vfs_stdsync() 387 * by explicitly setting it in the vfsops->vfs_sync vector 388 * entry. 389 */ 390 vfsops->vfs_sync = vfs_stdnosync; 391 } 392 if (vfsops->vfs_vget == NULL) { 393 /* convert an inode number to a vnode */ 394 vfsops->vfs_vget = vfs_stdvget; 395 } 396 if (vfsops->vfs_fhtovp == NULL) { 397 /* turn an NFS file handle into a vnode */ 398 vfsops->vfs_fhtovp = vfs_stdfhtovp; 399 } 400 if (vfsops->vfs_checkexp == NULL) { 401 /* check if file system is exported */ 402 vfsops->vfs_checkexp = vfs_stdcheckexp; 403 } 404 if (vfsops->vfs_vptofh == NULL) { 405 /* turn a vnode into an NFS file handle */ 406 vfsops->vfs_vptofh = vfs_stdvptofh; 407 } 408 if (vfsops->vfs_init == NULL) { 409 /* file system specific initialisation */ 410 vfsops->vfs_init = vfs_stdinit; 411 } 412 if (vfsops->vfs_uninit == NULL) { 413 /* file system specific uninitialisation */ 414 vfsops->vfs_uninit = vfs_stduninit; 415 } 416 if (vfsops->vfs_extattrctl == NULL) { 417 /* extended attribute control */ 418 vfsops->vfs_extattrctl = vfs_stdextattrctl; 419 } 420 421 if (vfsops->vfs_ncpgen_set == NULL) { 422 /* namecache generation number */ 423 vfsops->vfs_ncpgen_set = vfs_stdncpgen_set; 424 } 425 426 if (vfsops->vfs_ncpgen_test == NULL) { 427 /* check namecache generation */ 428 vfsops->vfs_ncpgen_test = vfs_stdncpgen_test; 429 } 430 431 /* VFS quota uid and gid accounting */ 432 if (vfs_quota_enabled && vfsops->vfs_acinit == NULL) { 433 vfsops->vfs_acinit = vfs_stdac_init; 434 } 435 if (vfs_quota_enabled && vfsops->vfs_acdone == NULL) { 436 vfsops->vfs_acdone = vfs_stdac_done; 437 } 438 439 /* 440 * Call init function for this VFS... 441 */ 442 vfs_init(vfc); 443 return 0; 444 } 445 446 447 /* 448 * Remove previously registered VFS. 449 * 450 * After doing general de-registration like removing sysctl 451 * nodes etc, it will call the filesystem specific vector 452 * op, i.e. vfsops->vfs_uninit(). 453 * 454 */ 455 int 456 vfs_unregister(struct vfsconf *vfc) 457 { 458 struct vfsconf *vfsp; 459 int error; 460 461 vfsp = vfsconf_find_by_name(vfc->vfc_name); 462 463 if (vfsp == NULL) 464 return EINVAL; 465 466 if (vfsp->vfc_refcount != 0) 467 return EBUSY; 468 469 if (vfc->vfc_vfsops->vfs_uninit != NULL) { 470 error = vfs_uninit(vfc, vfsp); 471 if (error) 472 return (error); 473 } 474 475 vfsconf_remove(vfsp); 476 return 0; 477 } 478 479 int 480 vfs_modevent(module_t mod, int type, void *data) 481 { 482 struct vfsconf *vfc; 483 int error = 0; 484 485 vfc = (struct vfsconf *)data; 486 487 switch (type) { 488 case MOD_LOAD: 489 if (vfc) 490 error = vfs_register(vfc); 491 break; 492 493 case MOD_UNLOAD: 494 if (vfc) 495 error = vfs_unregister(vfc); 496 break; 497 default: /* including MOD_SHUTDOWN */ 498 break; 499 } 500 return (error); 501 } 502