diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 1999-01-21 00:55:32 +0000 | 
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 1999-01-21 00:55:32 +0000 | 
| commit | 76b5366091f76c9bc73570149ef5055648fc2c39 (patch) | |
| tree | 590d020e0f2a5bea6e09d66d951a674443b21d67 /sys/kern/vfs_init.c | |
| parent | 4b4d01da6f07f7754ff6a6e4f5223e9f0984d1a6 (diff) | |
Notes
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 43589c740a7e..39900c612c64 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); -} | 
