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 */ 70 /* 71 * Manage vnode VOP operations vectors 72 */ 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/kernel.h> 76 #include <sys/mount.h> 77 #include <sys/sysctl.h> 78 #include <sys/vnode.h> 79 #include <sys/malloc.h> 80 #include <sys/objcache.h> 81 82 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors"); 83 static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers"); 84 85 /* 86 * Zone for namei 87 */ 88 struct objcache *namei_oc; 89 90 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list; 91 static void vfs_calc_vnodeops(struct vop_ops *ops); 92 93 94 /* 95 * Add a vnode operations (vnops) vector to the global list. 96 */ 97 void 98 vfs_nadd_vnodeops_sysinit(void *data) 99 { 100 struct vop_ops *ops = data; 101 102 vfs_add_vnodeops(NULL, ops, NULL); /* mount, template, newcopy */ 103 } 104 105 /* 106 * Unlink previously added vnode operations vector. 107 */ 108 void 109 vfs_nrm_vnodeops_sysinit(void *data) 110 { 111 struct vop_ops *ops = data; 112 113 vfs_rm_vnodeops(NULL, ops, NULL); 114 } 115 116 void 117 vfs_add_vnodeops(struct mount *mp, struct vop_ops *template, 118 struct vop_ops **ops_pp) 119 { 120 struct vop_ops *ops; 121 122 if (ops_pp) { 123 KKASSERT(*ops_pp == NULL); 124 *ops_pp = kmalloc(sizeof(*ops), M_VNODEOP, M_WAITOK); 125 ops = *ops_pp; 126 bcopy(template, ops, sizeof(*ops)); 127 } else { 128 ops = template; 129 } 130 131 vfs_calc_vnodeops(ops); 132 ops->head.vv_mount = mp; 133 134 if (mp) { 135 if (mp->mnt_vn_coherency_ops) 136 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 137 else if (mp->mnt_vn_journal_ops) 138 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 139 else 140 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 141 } 142 } 143 144 /* 145 * Remove a previously installed operations vector. 146 * 147 * NOTE: Either template or ops_pp may be NULL, but not both. 148 */ 149 void 150 vfs_rm_vnodeops(struct mount *mp, struct vop_ops *template, 151 struct vop_ops **ops_pp) 152 { 153 struct vop_ops *ops; 154 155 if (ops_pp) { 156 ops = *ops_pp; 157 *ops_pp = NULL; 158 } else { 159 ops = template; 160 } 161 if (ops == NULL) 162 return; 163 KKASSERT(mp == ops->head.vv_mount); 164 if (mp) { 165 if (mp->mnt_vn_coherency_ops) 166 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 167 else if (mp->mnt_vn_journal_ops) 168 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 169 else 170 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 171 } 172 if (ops_pp) 173 kfree(ops, M_VNODEOP); 174 } 175 176 /* 177 * Calculate the VFS operations vector array. This function basically 178 * replaces any NULL entry with the default entry. 179 */ 180 static void 181 vfs_calc_vnodeops(struct vop_ops *ops) 182 { 183 int off; 184 185 for (off = __offsetof(struct vop_ops, vop_ops_first_field); 186 off <= __offsetof(struct vop_ops, vop_ops_last_field); 187 off += sizeof(void *) 188 ) { 189 if (*(void **)((char *)ops + off) == NULL) 190 *(void **)((char *)ops + off) = ops->vop_default; 191 } 192 } 193 194 /* 195 * Routines having to do with the management of the vnode table. 196 */ 197 struct vattr va_null; 198 199 /* 200 * Initialize the vnode structures and initialize each file system type. 201 */ 202 /* ARGSUSED*/ 203 static void 204 vfsinit(void *dummy) 205 { 206 TAILQ_INIT(&vnodeopv_list); 207 namei_oc = objcache_create_simple(M_NAMEI, MAXPATHLEN); 208 209 /* 210 * Initialize the vnode table 211 */ 212 vfs_subr_init(); 213 vfs_mount_init(); 214 vfs_lock_init(); 215 216 /* 217 * Initialize the vnode name cache 218 */ 219 nchinit(); 220 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