vfs_init.c revision 93170
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed 6 * to Berkeley by John Heidemann of the UCLA Ficus project. 7 * 8 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 39 * $FreeBSD: head/sys/kern/vfs_init.c 93170 2002-03-25 21:30:50Z obrien $ 40 */ 41 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/kernel.h> 46#include <sys/mount.h> 47#include <sys/sysctl.h> 48#include <sys/vnode.h> 49#include <sys/malloc.h> 50 51 52MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); 53 54/* 55 * The highest defined VFS number. 56 */ 57int maxvfsconf = VFS_GENERIC + 1; 58 59/* 60 * Single-linked list of configured VFSes. 61 * New entries are added/deleted by vfs_register()/vfs_unregister() 62 */ 63struct vfsconf *vfsconf; 64 65/* 66 * vfs_init.c 67 * 68 * Allocate and fill in operations vectors. 69 * 70 * An undocumented feature of this approach to defining operations is that 71 * there can be multiple entries in vfs_opv_descs for the same operations 72 * vector. This allows third parties to extend the set of operations 73 * supported by another layer in a binary compatibile way. For example, 74 * assume that NFS needed to be modified to support Ficus. NFS has an entry 75 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 76 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 77 * listing those new operations Ficus adds to NFS, all without modifying the 78 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 79 * that is a(whole)nother story.) This is a feature. 80 */ 81 82/* Table of known vnodeop vectors (list of VFS vnode vectors) */ 83static const struct vnodeopv_desc **vnodeopv_descs; 84static int vnodeopv_num; 85 86/* Table of known descs (list of vnode op handlers "vop_access_desc") */ 87static struct vnodeop_desc **vfs_op_descs; 88/* Reference counts for vfs_op_descs */ 89static int *vfs_op_desc_refs; 90/* Number of descriptions */ 91static int num_op_descs; 92/* Number of entries in each description */ 93static int vfs_opv_numops; 94 95/* 96 * Recalculate the operations vector/description (those parts of it that can 97 * be recalculated, that is.) 98 * XXX It may be preferable to replace this function with an invariant check 99 * and a set of functions that should keep the table invariant. 100 */ 101static void 102vfs_opv_recalc(void) 103{ 104 int i, j; 105 vop_t ***opv_desc_vector_p; 106 vop_t **opv_desc_vector; 107 struct vnodeopv_entry_desc *opve_descp; 108 const struct vnodeopv_desc *opv; 109 110 if (vfs_op_descs == NULL) 111 panic("vfs_opv_recalc called with null vfs_op_descs"); 112 113 /* 114 * Run through and make sure all known descs have an offset 115 * 116 * vop_default_desc is hardwired at offset 1, and offset 0 117 * is a panic sanity check. 118 */ 119 vfs_opv_numops = 0; 120 for (i = 0; i < num_op_descs; i++) 121 if (vfs_opv_numops < (vfs_op_descs[i]->vdesc_offset + 1)) 122 vfs_opv_numops = vfs_op_descs[i]->vdesc_offset + 1; 123 for (i = 0; i < num_op_descs; i++) 124 if (vfs_op_descs[i]->vdesc_offset == 0) 125 vfs_op_descs[i]->vdesc_offset = vfs_opv_numops++; 126 /* 127 * Allocate and fill in the vectors 128 */ 129 for (i = 0; i < vnodeopv_num; i++) { 130 opv = vnodeopv_descs[i]; 131 opv_desc_vector_p = opv->opv_desc_vector_p; 132#ifdef WANT_BAD_JUJU 133 if (*opv_desc_vector_p) 134 FREE(*opv_desc_vector_p, M_VNODE); 135#endif 136 MALLOC(*opv_desc_vector_p, vop_t **, 137 vfs_opv_numops * sizeof(vop_t *), M_VNODE, 138 M_WAITOK | M_ZERO); 139 if (*opv_desc_vector_p == NULL) 140 panic("no memory for vop_t ** vector"); 141 142 /* Fill in, with slot 0 being to return EOPNOTSUPP */ 143 opv_desc_vector = *opv_desc_vector_p; 144 opv_desc_vector[0] = (vop_t *)vop_eopnotsupp; 145 for (j = 0; opv->opv_desc_ops[j].opve_op; j++) { 146 opve_descp = &(opv->opv_desc_ops[j]); 147 opv_desc_vector[opve_descp->opve_op->vdesc_offset] = 148 opve_descp->opve_impl; 149 } 150 151 /* Replace unfilled routines with their default (slot 1). */ 152 opv_desc_vector = *(opv->opv_desc_vector_p); 153 if (opv_desc_vector[1] == NULL) 154 panic("vfs_opv_recalc: vector without a default."); 155 for (j = 0; j < vfs_opv_numops; j++) 156 if (opv_desc_vector[j] == NULL) 157 opv_desc_vector[j] = opv_desc_vector[1]; 158 } 159} 160 161/* Add a set of vnode operations (a description) to the table above. */ 162void 163vfs_add_vnodeops(const void *data) 164{ 165 const struct vnodeopv_desc *opv; 166 const struct vnodeopv_desc **newopv; 167 struct vnodeop_desc **newop; 168 int *newref; 169 vop_t **opv_desc_vector; 170 struct vnodeop_desc *desc; 171 int i, j; 172 173 opv = (const struct vnodeopv_desc *)data; 174 MALLOC(newopv, const struct vnodeopv_desc **, 175 (vnodeopv_num + 1) * sizeof(*newopv), M_VNODE, M_WAITOK); 176 if (newopv == NULL) 177 panic("vfs_add_vnodeops: no memory"); 178 if (vnodeopv_descs) { 179 bcopy(vnodeopv_descs, newopv, vnodeopv_num * sizeof(*newopv)); 180 FREE(vnodeopv_descs, M_VNODE); 181 } 182 newopv[vnodeopv_num] = opv; 183 vnodeopv_descs = newopv; 184 vnodeopv_num++; 185 186 /* See if we have turned up a new vnode op desc */ 187 opv_desc_vector = *(opv->opv_desc_vector_p); 188 for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { 189 for (j = 0; j < num_op_descs; j++) { 190 if (desc == vfs_op_descs[j]) { 191 /* found it, increase reference count */ 192 vfs_op_desc_refs[j]++; 193 break; 194 } 195 } 196 if (j == num_op_descs) { 197 /* not found, new entry */ 198 MALLOC(newop, struct vnodeop_desc **, 199 (num_op_descs + 1) * sizeof(*newop), 200 M_VNODE, M_WAITOK); 201 if (newop == NULL) 202 panic("vfs_add_vnodeops: no memory for desc"); 203 /* new reference count (for unload) */ 204 MALLOC(newref, int *, 205 (num_op_descs + 1) * sizeof(*newref), 206 M_VNODE, M_WAITOK); 207 if (newref == NULL) 208 panic("vfs_add_vnodeops: no memory for refs"); 209 if (vfs_op_descs) { 210 bcopy(vfs_op_descs, newop, 211 num_op_descs * sizeof(*newop)); 212 FREE(vfs_op_descs, M_VNODE); 213 } 214 if (vfs_op_desc_refs) { 215 bcopy(vfs_op_desc_refs, newref, 216 num_op_descs * sizeof(*newref)); 217 FREE(vfs_op_desc_refs, M_VNODE); 218 } 219 newop[num_op_descs] = desc; 220 newref[num_op_descs] = 1; 221 vfs_op_descs = newop; 222 vfs_op_desc_refs = newref; 223 num_op_descs++; 224 } 225 } 226 vfs_opv_recalc(); 227} 228 229/* Remove a vnode type from the vnode description table above. */ 230void 231vfs_rm_vnodeops(const void *data) 232{ 233 const struct vnodeopv_desc *opv; 234 const struct vnodeopv_desc **newopv; 235 struct vnodeop_desc **newop; 236 int *newref; 237 vop_t **opv_desc_vector; 238 struct vnodeop_desc *desc; 239 int i, j, k; 240 241 opv = (const struct vnodeopv_desc *)data; 242 /* Lower ref counts on descs in the table and release if zero */ 243 opv_desc_vector = *(opv->opv_desc_vector_p); 244 for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { 245 for (j = 0; j < num_op_descs; j++) { 246 if (desc == vfs_op_descs[j]) { 247 /* found it, decrease reference count */ 248 vfs_op_desc_refs[j]--; 249 break; 250 } 251 } 252 for (j = 0; j < num_op_descs; j++) { 253 if (vfs_op_desc_refs[j] > 0) 254 continue; 255 if (vfs_op_desc_refs[j] < 0) 256 panic("vfs_remove_vnodeops: negative refcnt"); 257 MALLOC(newop, struct vnodeop_desc **, 258 (num_op_descs - 1) * sizeof(*newop), 259 M_VNODE, M_WAITOK); 260 if (newop == NULL) 261 panic("vfs_remove_vnodeops: no memory for desc"); 262 /* new reference count (for unload) */ 263 MALLOC(newref, int *, 264 (num_op_descs - 1) * sizeof(*newref), 265 M_VNODE, M_WAITOK); 266 if (newref == NULL) 267 panic("vfs_remove_vnodeops: no memory for refs"); 268 for (k = j; k < (num_op_descs - 1); k++) { 269 vfs_op_descs[k] = vfs_op_descs[k + 1]; 270 vfs_op_desc_refs[k] = vfs_op_desc_refs[k + 1]; 271 } 272 bcopy(vfs_op_descs, newop, 273 (num_op_descs - 1) * sizeof(*newop)); 274 bcopy(vfs_op_desc_refs, newref, 275 (num_op_descs - 1) * sizeof(*newref)); 276 FREE(vfs_op_descs, M_VNODE); 277 FREE(vfs_op_desc_refs, M_VNODE); 278 vfs_op_descs = newop; 279 vfs_op_desc_refs = newref; 280 num_op_descs--; 281 } 282 } 283 284 for (i = 0; i < vnodeopv_num; i++) { 285 if (vnodeopv_descs[i] == opv) { 286 for (j = i; j < (vnodeopv_num - 1); j++) 287 vnodeopv_descs[j] = vnodeopv_descs[j + 1]; 288 break; 289 } 290 } 291 if (i == vnodeopv_num) 292 panic("vfs_remove_vnodeops: opv not found"); 293 MALLOC(newopv, const struct vnodeopv_desc **, 294 (vnodeopv_num - 1) * sizeof(*newopv), M_VNODE, M_WAITOK); 295 if (newopv == NULL) 296 panic("vfs_remove_vnodeops: no memory"); 297 bcopy(vnodeopv_descs, newopv, (vnodeopv_num - 1) * sizeof(*newopv)); 298 FREE(vnodeopv_descs, M_VNODE); 299 vnodeopv_descs = newopv; 300 vnodeopv_num--; 301 302 vfs_opv_recalc(); 303} 304 305/* 306 * Routines having to do with the management of the vnode table. 307 */ 308struct vattr va_null; 309 310/* 311 * Initialize the vnode structures and initialize each file system type. 312 */ 313/* ARGSUSED*/ 314static void 315vfsinit(void *dummy) 316{ 317 318 vattr_null(&va_null); 319} 320SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 321 322/* Register a new file system type in the global table */ 323int 324vfs_register(struct vfsconf *vfc) 325{ 326 struct sysctl_oid *oidp; 327 struct vfsconf *vfsp; 328 329 vfsp = NULL; 330 if (vfsconf) 331 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) 332 if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0) 333 return EEXIST; 334 335 vfc->vfc_typenum = maxvfsconf++; 336 if (vfsp) 337 vfsp->vfc_next = vfc; 338 else 339 vfsconf = vfc; 340 vfc->vfc_next = NULL; 341 342 /* 343 * If this filesystem has a sysctl node under vfs 344 * (i.e. vfs.xxfs), then change the oid number of that node to 345 * match the filesystem's type number. This allows user code 346 * which uses the type number to read sysctl variables defined 347 * by the filesystem to continue working. Since the oids are 348 * in a sorted list, we need to make sure the order is 349 * preserved by re-registering the oid after modifying its 350 * number. 351 */ 352 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 353 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 354 sysctl_unregister_oid(oidp); 355 oidp->oid_number = vfc->vfc_typenum; 356 sysctl_register_oid(oidp); 357 } 358 359 /* 360 * Call init function for this VFS... 361 */ 362 (*(vfc->vfc_vfsops->vfs_init))(vfc); 363 364 return 0; 365} 366 367 368/* Remove registration of a file system type */ 369int 370vfs_unregister(struct vfsconf *vfc) 371{ 372 struct vfsconf *vfsp, *prev_vfsp; 373 int error, i, maxtypenum; 374 375 i = vfc->vfc_typenum; 376 377 prev_vfsp = NULL; 378 for (vfsp = vfsconf; vfsp; 379 prev_vfsp = vfsp, vfsp = vfsp->vfc_next) { 380 if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) 381 break; 382 } 383 if (vfsp == NULL) 384 return EINVAL; 385 if (vfsp->vfc_refcount) 386 return EBUSY; 387 if (vfc->vfc_vfsops->vfs_uninit != NULL) { 388 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 389 if (error) 390 return (error); 391 } 392 if (prev_vfsp) 393 prev_vfsp->vfc_next = vfsp->vfc_next; 394 else 395 vfsconf = vfsp->vfc_next; 396 maxtypenum = VFS_GENERIC; 397 for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next) 398 if (maxtypenum < vfsp->vfc_typenum) 399 maxtypenum = vfsp->vfc_typenum; 400 maxvfsconf = maxtypenum + 1; 401 return 0; 402} 403 404/* 405 * Standard kernel module handling code for file system modules. 406 * Referenced from VFS_SET(). 407 */ 408int 409vfs_modevent(module_t mod, int type, void *data) 410{ 411 struct vfsconf *vfc; 412 int error = 0; 413 414 vfc = (struct vfsconf *)data; 415 416 switch (type) { 417 case MOD_LOAD: 418 if (vfc) 419 error = vfs_register(vfc); 420 break; 421 422 case MOD_UNLOAD: 423 if (vfc) 424 error = vfs_unregister(vfc); 425 break; 426 default: /* including MOD_SHUTDOWN */ 427 break; 428 } 429 return (error); 430} 431