1 /* $NetBSD: vfs_init.c,v 1.37 2008/01/16 12:34:51 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1989, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This code is derived from software contributed 45 * to Berkeley by John Heidemann of the UCLA Ficus project. 46 * 47 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 48 * 49 * Redistribution and use in source and binary forms, with or without 50 * modification, are permitted provided that the following conditions 51 * are met: 52 * 1. Redistributions of source code must retain the above copyright 53 * notice, this list of conditions and the following disclaimer. 54 * 2. Redistributions in binary form must reproduce the above copyright 55 * notice, this list of conditions and the following disclaimer in the 56 * documentation and/or other materials provided with the distribution. 57 * 3. Neither the name of the University nor the names of its contributors 58 * may be used to endorse or promote products derived from this software 59 * without specific prior written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 71 * SUCH DAMAGE. 72 * 73 * @(#)vfs_init.c 8.5 (Berkeley) 5/11/95 74 */ 75 76 #include <sys/cdefs.h> 77 __KERNEL_RCSID(0, "$NetBSD: vfs_init.c,v 1.37 2008/01/16 12:34:51 ad Exp $"); 78 79 #include <sys/param.h> 80 #include <sys/mount.h> 81 #include <sys/time.h> 82 #include <sys/vnode.h> 83 #include <sys/stat.h> 84 #include <sys/namei.h> 85 #include <sys/ucred.h> 86 #include <sys/buf.h> 87 #include <sys/errno.h> 88 #include <sys/malloc.h> 89 #include <sys/systm.h> 90 #include <sys/module.h> 91 92 /* 93 * Sigh, such primitive tools are these... 94 */ 95 #if 0 96 #define DODEBUG(A) A 97 #else 98 #define DODEBUG(A) 99 #endif 100 101 /* 102 * The global list of vnode operations. 103 */ 104 extern const struct vnodeop_desc * const vfs_op_descs[]; 105 106 /* 107 * These vnodeopv_descs are listed here because they are not 108 * associated with any particular file system, and thus cannot 109 * be initialized by vfs_attach(). 110 */ 111 extern const struct vnodeopv_desc dead_vnodeop_opv_desc; 112 extern const struct vnodeopv_desc fifo_vnodeop_opv_desc; 113 extern const struct vnodeopv_desc spec_vnodeop_opv_desc; 114 extern const struct vnodeopv_desc sync_vnodeop_opv_desc; 115 116 const struct vnodeopv_desc * const vfs_special_vnodeopv_descs[] = { 117 &dead_vnodeop_opv_desc, 118 &fifo_vnodeop_opv_desc, 119 &spec_vnodeop_opv_desc, 120 &sync_vnodeop_opv_desc, 121 NULL, 122 }; 123 124 struct vfs_list_head vfs_list = /* vfs list */ 125 LIST_HEAD_INITIALIZER(vfs_list); 126 127 /* 128 * This code doesn't work if the defn is **vnodop_defns with cc. 129 * The problem is because of the compiler sometimes putting in an 130 * extra level of indirection for arrays. It's an interesting 131 * "feature" of C. 132 */ 133 typedef int (*PFI)(void *); 134 135 /* 136 * A miscellaneous routine. 137 * A generic "default" routine that just returns an error. 138 */ 139 /*ARGSUSED*/ 140 int 141 vn_default_error(void *v) 142 { 143 144 return (EOPNOTSUPP); 145 } 146 147 /* 148 * vfs_init.c 149 * 150 * Allocate and fill in operations vectors. 151 * 152 * An undocumented feature of this approach to defining operations is that 153 * there can be multiple entries in vfs_opv_descs for the same operations 154 * vector. This allows third parties to extend the set of operations 155 * supported by another layer in a binary compatibile way. For example, 156 * assume that NFS needed to be modified to support Ficus. NFS has an entry 157 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 158 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 159 * listing those new operations Ficus adds to NFS, all without modifying the 160 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 161 * that is a(whole)nother story.) This is a feature. 162 */ 163 164 /* 165 * Init the vector, if it needs it. 166 * Also handle backwards compatibility. 167 */ 168 static void 169 vfs_opv_init_explicit(const struct vnodeopv_desc *vfs_opv_desc) 170 { 171 int (**opv_desc_vector)(void *); 172 const struct vnodeopv_entry_desc *opve_descp; 173 174 opv_desc_vector = *(vfs_opv_desc->opv_desc_vector_p); 175 176 for (opve_descp = vfs_opv_desc->opv_desc_ops; 177 opve_descp->opve_op; 178 opve_descp++) { 179 /* 180 * Sanity check: is this operation listed 181 * in the list of operations? We check this 182 * by seeing if its offset is zero. Since 183 * the default routine should always be listed 184 * first, it should be the only one with a zero 185 * offset. Any other operation with a zero 186 * offset is probably not listed in 187 * vfs_op_descs, and so is probably an error. 188 * 189 * A panic here means the layer programmer 190 * has committed the all-too common bug 191 * of adding a new operation to the layer's 192 * list of vnode operations but 193 * not adding the operation to the system-wide 194 * list of supported operations. 195 */ 196 if (opve_descp->opve_op->vdesc_offset == 0 && 197 opve_descp->opve_op->vdesc_offset != VOFFSET(vop_default)) { 198 printf("operation %s not listed in %s.\n", 199 opve_descp->opve_op->vdesc_name, "vfs_op_descs"); 200 panic ("vfs_opv_init: bad operation"); 201 } 202 203 /* 204 * Fill in this entry. 205 */ 206 opv_desc_vector[opve_descp->opve_op->vdesc_offset] = 207 opve_descp->opve_impl; 208 } 209 } 210 211 static void 212 vfs_opv_init_default(const struct vnodeopv_desc *vfs_opv_desc) 213 { 214 int j; 215 int (**opv_desc_vector)(void *); 216 217 opv_desc_vector = *(vfs_opv_desc->opv_desc_vector_p); 218 219 /* 220 * Force every operations vector to have a default routine. 221 */ 222 if (opv_desc_vector[VOFFSET(vop_default)] == NULL) 223 panic("vfs_opv_init: operation vector without default routine."); 224 225 for (j = 0; j < VNODE_OPS_COUNT; j++) 226 if (opv_desc_vector[j] == NULL) 227 opv_desc_vector[j] = 228 opv_desc_vector[VOFFSET(vop_default)]; 229 } 230 231 void 232 vfs_opv_init(const struct vnodeopv_desc * const *vopvdpp) 233 { 234 int (**opv_desc_vector)(void *); 235 int i; 236 237 /* 238 * Allocate the vectors. 239 */ 240 for (i = 0; vopvdpp[i] != NULL; i++) { 241 /* XXX - shouldn't be M_VNODE */ 242 opv_desc_vector = 243 malloc(VNODE_OPS_COUNT * sizeof(PFI), M_VNODE, M_WAITOK); 244 memset(opv_desc_vector, 0, VNODE_OPS_COUNT * sizeof(PFI)); 245 *(vopvdpp[i]->opv_desc_vector_p) = opv_desc_vector; 246 DODEBUG(printf("vector at %p allocated\n", 247 opv_desc_vector_p)); 248 } 249 250 /* 251 * ...and fill them in. 252 */ 253 for (i = 0; vopvdpp[i] != NULL; i++) 254 vfs_opv_init_explicit(vopvdpp[i]); 255 256 /* 257 * Finally, go back and replace unfilled routines 258 * with their default. 259 */ 260 for (i = 0; vopvdpp[i] != NULL; i++) 261 vfs_opv_init_default(vopvdpp[i]); 262 } 263 264 void 265 vfs_opv_free(const struct vnodeopv_desc * const *vopvdpp) 266 { 267 int i; 268 269 /* 270 * Free the vectors allocated in vfs_opv_init(). 271 */ 272 for (i = 0; vopvdpp[i] != NULL; i++) { 273 /* XXX - shouldn't be M_VNODE */ 274 free(*(vopvdpp[i]->opv_desc_vector_p), M_VNODE); 275 *(vopvdpp[i]->opv_desc_vector_p) = NULL; 276 } 277 } 278 279 #ifdef DEBUG 280 static void 281 vfs_op_check(void) 282 { 283 int i; 284 285 DODEBUG(printf("Vnode_interface_init.\n")); 286 287 /* 288 * Check offset of each op. 289 */ 290 for (i = 0; vfs_op_descs[i]; i++) { 291 if (vfs_op_descs[i]->vdesc_offset != i) 292 panic("vfs_op_check: vfs_op_desc[] offset mismatch"); 293 } 294 295 if (i != VNODE_OPS_COUNT) { 296 panic("vfs_op_check: vnode ops count mismatch (%d != %d)", 297 i, VNODE_OPS_COUNT); 298 } 299 300 DODEBUG(printf ("vfs_opv_numops=%d\n", VNODE_OPS_COUNT)); 301 } 302 #endif /* DEBUG */ 303 304 /* 305 * Initialize the vnode structures and initialize each file system type. 306 */ 307 void 308 vfsinit(void) 309 { 310 __link_set_decl(vfsops, struct vfsops); 311 struct vfsops * const *vfsp; 312 313 /* 314 * Initialize the namei pathname buffer pool and cache. 315 */ 316 pnbuf_cache = pool_cache_init(MAXPATHLEN, 0, 0, 0, "pnbufpl", 317 NULL, IPL_NONE, NULL, NULL, NULL); 318 KASSERT(pnbuf_cache != NULL); 319 320 /* 321 * Initialize the vnode table 322 */ 323 vntblinit(); 324 325 /* 326 * Initialize the vnode name cache 327 */ 328 nchinit(); 329 330 #ifdef DEBUG 331 /* 332 * Check the list of vnode operations. 333 */ 334 vfs_op_check(); 335 #endif 336 337 /* 338 * Initialize the special vnode operations. 339 */ 340 vfs_opv_init(vfs_special_vnodeopv_descs); 341 342 /* 343 * Establish each file system which was statically 344 * included in the kernel. 345 */ 346 module_init_class(MODULE_CLASS_VFS); 347 __link_set_foreach(vfsp, vfsops) { 348 if (vfs_attach(*vfsp)) { 349 printf("multiple `%s' file systems", 350 (*vfsp)->vfs_name); 351 panic("vfsinit"); 352 } 353 } 354 } 355 356 /* 357 * Drop a reference to a file system type. 358 */ 359 void 360 vfs_delref(struct vfsops *vfs) 361 { 362 363 mutex_enter(&vfs_list_lock); 364 vfs->vfs_refcount--; 365 mutex_exit(&vfs_list_lock); 366 } 367 368 /* 369 * Establish a file system and initialize it. 370 */ 371 int 372 vfs_attach(struct vfsops *vfs) 373 { 374 struct vfsops *v; 375 int error = 0; 376 377 mutex_enter(&vfs_list_lock); 378 379 /* 380 * Make sure this file system doesn't already exist. 381 */ 382 LIST_FOREACH(v, &vfs_list, vfs_list) { 383 if (strcmp(vfs->vfs_name, v->vfs_name) == 0) { 384 error = EEXIST; 385 goto out; 386 } 387 } 388 389 /* 390 * Initialize the vnode operations for this file system. 391 */ 392 vfs_opv_init(vfs->vfs_opv_descs); 393 394 /* 395 * Now initialize the file system itself. 396 */ 397 (*vfs->vfs_init)(); 398 399 /* 400 * ...and link it into the kernel's list. 401 */ 402 LIST_INSERT_HEAD(&vfs_list, vfs, vfs_list); 403 404 /* 405 * Sanity: make sure the reference count is 0. 406 */ 407 vfs->vfs_refcount = 0; 408 out: 409 mutex_exit(&vfs_list_lock); 410 return (error); 411 } 412 413 /* 414 * Remove a file system from the kernel. 415 */ 416 int 417 vfs_detach(struct vfsops *vfs) 418 { 419 struct vfsops *v; 420 int error = 0; 421 422 mutex_enter(&vfs_list_lock); 423 424 /* 425 * Make sure no one is using the filesystem. 426 */ 427 if (vfs->vfs_refcount != 0) { 428 error = EBUSY; 429 goto out; 430 } 431 432 /* 433 * ...and remove it from the kernel's list. 434 */ 435 LIST_FOREACH(v, &vfs_list, vfs_list) { 436 if (v == vfs) { 437 LIST_REMOVE(v, vfs_list); 438 break; 439 } 440 } 441 442 if (v == NULL) { 443 error = ESRCH; 444 goto out; 445 } 446 447 /* 448 * Now run the file system-specific cleanups. 449 */ 450 (*vfs->vfs_done)(); 451 452 /* 453 * Free the vnode operations vector. 454 */ 455 vfs_opv_free(vfs->vfs_opv_descs); 456 out: 457 mutex_exit(&vfs_list_lock); 458 return (error); 459 } 460 461 void 462 vfs_reinit(void) 463 { 464 struct vfsops *vfs; 465 466 mutex_enter(&vfs_list_lock); 467 LIST_FOREACH(vfs, &vfs_list, vfs_list) { 468 if (vfs->vfs_reinit) { 469 vfs->vfs_refcount++; 470 mutex_exit(&vfs_list_lock); 471 (*vfs->vfs_reinit)(); 472 mutex_enter(&vfs_list_lock); 473 vfs->vfs_refcount--; 474 } 475 } 476 mutex_exit(&vfs_list_lock); 477 } 478