diff options
Diffstat (limited to 'sys/kern/vfs_init.c')
-rw-r--r-- | sys/kern/vfs_init.c | 413 |
1 files changed, 169 insertions, 244 deletions
diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index 43589c740a7e8..39900c612c64d 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 - * $Id: vfs_init.c,v 1.40 1998/11/15 15:18:30 bde Exp $ + * $Id: vfs_init.c,v 1.34 1998/10/05 11:10:55 obrien Exp $ */ @@ -49,10 +49,33 @@ #include <sys/malloc.h> #include <vm/vm_zone.h> +static void vfs_op_init __P((void)); + +static void vfsinit __P((void *)); +SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); /* + * Sigh, such primitive tools are these... + */ +#if 0 +#define DODEBUG(A) A +#else +#define DODEBUG(A) +#endif + +static struct vfsconf void_vfsconf; + +#ifdef unused +extern struct linker_set vfs_opv_descs_; +#define vfs_opv_descs ((struct vnodeopv_desc **)vfs_opv_descs_.ls_items) +#endif + +extern struct vnodeop_desc *vfs_op_descs[]; + /* and the operations they perform */ + +/* * XXX this bloat just exands the sysctl__vfs linker set a little so that * we can attach sysctls for VFS modules without expanding the linker set. * Currently (1998/09/06), only one VFS uses sysctls, so 2 extra linker @@ -83,221 +106,133 @@ struct vm_zone *namei_zone; * listing those new operations Ficus adds to NFS, all without modifying the * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but * that is a(whole)nother story.) This is a feature. + * + * Without an explicit reserve area, however, you must replace vnode_if.c + * and vnode_if.h when you do this, or you will be derefrencing of the + * end of vfs_op_descs[]. This is a flaw in the use of a structure + * pointer array rather than an agregate to define vfs_op_descs. So + * it's not a very dynamic "feature". */ - -/* Table of known vnodeop vectors (list of VFS vnode vectors) */ -static struct vnodeopv_desc **vnodeopv_descs; -static int vnodeopv_num; - -/* Table of known descs (list of vnode op handlers "vop_access_desc") */ -static struct vnodeop_desc **vfs_op_descs; -static int *vfs_op_desc_refs; /* reference counts */ -static int num_op_descs; -static int vfs_opv_numops; - -static void -vfs_opv_recalc(void) +void +vfs_opv_init(struct vnodeopv_desc *opv) { - int i, j; + int j, k; vop_t ***opv_desc_vector_p; vop_t **opv_desc_vector; struct vnodeopv_entry_desc *opve_descp; - struct vnodeopv_desc *opv; - - if (vfs_op_descs == NULL) - panic("vfs_opv_recalc called with null vfs_op_descs"); /* - * Run through and make sure all known descs have an offset - * - * vop_default_desc is hardwired at offset 1, and offset 0 - * is a panic sanity check. + * Allocate the dynamic vectors and fill them in. */ - vfs_opv_numops = 0; - for (i = 0; i < num_op_descs; i++) - if (vfs_opv_numops < (vfs_op_descs[i]->vdesc_offset + 1)) - vfs_opv_numops = vfs_op_descs[i]->vdesc_offset + 1; - for (i = 0; i < num_op_descs; i++) - if (vfs_op_descs[i]->vdesc_offset == 0) - vfs_op_descs[i]->vdesc_offset = vfs_opv_numops++; + opv_desc_vector_p = opv->opv_desc_vector_p; /* - * Allocate and fill in the vectors + * Allocate and init the vector, if it needs it. + * Also handle backwards compatibility. */ - for (i = 0; i < vnodeopv_num; i++) { - opv = vnodeopv_descs[i]; - opv_desc_vector_p = opv->opv_desc_vector_p; - if (*opv_desc_vector_p) - FREE(*opv_desc_vector_p, M_VNODE); + if (*opv_desc_vector_p == NULL) { + /* XXX - shouldn't be M_VNODE */ MALLOC(*opv_desc_vector_p, vop_t **, - vfs_opv_numops * sizeof(vop_t *), M_VNODE, M_WAITOK); - if (*opv_desc_vector_p == NULL) - panic("no memory for vop_t ** vector"); - bzero(*opv_desc_vector_p, vfs_opv_numops * sizeof(vop_t *)); - - /* Fill in, with slot 0 being panic */ - opv_desc_vector = *opv_desc_vector_p; - opv_desc_vector[0] = (vop_t *)vop_panic; - for (j = 0; opv->opv_desc_ops[j].opve_op; j++) { - opve_descp = &(opv->opv_desc_ops[j]); - opv_desc_vector[opve_descp->opve_op->vdesc_offset] = - opve_descp->opve_impl; - } - - /* Replace unfilled routines with their default (slot 1). */ - opv_desc_vector = *(opv->opv_desc_vector_p); - if (opv_desc_vector[1] == NULL) - panic("vfs_opv_recalc: vector without a default."); - for (j = 0; j < vfs_opv_numops; j++) - if (opv_desc_vector[j] == NULL) - opv_desc_vector[j] = opv_desc_vector[1]; + vfs_opv_numops * sizeof(vop_t *), M_VNODE, + M_WAITOK); + bzero(*opv_desc_vector_p, + vfs_opv_numops * sizeof(vop_t *)); + DODEBUG(printf("vector at %x allocated\n", + opv_desc_vector_p)); } -} + opv_desc_vector = *opv_desc_vector_p; + for (j = 0; opv->opv_desc_ops[j].opve_op; j++) { + opve_descp = &(opv->opv_desc_ops[j]); -void -vfs_add_vnodeops(void *data) -{ - struct vnodeopv_desc *opv; - struct vnodeopv_desc **newopv; - struct vnodeop_desc **newop; - int *newref; - vop_t **opv_desc_vector; - struct vnodeop_desc *desc; - int i, j; - - opv = (struct vnodeopv_desc *)data; - MALLOC(newopv, struct vnodeopv_desc **, - (vnodeopv_num + 1) * sizeof(*newopv), M_VNODE, M_WAITOK); - if (newopv == NULL) - panic("vfs_add_vnodeops: no memory"); - if (vnodeopv_descs) { - bcopy(vnodeopv_descs, newopv, vnodeopv_num * sizeof(*newopv)); - FREE(vnodeopv_descs, M_VNODE); + /* + * Sanity check: is this operation listed + * in the list of operations? We check this + * by seeing if its offest is zero. Since + * the default routine should always be listed + * first, it should be the only one with a zero + * offset. Any other operation with a zero + * offset is probably not listed in + * vfs_op_descs, and so is probably an error. + * + * A panic here means the layer programmer + * has committed the all-too common bug + * of adding a new operation to the layer's + * list of vnode operations but + * not adding the operation to the system-wide + * list of supported operations. + */ + if (opve_descp->opve_op->vdesc_offset == 0 && + opve_descp->opve_op->vdesc_offset != + VOFFSET(vop_default)) { + printf("operation %s not listed in %s.\n", + opve_descp->opve_op->vdesc_name, + "vfs_op_descs"); + panic ("vfs_opv_init: bad operation"); + } + /* + * Fill in this entry. + */ + opv_desc_vector[opve_descp->opve_op->vdesc_offset] = + opve_descp->opve_impl; } - newopv[vnodeopv_num] = opv; - vnodeopv_descs = newopv; - vnodeopv_num++; - - /* See if we have turned up a new vnode op desc */ + /* + * Finally, go back and replace unfilled routines + * with their default. (Sigh, an O(n^3) algorithm. I + * could make it better, but that'd be work, and n is small.) + */ opv_desc_vector = *(opv->opv_desc_vector_p); - for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { - for (j = 0; j < num_op_descs; j++) { - if (desc == vfs_op_descs[j]) { - /* found it, increase reference count */ - vfs_op_desc_refs[j]++; - break; - } - } - if (j == num_op_descs) { - /* not found, new entry */ - MALLOC(newop, struct vnodeop_desc **, - (num_op_descs + 1) * sizeof(*newop), - M_VNODE, M_WAITOK); - if (newop == NULL) - panic("vfs_add_vnodeops: no memory for desc"); - /* new reference count (for unload) */ - MALLOC(newref, int *, - (num_op_descs + 1) * sizeof(*newref), - M_VNODE, M_WAITOK); - if (newref == NULL) - panic("vfs_add_vnodeops: no memory for refs"); - if (vfs_op_descs) { - bcopy(vfs_op_descs, newop, - num_op_descs * sizeof(*newop)); - FREE(vfs_op_descs, M_VNODE); - } - if (vfs_op_desc_refs) { - bcopy(vfs_op_desc_refs, newref, - num_op_descs * sizeof(*newref)); - FREE(vfs_op_desc_refs, M_VNODE); - } - newop[num_op_descs] = desc; - newref[num_op_descs] = 1; - vfs_op_descs = newop; - vfs_op_desc_refs = newref; - num_op_descs++; - } + /* + * Force every operations vector to have a default routine. + */ + if (opv_desc_vector[VOFFSET(vop_default)]==NULL) { + panic("vfs_opv_init: operation vector without default routine."); } - vfs_opv_recalc(); + for (k = 0; k<vfs_opv_numops; k++) + if (opv_desc_vector[k] == NULL) + opv_desc_vector[k] = + opv_desc_vector[VOFFSET(vop_default)]; } -void -vfs_rm_vnodeops(void *data) +/* + * Initialize known vnode operations vectors. + */ +static void +vfs_op_init() { - struct vnodeopv_desc *opv; - struct vnodeopv_desc **newopv; - struct vnodeop_desc **newop; - int *newref; - vop_t **opv_desc_vector; - struct vnodeop_desc *desc; - int i, j, k; - - opv = (struct vnodeopv_desc *)data; - /* Lower ref counts on descs in the table and release if zero */ - opv_desc_vector = *(opv->opv_desc_vector_p); - for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { - for (j = 0; j < num_op_descs; j++) { - if (desc == vfs_op_descs[j]) { - /* found it, decrease reference count */ - vfs_op_desc_refs[j]--; - break; - } - } - for (j = 0; j < num_op_descs; j++) { - if (vfs_op_desc_refs[j] > 0) - continue; - if (vfs_op_desc_refs[j] < 0) - panic("vfs_remove_vnodeops: negative refcnt"); - MALLOC(newop, struct vnodeop_desc **, - (num_op_descs - 1) * sizeof(*newop), - M_VNODE, M_WAITOK); - if (newop == NULL) - panic("vfs_remove_vnodeops: no memory for desc"); - /* new reference count (for unload) */ - MALLOC(newref, int *, - (num_op_descs - 1) * sizeof(*newref), - M_VNODE, M_WAITOK); - if (newref == NULL) - panic("vfs_remove_vnodeops: no memory for refs"); - for (k = j; k < (num_op_descs - 1); k++) { - vfs_op_descs[k] = vfs_op_descs[k + 1]; - vfs_op_desc_refs[k] = vfs_op_desc_refs[k + 1]; - } - bcopy(vfs_op_descs, newop, - (num_op_descs - 1) * sizeof(*newop)); - bcopy(vfs_op_desc_refs, newref, - (num_op_descs - 1) * sizeof(*newref)); - FREE(vfs_op_descs, M_VNODE); - FREE(vfs_op_desc_refs, M_VNODE); - vfs_op_descs = newop; - vfs_op_desc_refs = newref; - num_op_descs--; - } - } - - for (i = 0; i < vnodeopv_num; i++) { - if (vnodeopv_descs[i] == opv) { - for (j = i; j < (vnodeopv_num - 1); j++) - vnodeopv_descs[j] = vnodeopv_descs[j + 1]; - break; - } - } - if (i == vnodeopv_num) - panic("vfs_remove_vnodeops: opv not found"); - MALLOC(newopv, struct vnodeopv_desc **, - (vnodeopv_num - 1) * sizeof(*newopv), M_VNODE, M_WAITOK); - if (newopv == NULL) - panic("vfs_remove_vnodeops: no memory"); - bcopy(vnodeopv_descs, newopv, (vnodeopv_num - 1) * sizeof(*newopv)); - FREE(vnodeopv_descs, M_VNODE); - vnodeopv_descs = newopv; - vnodeopv_num--; + int i; - vfs_opv_recalc(); + DODEBUG(printf("Vnode_interface_init.\n")); + DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops)); +#ifdef unused + /* + * Set all vnode vectors to a well known value. + */ + for (i = 0; vfs_opv_descs[i]; i++) + *(vfs_opv_descs[i]->opv_desc_vector_p) = NULL; +#endif + /* + * assign each op to its offset + * + * XXX This should not be needed, but is because the per + * XXX FS ops tables are not sorted according to the + * XXX vnodeop_desc's offset in vfs_op_descs. This + * XXX is the same reason we have to take the hit for + * XXX the static inline function calls instead of using + * XXX simple macro references. + */ + for (i = 0; i < vfs_opv_numops; i++) + vfs_op_descs[i]->vdesc_offset = i; +#ifdef unused + /* Finish the job */ + for (i = 0; vfs_opv_descs[i]; i++) + vfs_opv_init(vfs_opv_descs[i]); +#endif } /* * Routines having to do with the management of the vnode table. */ +extern struct vnodeops dead_vnodeops; +extern struct vnodeops spec_vnodeops; struct vattr va_null; /* @@ -305,8 +240,11 @@ struct vattr va_null; */ /* ARGSUSED*/ static void -vfsinit(void *dummy) +vfsinit(dummy) + void *dummy; { + struct vfsconf **vfc, *vfsp; + int maxtypenum; namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2); @@ -319,23 +257,28 @@ vfsinit(void *dummy) */ nchinit(); /* + * Build vnode operation vectors. + */ + vfs_op_init(); + /* * Initialize each file system type. * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF). */ vattr_null(&va_null); maxvfsconf = VFS_GENERIC + 1; } -SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) int -vfs_register(struct vfsconf *vfc) +vfs_register(vfc) + struct vfsconf *vfc; { struct linker_set *l; struct sysctl_oid **oidpp; struct vfsconf *vfsp; - int i, exists; + int error, i, maxtypenum, exists; vfsp = NULL; + exists = 0; l = &sysctl__vfs; if (vfsconf) for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) @@ -344,33 +287,23 @@ vfs_register(struct vfsconf *vfc) vfc->vfc_typenum = maxvfsconf++; if (vfc->vfc_vfsops->vfs_oid != NULL) { - /* - * Attach the oid to the "vfs" node of the sysctl tree if - * it isn't already there (it will be there for statically - * configured vfs's). - */ - exists = 0; - for (i = l->ls_length, - oidpp = (struct sysctl_oid **)l->ls_items; - i-- != 0; oidpp++) - if (*oidpp == vfc->vfc_vfsops->vfs_oid) { + oidpp = (struct sysctl_oid **)l->ls_items; + for (i = l->ls_length; i-- && !exists; oidpp++) + if (*oidpp == vfc->vfc_vfsops->vfs_oid) exists = 1; + } + if (exists == 0 && vfc->vfc_vfsops->vfs_oid != NULL) { + oidpp = (struct sysctl_oid **)l->ls_items; + for (i = l->ls_length; i--; oidpp++) { + if (*oidpp == NULL || + *oidpp == &sysctl___vfs_mod0 || + *oidpp == &sysctl___vfs_mod1) { + *oidpp = vfc->vfc_vfsops->vfs_oid; + (*oidpp)->oid_number = vfc->vfc_typenum; + sysctl_order_all(); break; } - if (exists == 0) - for (i = l->ls_length, - oidpp = (struct sysctl_oid **)l->ls_items; - i-- != 0; oidpp++) { - if (*oidpp == NULL || - *oidpp == &sysctl___vfs_mod0 || - *oidpp == &sysctl___vfs_mod1) { - *oidpp = vfc->vfc_vfsops->vfs_oid; - break; - } - } - - vfc->vfc_vfsops->vfs_oid->oid_number = vfc->vfc_typenum; - sysctl_order_all(); + } } if (vfsp) vfsp->vfc_next = vfc; @@ -387,8 +320,24 @@ vfs_register(struct vfsconf *vfc) } +/* + * To be called at SI_SUB_VFS, SECOND, for each VFS before any are registered. + */ +void +vfs_mod_opv_init(handle) + void *handle; +{ + int i; + struct vnodeopv_desc *opv; + + opv = (struct vnodeopv_desc *)handle; + *(opv->opv_desc_vector_p) = NULL; + vfs_opv_init(opv); +} + int -vfs_unregister(struct vfsconf *vfc) +vfs_unregister(vfc) + struct vfsconf *vfc; { struct linker_set *l; struct sysctl_oid **oidpp; @@ -435,27 +384,3 @@ vfs_unregister(struct vfsconf *vfc) maxvfsconf = maxtypenum + 1; return 0; } - -int -vfs_modevent(module_t mod, int type, void *data) -{ - struct vfsconf *vfc; - int error = 0; - - vfc = (struct vfsconf *)data; - - switch (type) { - case MOD_LOAD: - if (vfc) - error = vfs_register(vfc); - break; - - case MOD_UNLOAD: - if (vfc) - error = vfs_unregister(vfc); - break; - default: /* including MOD_SHUTDOWN */ - break; - } - return (error); -} |