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