vfs_init.c revision 40637
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 * $Id: vfs_init.c,v 1.35 1998/10/16 03:55:00 peter Exp $ 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#include <vm/vm_zone.h> 51 52static void vfs_op_init __P((void)); 53 54static void vfsinit __P((void *)); 55SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 56 57MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); 58 59/* 60 * Sigh, such primitive tools are these... 61 */ 62#if 0 63#define DODEBUG(A) A 64#else 65#define DODEBUG(A) 66#endif 67 68static struct vfsconf void_vfsconf; 69 70#ifdef unused 71extern struct linker_set vfs_opv_descs_; 72#define vfs_opv_descs ((struct vnodeopv_desc **)vfs_opv_descs_.ls_items) 73#endif 74 75extern struct vnodeop_desc *vfs_op_descs[]; 76 /* and the operations they perform */ 77 78/* 79 * XXX this bloat just exands the sysctl__vfs linker set a little so that 80 * we can attach sysctls for VFS modules without expanding the linker set. 81 * Currently (1998/09/06), only one VFS uses sysctls, so 2 extra linker 82 * set slots are more than sufficient. 83 */ 84extern struct linker_set sysctl__vfs; 85static int mod_xx; 86SYSCTL_INT(_vfs, OID_AUTO, mod0, CTLFLAG_RD, &mod_xx, 0, ""); 87SYSCTL_INT(_vfs, OID_AUTO, mod1, CTLFLAG_RD, &mod_xx, 0, ""); 88 89/* 90 * Zone for namei 91 */ 92struct vm_zone *namei_zone; 93 94/* 95 * vfs_init.c 96 * 97 * Allocate and fill in operations vectors. 98 * 99 * An undocumented feature of this approach to defining operations is that 100 * there can be multiple entries in vfs_opv_descs for the same operations 101 * vector. This allows third parties to extend the set of operations 102 * supported by another layer in a binary compatibile way. For example, 103 * assume that NFS needed to be modified to support Ficus. NFS has an entry 104 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 105 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 106 * listing those new operations Ficus adds to NFS, all without modifying the 107 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 108 * that is a(whole)nother story.) This is a feature. 109 * 110 * Without an explicit reserve area, however, you must replace vnode_if.c 111 * and vnode_if.h when you do this, or you will be derefrencing of the 112 * end of vfs_op_descs[]. This is a flaw in the use of a structure 113 * pointer array rather than an agregate to define vfs_op_descs. So 114 * it's not a very dynamic "feature". 115 */ 116void 117vfs_opv_init(struct vnodeopv_desc *opv) 118{ 119 int j, k; 120 vop_t ***opv_desc_vector_p; 121 vop_t **opv_desc_vector; 122 struct vnodeopv_entry_desc *opve_descp; 123 124 /* 125 * Allocate the dynamic vectors and fill them in. 126 */ 127 opv_desc_vector_p = opv->opv_desc_vector_p; 128 /* 129 * Allocate and init the vector, if it needs it. 130 * Also handle backwards compatibility. 131 */ 132 if (*opv_desc_vector_p == NULL) { 133 /* XXX - shouldn't be M_VNODE */ 134 MALLOC(*opv_desc_vector_p, vop_t **, 135 vfs_opv_numops * sizeof(vop_t *), M_VNODE, 136 M_WAITOK); 137 bzero(*opv_desc_vector_p, 138 vfs_opv_numops * sizeof(vop_t *)); 139 DODEBUG(printf("vector at %x allocated\n", 140 opv_desc_vector_p)); 141 } 142 opv_desc_vector = *opv_desc_vector_p; 143 for (j = 0; opv->opv_desc_ops[j].opve_op; j++) { 144 opve_descp = &(opv->opv_desc_ops[j]); 145 146 /* 147 * Sanity check: is this operation listed 148 * in the list of operations? We check this 149 * by seeing if its offest is zero. Since 150 * the default routine should always be listed 151 * first, it should be the only one with a zero 152 * offset. Any other operation with a zero 153 * offset is probably not listed in 154 * vfs_op_descs, and so is probably an error. 155 * 156 * A panic here means the layer programmer 157 * has committed the all-too common bug 158 * of adding a new operation to the layer's 159 * list of vnode operations but 160 * not adding the operation to the system-wide 161 * list of supported operations. 162 */ 163 if (opve_descp->opve_op->vdesc_offset == 0 && 164 opve_descp->opve_op->vdesc_offset != 165 VOFFSET(vop_default)) { 166 printf("operation %s not listed in %s.\n", 167 opve_descp->opve_op->vdesc_name, 168 "vfs_op_descs"); 169 panic ("vfs_opv_init: bad operation"); 170 } 171 /* 172 * Fill in this entry. 173 */ 174 opv_desc_vector[opve_descp->opve_op->vdesc_offset] = 175 opve_descp->opve_impl; 176 } 177 /* 178 * Finally, go back and replace unfilled routines 179 * with their default. (Sigh, an O(n^3) algorithm. I 180 * could make it better, but that'd be work, and n is small.) 181 */ 182 opv_desc_vector = *(opv->opv_desc_vector_p); 183 /* 184 * Force every operations vector to have a default routine. 185 */ 186 if (opv_desc_vector[VOFFSET(vop_default)]==NULL) { 187 panic("vfs_opv_init: operation vector without default routine."); 188 } 189 for (k = 0; k<vfs_opv_numops; k++) 190 if (opv_desc_vector[k] == NULL) 191 opv_desc_vector[k] = 192 opv_desc_vector[VOFFSET(vop_default)]; 193} 194 195/* 196 * Initialize known vnode operations vectors. 197 */ 198static void 199vfs_op_init() 200{ 201 int i; 202 203 DODEBUG(printf("Vnode_interface_init.\n")); 204 DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops)); 205#ifdef unused 206 /* 207 * Set all vnode vectors to a well known value. 208 */ 209 for (i = 0; vfs_opv_descs[i]; i++) 210 *(vfs_opv_descs[i]->opv_desc_vector_p) = NULL; 211#endif 212 /* 213 * assign each op to its offset 214 * 215 * XXX This should not be needed, but is because the per 216 * XXX FS ops tables are not sorted according to the 217 * XXX vnodeop_desc's offset in vfs_op_descs. This 218 * XXX is the same reason we have to take the hit for 219 * XXX the static inline function calls instead of using 220 * XXX simple macro references. 221 */ 222 for (i = 0; i < vfs_opv_numops; i++) 223 vfs_op_descs[i]->vdesc_offset = i; 224#ifdef unused 225 /* Finish the job */ 226 for (i = 0; vfs_opv_descs[i]; i++) 227 vfs_opv_init(vfs_opv_descs[i]); 228#endif 229} 230 231/* 232 * Routines having to do with the management of the vnode table. 233 */ 234extern struct vnodeops dead_vnodeops; 235extern struct vnodeops spec_vnodeops; 236struct vattr va_null; 237 238/* 239 * Initialize the vnode structures and initialize each file system type. 240 */ 241/* ARGSUSED*/ 242static void 243vfsinit(dummy) 244 void *dummy; 245{ 246 struct vfsconf **vfc, *vfsp; 247 int maxtypenum; 248 249 namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2); 250 251 /* 252 * Initialize the vnode table 253 */ 254 vntblinit(); 255 /* 256 * Initialize the vnode name cache 257 */ 258 nchinit(); 259 /* 260 * Build vnode operation vectors. 261 */ 262 vfs_op_init(); 263 /* 264 * Initialize each file system type. 265 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF). 266 */ 267 vattr_null(&va_null); 268 maxvfsconf = VFS_GENERIC + 1; 269} 270 271int 272vfs_register(vfc) 273 struct vfsconf *vfc; 274{ 275 struct linker_set *l; 276 struct sysctl_oid **oidpp; 277 struct vfsconf *vfsp; 278 int error, i, maxtypenum, exists; 279 280 vfsp = NULL; 281 l = &sysctl__vfs; 282 if (vfsconf) 283 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) 284 if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) 285 return EEXIST; 286 287 vfc->vfc_typenum = maxvfsconf++; 288 if (vfc->vfc_vfsops->vfs_oid != NULL) { 289 /* 290 * Attach the oid to the "vfs" node of the sysctl tree if 291 * it isn't already there (it will be there for statically 292 * configured vfs's). 293 */ 294 exists = 0; 295 for (i = l->ls_length, 296 oidpp = (struct sysctl_oid **)l->ls_items; 297 i-- != 0; oidpp++) 298 if (*oidpp == vfc->vfc_vfsops->vfs_oid) { 299 exists = 1; 300 break; 301 } 302 if (exists == 0) 303 for (i = l->ls_length, 304 oidpp = (struct sysctl_oid **)l->ls_items; 305 i-- != 0; oidpp++) { 306 if (*oidpp == NULL || 307 *oidpp == &sysctl___vfs_mod0 || 308 *oidpp == &sysctl___vfs_mod1) { 309 *oidpp = vfc->vfc_vfsops->vfs_oid; 310 break; 311 } 312 } 313 314 vfc->vfc_vfsops->vfs_oid->oid_number = vfc->vfc_typenum; 315 sysctl_order_all(); 316 } 317 if (vfsp) 318 vfsp->vfc_next = vfc; 319 else 320 vfsconf = vfc; 321 vfc->vfc_next = NULL; 322 323 /* 324 * Call init function for this VFS... 325 */ 326 (*(vfc->vfc_vfsops->vfs_init))(vfc); 327 328 return 0; 329} 330 331 332/* 333 * To be called at SI_SUB_VFS, SECOND, for each VFS before any are registered. 334 */ 335void 336vfs_mod_opv_init(handle) 337 void *handle; 338{ 339 int i; 340 struct vnodeopv_desc *opv; 341 342 opv = (struct vnodeopv_desc *)handle; 343 *(opv->opv_desc_vector_p) = NULL; 344 vfs_opv_init(opv); 345} 346 347int 348vfs_unregister(vfc) 349 struct vfsconf *vfc; 350{ 351 struct linker_set *l; 352 struct sysctl_oid **oidpp; 353 struct vfsconf *vfsp, *prev_vfsp; 354 int error, i, maxtypenum; 355 356 i = vfc->vfc_typenum; 357 358 prev_vfsp = NULL; 359 for (vfsp = vfsconf; vfsp; 360 prev_vfsp = vfsp, vfsp = vfsp->vfc_next) { 361 if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) 362 break; 363 } 364 if (vfsp == NULL) 365 return EINVAL; 366 if (vfsp->vfc_refcount) 367 return EBUSY; 368 if (vfc->vfc_vfsops->vfs_uninit != NULL) { 369 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 370 if (error) 371 return (error); 372 } 373 if (prev_vfsp) 374 prev_vfsp->vfc_next = vfsp->vfc_next; 375 else 376 vfsconf = vfsp->vfc_next; 377 if (vfsp->vfc_vfsops->vfs_oid != NULL) { 378 l = &sysctl__vfs; 379 for (i = l->ls_length, 380 oidpp = (struct sysctl_oid **)l->ls_items; 381 i--; oidpp++) { 382 if (*oidpp == vfsp->vfc_vfsops->vfs_oid) { 383 *oidpp = NULL; 384 sysctl_order_all(); 385 break; 386 } 387 } 388 } 389 maxtypenum = VFS_GENERIC; 390 for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next) 391 if (maxtypenum < vfsp->vfc_typenum) 392 maxtypenum = vfsp->vfc_typenum; 393 maxvfsconf = maxtypenum + 1; 394 return 0; 395} 396