Subject: Overhaul device parent matching in config(8)/kernel
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-kern
Date: 09/25/2002 09:49:42
--ZGiS0Q5IWpPtfppv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Folks...
I have overhauled how device parent matching is done in the kernel in
order to better support:
1. Drivers are loadable modules (no, this is no where near
complete yet).
2. Some forthcoming changes to support attaching real devices
to pseudo-devices.
For those of you fortunate enough to not know how this currently works
in the kernel, here is a lesson:
* For each entry in the cfdata[] table, config(8) emits a
"parent vector", which is an array of indices back into
the cfdata[] table. These reference cfdata[] entries for
potential parents of the device.
* When the kernel attaches a device, it scans the cfdata[]
table looking for un-attached entries who's parent vector
array references the device's cfdata[] entry, and when it
finds one, applies the match info in the child's cfdata[]
entry, attempting to attach the device.
This is sub-optimal for several reasons:
* In the presence of multiple cfdata[] tables (i.e. which
would be the case with loadable driver modules), the parent
vector can't reference a parent from another cfdata[] table.
* For devices which are spec'd to attach to an interface attribute
(e.g. "scsibus* at scsi?"), config(8) represents this internally
by expanding the vector to all device's which carry that interface
attribute. I.e. if you say "acphy* at mii?", conifig(8) actually
generates a parent vector that looks like this:
acphy* at url*|aue*|xi*|ste*|bge*|wm*|stge*|gsip*| \
sip*|vr*|tl*|pcn*|sf*|tlp*|tlp*|rtk*|ne0|\
ne1|ne*|ne*|ne*|ne*|epic*|sm0|sm*|sm*|fxp*|\
ex*|ep*|ep*|ep*|ep*|ep*|ep*
This obviously doesn't work if you later load a "foo" device
which carries the "mii" interface attribute, and want to attach
an acphy to it ... you'd need to create another cfdata[] entry
for acphy with the correct parent vector.
What I have done to address this is:
* Add a "const char **cd_attrs" member to the cfdriver structure.
If non-NULL, it is an array of interface attributes carried by
a device, e.g.:
static const char *ex_attrs[] = { "mii", NULL };
struct cfdriver ex_cd = {
NULL, "ex", DV_IFNET, 0, ex_attrs
};
For devices which do not have interface attributes, you
have this instead:
struct cfdriver lc_cd = {
NULL, "lc", DV_IFNET, 0, NULL
};
By recording the fact that something has an interface attribute,
this allows you to attach to that attribute at run-time, rather
than relying on a pre-expanded list of things that have the
attribute.
* Remove the parent vector array, in favor of a new "parent spec",
which looks like this:
struct cfparent {
const char *cfp_iattr; /* interface attribute */
const char *cfp_parent; /* optional specific parent */
int cfp_unit; /* optional specific unit
(-1 to wildcard) */
};
Since all devices attach to an interface attribute, the
parent spec records which one. Additionally, if a device
instance wants to attach to a specific parent, that is also
recorded. So, the new parent spec can preceisely describe
the following three cases:
scsibus* at scsi?
-> iattr = "scsi", parent = NULL, unit = -1
scsibus* at ahc?
-> iattr = "scsi", parent = "ahc", unit = -1
scsibus* at ahc5
-> iattr = "scsi", parent = "ahc", unit = 5
* The kernel now uses the cd_attrs array and the parent specs
to identify potential children of a device (i.e. the device
matches the child's parent spec). This works in the presence
of multiple cfdata tables, because no references back into
any cfdata table are made; everything is done with string
comparisons.
This exercise has also allowed me to garbage-collect vast amounts of
confusing code from config(8) :-)
Attached are the diffs that implement this. They're actually not
that large, and some of the changes were merely to make the
__BROKEN_CONFIG_UNIT_USAGE stuff a little more readable.
--
-- Jason R. Thorpe <thorpej@wasabisystems.com>
--ZGiS0Q5IWpPtfppv
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=config-diffs
Index: sys/kern/subr_autoconf.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/subr_autoconf.c,v
retrieving revision 1.65
diff -c -r1.65 subr_autoconf.c
*** sys/kern/subr_autoconf.c 2002/09/23 23:16:06 1.65
--- sys/kern/subr_autoconf.c 2002/09/25 15:13:29
***************
*** 222,227 ****
--- 222,278 ----
}
/*
+ * Determine if `parent' is a potential parent for a device spec based
+ * on `cfp'.
+ */
+ static int
+ cfparent_match(struct device *parent, const struct cfparent *cfp)
+ {
+ struct cfdriver *pcd = parent->dv_cfdata->cf_driver;
+ const char **cpp, *cp;
+
+ /*
+ * First, ensure this parent has the correct interface
+ * attribute.
+ */
+ if (pcd->cd_attrs == NULL)
+ return (0); /* no interface attributes -> no children */
+ for (cpp = pcd->cd_attrs; (cp = *cpp) != NULL; cpp++) {
+ if (cp[0] == cfp->cfp_iattr[0] &&
+ strcmp(cp, cfp->cfp_iattr) == 0) {
+ /* Match. */
+ break;
+ }
+ }
+ if (cp == NULL)
+ return (0); /* doesn't carry the req'd attribute */
+
+ /*
+ * If no specific parent device instance was specified (i.e.
+ * we're attaching to the attribute only), we're done!
+ */
+ if (cfp->cfp_parent == NULL)
+ return (1);
+
+ /*
+ * Check the parent device's name.
+ */
+ if (pcd->cd_name[0] != cfp->cfp_parent[0] ||
+ strcmp(pcd->cd_name, cfp->cfp_parent) != 0)
+ return (0); /* not the same parent */
+
+ /*
+ * Make sure the unit number matches.
+ */
+ if (cfp->cfp_unit == -1 || /* wildcard */
+ cfp->cfp_unit == parent->dv_unit)
+ return (1);
+
+ /* Unit numbers don't match. */
+ return (0);
+ }
+
+ /*
* Iterate over all potential children of some device, calling the given
* function (default being the child's match function) for each one.
* Nonzero returns are matches; the highest value returned is considered
***************
*** 237,243 ****
{
struct cftable *ct;
struct cfdata *cf;
- short *p;
struct matchinfo m;
m.fn = fn;
--- 288,293 ----
***************
*** 258,266 ****
if (cf->cf_fstate == FSTATE_DNOTFOUND ||
cf->cf_fstate == FSTATE_DSTAR)
continue;
! for (p = cf->cf_parents; *p >= 0; p++)
! if (parent->dv_cfdata == &(ct->ct_cfdata)[*p])
! mapply(&m, cf);
}
}
return (m.match);
--- 308,315 ----
if (cf->cf_fstate == FSTATE_DNOTFOUND ||
cf->cf_fstate == FSTATE_DSTAR)
continue;
! if (cfparent_match(parent, cf->cf_pspec))
! mapply(&m, cf);
}
}
return (m.match);
***************
*** 404,409 ****
--- 453,459 ----
ca = cf->cf_attach;
if (ca->ca_devsize < sizeof(struct device))
panic("config_attach");
+
#ifndef __BROKEN_CONFIG_UNIT_USAGE
if (cf->cf_fstate == FSTATE_STAR) {
for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
***************
*** 415,429 ****
*/
} else {
myunit = cf->cf_unit;
! #else /* __BROKEN_CONFIG_UNIT_USAGE */
myunit = cf->cf_unit;
if (cf->cf_fstate == FSTATE_STAR)
cf->cf_unit++;
else {
- #endif /* __BROKEN_CONFIG_UNIT_USAGE */
KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
cf->cf_fstate = FSTATE_FOUND;
}
/* compute length of name and decimal expansion of unit number */
lname = strlen(cd->cd_name);
--- 465,482 ----
*/
} else {
myunit = cf->cf_unit;
! KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
! cf->cf_fstate = FSTATE_FOUND;
! }
! #else
myunit = cf->cf_unit;
if (cf->cf_fstate == FSTATE_STAR)
cf->cf_unit++;
else {
KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
cf->cf_fstate = FSTATE_FOUND;
}
+ #endif /* ! __BROKEN_CONFIG_UNIT_USAGE */
/* compute length of name and decimal expansion of unit number */
lname = strlen(cd->cd_name);
***************
*** 465,473 ****
* Before attaching, clobber any unfound devices that are
* otherwise identical.
*/
- #ifdef __BROKEN_CONFIG_UNIT_USAGE
- /* bump the unit number on all starred cfdata for this device. */
- #endif /* __BROKEN_CONFIG_UNIT_USAGE */
TAILQ_FOREACH(ct, &allcftables, ct_list) {
for (cf = ct->ct_cfdata; cf->cf_driver; cf++) {
if (cf->cf_driver == cd &&
--- 518,523 ----
***************
*** 475,480 ****
--- 525,534 ----
if (cf->cf_fstate == FSTATE_NOTFOUND)
cf->cf_fstate = FSTATE_FOUND;
#ifdef __BROKEN_CONFIG_UNIT_USAGE
+ /*
+ * Bump the unit number on all starred cfdata
+ * entries for this device.
+ */
if (cf->cf_fstate == FSTATE_STAR)
cf->cf_unit++;
#endif /* __BROKEN_CONFIG_UNIT_USAGE */
***************
*** 570,581 ****
/*
* Mark cfdata to show that the unit can be reused, if possible.
*/
- #ifdef __BROKEN_CONFIG_UNIT_USAGE
- /*
- * Note that we can only re-use a starred unit number if the unit
- * being detached had the last assigned unit number.
- */
- #endif /* __BROKEN_CONFIG_UNIT_USAGE */
TAILQ_FOREACH(ct, &allcftables, ct_list) {
for (cf = ct->ct_cfdata; cf->cf_driver; cf++) {
if (cf->cf_driver == cd) {
--- 624,629 ----
***************
*** 583,588 ****
--- 631,641 ----
cf->cf_unit == dev->dv_unit)
cf->cf_fstate = FSTATE_NOTFOUND;
#ifdef __BROKEN_CONFIG_UNIT_USAGE
+ /*
+ * Note that we can only re-use a starred
+ * unit number if the unit being detached
+ * had the last assigned unit number.
+ */
if (cf->cf_fstate == FSTATE_STAR &&
cf->cf_unit == dev->dv_unit + 1)
cf->cf_unit--;
Index: sys/sys/device.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/device.h,v
retrieving revision 1.50
diff -c -r1.50 device.h
*** sys/sys/device.h 2002/09/23 23:16:07 1.50
--- sys/sys/device.h 2002/09/25 15:13:30
***************
*** 162,167 ****
--- 162,180 ----
}
/*
+ * Description of a configuration parent. Each device attachment attaches
+ * to an "interface attribute", which is given in this structure. The parent
+ * *must* carry this attribute. Optionally, an individual device instance
+ * may also specify a specific parent device instance.
+ */
+ struct cfparent {
+ const char *cfp_iattr; /* interface attribute */
+ const char *cfp_parent; /* optional specific parent */
+ int cfp_unit; /* optional specific unit
+ (-1 to wildcard) */
+ };
+
+ /*
* Configuration data (i.e., data placed in ioconf.c).
*/
struct cfdata {
***************
*** 171,177 ****
short cf_fstate; /* finding state (below) */
int *cf_loc; /* locators (machine dependent) */
int cf_flags; /* flags from config */
! short *cf_parents; /* potential parents */
const char **cf_locnames; /* locator names (machine dependent) */
};
#define FSTATE_NOTFOUND 0 /* has not been found */
--- 184,190 ----
short cf_fstate; /* finding state (below) */
int *cf_loc; /* locators (machine dependent) */
int cf_flags; /* flags from config */
! const struct cfparent *cf_pspec;/* parent specification */
const char **cf_locnames; /* locator names (machine dependent) */
};
#define FSTATE_NOTFOUND 0 /* has not been found */
***************
*** 224,229 ****
--- 237,243 ----
const char *cd_name; /* device name */
enum devclass cd_class; /* device classification */
int cd_ndevs; /* size of cd_devs array */
+ const char **cd_attrs; /* attributes for this device */
};
/*
Index: usr.sbin/config/defs.h
===================================================================
RCS file: /cvsroot/syssrc/usr.sbin/config/defs.h,v
retrieving revision 1.6
diff -c -r1.6 defs.h
*** usr.sbin/config/defs.h 2002/09/11 06:20:09 1.6
--- usr.sbin/config/defs.h 2002/09/25 15:13:31
***************
*** 156,161 ****
--- 156,175 ----
};
/*
+ * Parent specification. Multiple device instances may share a
+ * given parent spec. Parent specs are emitted only if there are
+ * device instances which actually reference it.
+ */
+ struct pspec {
+ TAILQ_ENTRY(pspec) p_list; /* link on parent spec list */
+ struct attr *p_iattr; /* interface attribute of parent */
+ struct devbase *p_atdev; /* optional parent device base */
+ int p_atunit; /* optional parent device unit */
+ struct nvlist *p_devs; /* children using it */
+ int p_inst; /* parent spec instance */
+ };
+
+ /*
* The "base" part (struct devbase) of a device ("uba", "sd"; but not
* "uba2" or "sd0"). It may be found "at" one or more attributes,
* including "at root" (this is represented by a NULL attribute), as
***************
*** 225,246 ****
struct devi *i_asame; /* list on same base attachment */
struct devi *i_alias; /* other aliases of this instance */
const char *i_at; /* where this is "at" (NULL if at root) */
! struct attr *i_atattr; /* attr that allowed attach */
! struct devbase *i_atdev;/* if "at <devname><unit>", else NULL */
struct deva *i_atdeva;
! const char **i_locs; /* locators (as given by i_atattr) */
! int i_atunit; /* unit from "at" */
int i_cfflags; /* flags from config line */
int i_lineno; /* line # in config, for later errors */
/* created during packing or ioconf.c generation */
- /* i_loclen via i_atattr->a_loclen */
short i_collapsed; /* set => this alias no longer needed */
short i_cfindex; /* our index in cfdata */
- short i_pvlen; /* number of parents */
- short i_pvoff; /* offset in parents.vec */
short i_locoff; /* offset in locators.vec */
- struct devi **i_parents;/* the parents themselves */
};
/* special units */
--- 239,254 ----
struct devi *i_asame; /* list on same base attachment */
struct devi *i_alias; /* other aliases of this instance */
const char *i_at; /* where this is "at" (NULL if at root) */
! struct pspec *i_pspec; /* parent spec (NULL if at root) */
struct deva *i_atdeva;
! const char **i_locs; /* locators (as given by pspec's iattr) */
int i_cfflags; /* flags from config line */
int i_lineno; /* line # in config, for later errors */
/* created during packing or ioconf.c generation */
short i_collapsed; /* set => this alias no longer needed */
short i_cfindex; /* our index in cfdata */
short i_locoff; /* offset in locators.vec */
};
/* special units */
***************
*** 375,381 ****
--- 383,391 ----
TAILQ_HEAD(, devi) alldevi, /* list of all instances */
allpseudo; /* list of all pseudo-devices */
TAILQ_HEAD(, devm) alldevms; /* list of all device-majors */
+ TAILQ_HEAD(, pspec) allpspecs; /* list of all parent specs */
int ndevi; /* number of devi's (before packing) */
+ int npspecs; /* number of parent specs */
int maxbdevm; /* max number of block major */
int maxcdevm; /* max number of character major */
int do_devsw; /* 0 if pre-devsw config */
***************
*** 390,399 ****
struct devi **packed; /* arrayified table for packed devi's */
int npacked; /* size of packed table, <= ndevi */
- struct { /* pv[] table for config */
- short *vec;
- int used;
- } parents;
struct { /* loc[] table for config */
const char **vec;
int used;
--- 400,405 ----
Index: usr.sbin/config/main.c
===================================================================
RCS file: /cvsroot/syssrc/usr.sbin/config/main.c,v
retrieving revision 1.70
diff -c -r1.70 main.c
*** usr.sbin/config/main.c 2002/09/11 06:20:09 1.70
--- usr.sbin/config/main.c 2002/09/25 15:13:32
***************
*** 864,871 ****
static int
hasparent(struct devi *i)
{
struct nvlist *nv;
- int atunit = i->i_atunit;
/*
* We determine whether or not a device has a parent in in one
--- 864,871 ----
static int
hasparent(struct devi *i)
{
+ struct pspec *p;
struct nvlist *nv;
/*
* We determine whether or not a device has a parent in in one
***************
*** 879,896 ****
* may be able to attach the device.
*/
/*
* Case (1): A parent was named. Either it's configured, or not.
*/
! if (i->i_atdev != NULL)
! return (devbase_has_instances(i->i_atdev, atunit));
/*
* Case (2): No parent was named. Look for devs that provide the attr.
*/
! if (i->i_atattr != NULL)
! for (nv = i->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
! if (devbase_has_instances(nv->nv_ptr, atunit))
return (1);
return (0);
}
--- 879,900 ----
* may be able to attach the device.
*/
+ /* No pspec, no parent (root node). */
+ if ((p = i->i_pspec) == NULL)
+ return (0);
+
/*
* Case (1): A parent was named. Either it's configured, or not.
*/
! if (p->p_atdev != NULL)
! return (devbase_has_instances(p->p_atdev, p->p_atunit));
/*
* Case (2): No parent was named. Look for devs that provide the attr.
*/
! if (p->p_iattr != NULL)
! for (nv = p->p_iattr->a_refs; nv != NULL; nv = nv->nv_next)
! if (devbase_has_instances(nv->nv_ptr, p->p_atunit))
return (1);
return (0);
}
***************
*** 944,961 ****
int
crosscheck(void)
{
struct devi *i;
struct config *cf;
int errs;
errs = 0;
TAILQ_FOREACH(i, &alldevi, i_next) {
! if (i->i_at == NULL || hasparent(i))
continue;
xerror(conffile, i->i_lineno,
"%s at %s is orphaned", i->i_name, i->i_at);
(void)fprintf(stderr, " (%s %s declared)\n",
! i->i_atunit == WILD ? "nothing matching" : "no",
i->i_at);
errs++;
}
--- 948,966 ----
int
crosscheck(void)
{
+ struct pspec *p;
struct devi *i;
struct config *cf;
int errs;
errs = 0;
TAILQ_FOREACH(i, &alldevi, i_next) {
! if ((p = i->i_pspec) == NULL || hasparent(i))
continue;
xerror(conffile, i->i_lineno,
"%s at %s is orphaned", i->i_name, i->i_at);
(void)fprintf(stderr, " (%s %s declared)\n",
! p->p_atunit == WILD ? "nothing matching" : "no",
i->i_at);
errs++;
}
Index: usr.sbin/config/mkioconf.c
===================================================================
RCS file: /cvsroot/syssrc/usr.sbin/config/mkioconf.c,v
retrieving revision 1.61
diff -c -r1.61 mkioconf.c
*** usr.sbin/config/mkioconf.c 2002/09/11 06:20:09 1.61
--- usr.sbin/config/mkioconf.c 2002/09/25 15:13:32
***************
*** 62,68 ****
static int emithdr(FILE *);
static int emitloc(FILE *);
static int emitpseudo(FILE *);
! static int emitpv(FILE *);
static int emitroots(FILE *);
static int emitvfslist(FILE *);
static int emitname2blk(FILE *);
--- 62,68 ----
static int emithdr(FILE *);
static int emitloc(FILE *);
static int emitpseudo(FILE *);
! static int emitparents(FILE *);
static int emitroots(FILE *);
static int emitvfslist(FILE *);
static int emitname2blk(FILE *);
***************
*** 91,98 ****
}
v = emithdr(fp);
if (v != 0 || emitcfdrivers(fp) || emitexterns(fp) || emitloc(fp) ||
! emitpv(fp) || emitcfdata(fp) || emitroots(fp) || emitpseudo(fp) ||
! emitvfslist(fp) || (do_devsw ? 0 : emitname2blk(fp))) {
if (v >= 0)
(void)fprintf(stderr,
"config: error writing ioconf.c: %s\n",
--- 91,99 ----
}
v = emithdr(fp);
if (v != 0 || emitcfdrivers(fp) || emitexterns(fp) || emitloc(fp) ||
! emitparents(fp) || emitcfdata(fp) || emitroots(fp) ||
! emitpseudo(fp) || emitvfslist(fp) ||
! (do_devsw ? 0 : emitname2blk(fp))) {
if (v >= 0)
(void)fprintf(stderr,
"config: error writing ioconf.c: %s\n",
***************
*** 168,187 ****
emitcfdrivers(FILE *fp)
{
struct devbase *d;
NEWLINE;
TAILQ_FOREACH(d, &allbases, d_next) {
if (!devbase_has_instances(d, WILD))
continue;
if (fprintf(fp, "struct cfdriver %s_cd = {\n",
d->d_name) < 0)
return (1);
! if (fprintf(fp, "\tNULL, \"%s\", %s\n",
d->d_name, d->d_classattr != NULL ?
d->d_classattr->a_devclass : "DV_DULL") < 0)
return (1);
! if (fprintf(fp, "};\n\n") < 0)
return (1);
}
return (0);
}
--- 169,210 ----
emitcfdrivers(FILE *fp)
{
struct devbase *d;
+ struct nvlist *nv;
+ struct attr *a;
+ int has_iattrs;
NEWLINE;
TAILQ_FOREACH(d, &allbases, d_next) {
if (!devbase_has_instances(d, WILD))
continue;
+ has_iattrs = 0;
+ for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
+ a = nv->nv_ptr;
+ if (a->a_iattr == 0)
+ continue;
+ if (has_iattrs == 0 &&
+ fprintf(fp, "static const char *%s_attrs[] = { ",
+ d->d_name) < 0)
+ return (1);
+ has_iattrs = 1;
+ if (fprintf(fp, "\"%s\", ", a->a_name) < 0)
+ return (1);
+ }
+ if (has_iattrs && fprintf(fp, "NULL };\n") < 0)
+ return (1);
if (fprintf(fp, "struct cfdriver %s_cd = {\n",
d->d_name) < 0)
return (1);
! if (fprintf(fp, "\tNULL, \"%s\", %s, 0, ",
d->d_name, d->d_classattr != NULL ?
d->d_classattr->a_devclass : "DV_DULL") < 0)
+ return (1);
+ if (has_iattrs && fprintf(fp, "%s_attrs", d->d_name) < 0)
return (1);
! else if (has_iattrs == 0 && fprintf(fp, "NULL") < 0)
return (1);
+ if (fprintf(fp, "\n};\n\n") < 0)
+ return (1);
}
return (0);
}
***************
*** 261,283 ****
}
/*
! * Emit global parents-vector.
*/
static int
! emitpv(FILE *fp)
{
! int i;
! if (parents.used == 0)
! return (0);
!
! if (fprintf(fp, "\n/* parent vectors */\n\
! static short pv[%d] = {", parents.used) < 0)
! return (1);
! for (i = 0; i < parents.used; i++)
! if (fprintf(fp, "%s%d,", SEP(i, 16), parents.vec[i]) < 0)
return (1);
! return (fprintf(fp, "\n};\n") < 0);
}
/*
--- 284,317 ----
}
/*
! * Emit static parent data.
*/
static int
! emitparents(FILE *fp)
{
! struct pspec *p;
! NEWLINE;
! TAILQ_FOREACH(p, &allpspecs, p_list) {
! if (p->p_devs == NULL)
! continue;
! if (fprintf(fp,
! "static const struct cfparent pspec%d = {\n", p->p_inst) < 0)
return (1);
! if (fprintf(fp, "\t\"%s\", ", p->p_iattr->a_name) < 0)
! return (1);
! if (p->p_atdev != NULL) {
! if (fprintf(fp, "\"%s\", %d", p->p_atdev->d_name,
! p->p_atunit == WILD ? -1
! : p->p_atunit) < 0)
! return (1);
! } else if (fprintf(fp, "NULL, 0") < 0)
! return (1);
! if (fprintf(fp, "\n};\n") < 0)
! return (1);
! }
!
! return (0);
}
/*
***************
*** 286,292 ****
static int
emitcfdata(FILE *fp)
{
! struct devi **p, *i, **par;
int unit, v;
const char *state, *basename, *attachment;
struct nvlist *nv;
--- 320,327 ----
static int
emitcfdata(FILE *fp)
{
! struct devi **p, *i;
! struct pspec *ps;
int unit, v;
const char *state, *basename, *attachment;
struct nvlist *nv;
***************
*** 300,332 ****
#define STAR FSTATE_STAR\n\
\n\
struct cfdata cfdata[] = {\n\
! /* attachment driver unit state loc flags parents\n\
locnames */\n") < 0)
return (1);
for (p = packed; (i = *p) != NULL; p++) {
/* the description */
if (fprintf(fp, "/*%3d: %s at ", i->i_cfindex, i->i_name) < 0)
return (1);
! par = i->i_parents;
! for (v = 0; v < i->i_pvlen; v++)
! if (fprintf(fp, "%s%s", v == 0 ? "" : "|",
! i->i_parents[v]->i_name) < 0)
! return (1);
! if (v == 0 && fputs("root", fp) < 0)
! return (1);
! a = i->i_atattr;
! for (nv = a->a_locs, v = 0; nv != NULL; nv = nv->nv_next, v++) {
! if (ARRNAME(nv->nv_name, lastname)) {
! if (fprintf(fp, " %s %s",
! nv->nv_name, i->i_locs[v]) < 0)
return (1);
} else {
! if (fprintf(fp, " %s %s",
! nv->nv_name, i->i_locs[v]) < 0)
return (1);
- lastname = nv->nv_name;
}
! }
if (fputs(" */\n", fp) < 0)
return (-1);
--- 335,379 ----
#define STAR FSTATE_STAR\n\
\n\
struct cfdata cfdata[] = {\n\
! /* attachment driver unit state loc flags pspec\n\
locnames */\n") < 0)
return (1);
for (p = packed; (i = *p) != NULL; p++) {
/* the description */
if (fprintf(fp, "/*%3d: %s at ", i->i_cfindex, i->i_name) < 0)
return (1);
! if ((ps = i->i_pspec) != NULL) {
! if (ps->p_atdev != NULL &&
! ps->p_atunit != WILD) {
! if (fprintf(fp, "%s%d", ps->p_atdev->d_name,
! ps->p_atunit) < 0)
! return (1);
! } else if (ps->p_atdev != NULL) {
! if (fprintf(fp, "%s?", ps->p_atdev->d_name) < 0)
return (1);
} else {
! if (fprintf(fp, "%s?", ps->p_iattr->a_name) < 0)
return (1);
}
!
! a = ps->p_iattr;
! for (nv = a->a_locs, v = 0; nv != NULL;
! nv = nv->nv_next, v++) {
! if (ARRNAME(nv->nv_name, lastname)) {
! if (fprintf(fp, " %s %s",
! nv->nv_name, i->i_locs[v]) < 0)
! return (1);
! } else {
! if (fprintf(fp, " %s %s",
! nv->nv_name,
! i->i_locs[v]) < 0)
! return (1);
! lastname = nv->nv_name;
! }
! }
! } else if (fputs("root", fp) < 0)
! return (1);
!
if (fputs(" */\n", fp) < 0)
return (-1);
***************
*** 345,357 ****
loc = locbuf;
} else
loc = "loc";
! if (fprintf(fp, "\
! {&%s_ca,%s&%s_cd,%s%2d, %s, %7s, %#6x, pv+%2d,\n\
! %scf_locnames},\n",
! attachment, strlen(attachment) < 6 ? "\t\t" : "\t",
! basename, strlen(basename) < 3 ? "\t\t" : "\t", unit,
! state, loc, i->i_cfflags, i->i_pvoff,
! a->a_locs ? a->a_name : "null") < 0)
return (1);
}
return (fputs(" {0}\n};\n", fp) < 0);
--- 392,411 ----
loc = locbuf;
} else
loc = "loc";
! if (fprintf(fp, " {&%s_ca,%s&%s_cd,%s%2d, %s, %7s, %#6x, ",
! attachment, strlen(attachment) < 6 ? "\t\t"
! : "\t",
! basename, strlen(basename) < 3 ? "\t\t"
! : "\t", unit,
! state, loc, i->i_cfflags) < 0)
! return (1);
! if (ps != NULL) {
! if (fprintf(fp, "&pspec%d,\n", ps->p_inst) < 0)
! return (1);
! } else if (fputs("NULL,", fp) < 0)
! return (1);
! if (fprintf(fp, " %scf_locnames},\n",
! a->a_locs ? a->a_name : "null") < 0)
return (1);
}
return (fputs(" {0}\n};\n", fp) < 0);
Index: usr.sbin/config/pack.c
===================================================================
RCS file: /cvsroot/syssrc/usr.sbin/config/pack.c,v
retrieving revision 1.12
diff -c -r1.12 pack.c
*** usr.sbin/config/pack.c 2002/06/05 10:56:19 1.12
--- usr.sbin/config/pack.c 2002/09/25 15:13:32
***************
*** 52,64 ****
/*
* Packing. We have three separate kinds of packing here.
*
! * First, we pack device instances, to collapse things like
*
- * uba0 at sbi0 nexus ?
- * uba0 at bi0 nexus ?
- *
- * into a single instance that is "at sbi0 or bi0".
- *
* Second, we pack locators. Given something like
*
* hp0 at mba0 drive 0
--- 52,59 ----
/*
* Packing. We have three separate kinds of packing here.
*
! * First, we pack device instances which have identical parent specs.
*
* Second, we pack locators. Given something like
*
* hp0 at mba0 drive 0
***************
*** 72,87 ****
* locators whose value is 0 and three whose value is -1. Rather than
* emitting six integers, we emit just two.
*
- * Finally, we pack parent vectors. This is very much like packing
- * locators. Unlike locators, however, parent vectors are always
- * terminated by -1 (rather like the way C strings always end with
- * a NUL).
- *
* When packing locators, we would like to find sequences such as
* {1 2 3} {2 3 4} {3} {4 5}
* and turn this into the flat sequence {1 2 3 4 5}, with each subsequence
* given by the appropriate offset (here 0, 1, 2, and 3 respectively).
- * When we pack parent vectors, overlap of this sort is impossible.
* Non-overlapping packing is much easier, and so we use that here
* and miss out on the chance to squeeze the locator sequence optimally.
* (So it goes.)
--- 67,76 ----
***************
*** 99,165 ****
static struct tails *tails[TAILHSIZE];
static int locspace;
- static int pvecspace;
- static int longest_pvec;
static void packdevi(void);
static void packlocs(void);
- static void packpvec(void);
- static void addparents(struct devi *src, struct devi *dst);
- static int nparents(struct devi **, struct devbase *, int);
static int sameas(struct devi *, struct devi *);
static int findvec(const void *, int, int, vec_cmp_func, int);
static int samelocs(const void *, int, int);
static int addlocs(const char **, int);
static int loclencmp(const void *, const void *);
- static int samepv(const void *, int, int);
- static int addpv(short *, int);
- static int pvlencmp(const void *, const void *);
static void resettails(void);
void
pack(void)
{
struct devi *i;
- int n;
/* Pack instances and make parent vectors. */
packdevi();
/*
* Now that we know what we have, find upper limits on space
! * needed for the loc[] and pv[] tables, and find the longest
! * single pvec. The loc and pv table sizes are bounded by
* what we would get if no packing occurred.
*/
! locspace = pvecspace = 0;
TAILQ_FOREACH(i, &alldevi, i_next) {
if (i->i_collapsed)
continue;
! locspace += i->i_atattr->a_loclen;
! n = i->i_pvlen + 1;
! if (n > longest_pvec)
! longest_pvec = n;
! pvecspace += n;
}
/* Allocate and pack loc[]. */
locators.vec = emalloc(locspace * sizeof(*locators.vec));
locators.used = 0;
packlocs();
-
- /* Allocate and pack pv[]. */
- parents.vec = emalloc(pvecspace * sizeof(*parents.vec));
- parents.used = 0;
- packpvec();
}
/*
! * Pack instances together wherever possible. When everything is
! * packed, go back and set up the parents for each. We must do this
! * on a second pass because during the first one, we do not know which,
! * if any, of the parents will collapse during packing.
*/
void
packdevi(void)
--- 88,135 ----
static struct tails *tails[TAILHSIZE];
static int locspace;
static void packdevi(void);
static void packlocs(void);
static int sameas(struct devi *, struct devi *);
static int findvec(const void *, int, int, vec_cmp_func, int);
static int samelocs(const void *, int, int);
static int addlocs(const char **, int);
static int loclencmp(const void *, const void *);
static void resettails(void);
void
pack(void)
{
+ struct pspec *p;
struct devi *i;
/* Pack instances and make parent vectors. */
packdevi();
/*
* Now that we know what we have, find upper limits on space
! * needed for the loc[] table. The loc table size is bounded by
* what we would get if no packing occurred.
*/
! locspace = 0;
TAILQ_FOREACH(i, &alldevi, i_next) {
if (i->i_collapsed)
continue;
! if ((p = i->i_pspec) == NULL)
! continue;
! locspace += p->p_iattr->a_loclen;
}
/* Allocate and pack loc[]. */
locators.vec = emalloc(locspace * sizeof(*locators.vec));
locators.used = 0;
packlocs();
}
/*
! * Pack device instances together wherever possible.
*/
void
packdevi(void)
***************
*** 211,218 ****
for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
m = n;
for (l = i; l != NULL; l = l->i_alias) {
- l->i_pvlen = 0;
- l->i_pvoff = -1;
l->i_locoff = -1;
/* try to find an equivalent for l */
for (j = m; j < n; j++) {
--- 181,186 ----
***************
*** 226,233 ****
/* could not find a suitable alias */
l->i_collapsed = 0;
l->i_cfindex = n;
- l->i_parents = emalloc(sizeof(*l->i_parents));
- l->i_parents[0] = NULL;
packed[n++] = l;
nextalias:;
}
--- 194,199 ----
***************
*** 235,365 ****
}
npacked = n;
packed[n] = NULL;
- TAILQ_FOREACH(i, &alldevi, i_next) {
- addparents(i, packed[i->i_cfindex]);
- }
}
/*
* Return true if two aliases are "the same". In this case, they need
! * to attach via the same attribute, have the same config flags, and
! * have the same locators.
*/
static int
sameas(struct devi *i1, struct devi *i2)
{
const char **p1, **p2;
! if (i1->i_atattr != i2->i_atattr)
return (0);
if (i1->i_cfflags != i2->i_cfflags)
return (0);
for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++)
if (*p1++ == 0)
return (1);
! return 0;
}
- /*
- * Add the parents associated with "src" to the (presumably uncollapsed)
- * instance "dst".
- */
static void
- addparents(struct devi *src, struct devi *dst)
- {
- struct nvlist *nv;
- struct devi *i, **p, **q;
- int j, n, old, new, ndup;
-
- if (dst->i_collapsed)
- panic("addparents() i_collapsed");
-
- /* Collect up list of parents to add. */
- if (src->i_at == NULL) /* none, 'cuz "at root" */
- return;
- if (src->i_atdev != NULL) {
- n = nparents(NULL, src->i_atdev, src->i_atunit);
- p = emalloc(n * sizeof *p);
- if (n == 0)
- return;
- (void)nparents(p, src->i_atdev, src->i_atunit);
- } else {
- n = 0;
- for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
- n += nparents(NULL, nv->nv_ptr, src->i_atunit);
- if (n == 0)
- return;
- p = emalloc(n * sizeof *p);
- n = 0;
- for (nv = src->i_atattr->a_refs; nv != NULL; nv = nv->nv_next)
- n += nparents(p + n, nv->nv_ptr, src->i_atunit);
- }
- /* Now elide duplicates. */
- ndup = 0;
- for (j = 0; j < n; j++) {
- i = p[j];
- for (q = dst->i_parents; *q != NULL; q++) {
- if (*q == i) {
- ndup++;
- p[j] = NULL;
- break;
- }
- }
- }
- /* Finally, add all the non-duplicates. */
- old = dst->i_pvlen;
- new = old + (n - ndup);
- if (old > new)
- panic("addparents() old > new");
- if (old == new) {
- free(p);
- return;
- }
- dst->i_parents = q = erealloc(dst->i_parents, (new + 1) * sizeof(*q));
- dst->i_pvlen = new;
- q[new] = NULL;
- q += old;
- for (j = 0; j < n; j++)
- if (p[j] != NULL)
- *q++ = p[j];
- free(p);
- }
-
- /*
- * Count up parents, and optionally store pointers to each.
- */
- static int
- nparents(struct devi **p, struct devbase *dev, int unit)
- {
- struct devi *i, *l;
- int n;
-
- n = 0;
- /* for each instance ... */
- for (i = dev->d_ihead; i != NULL; i = i->i_bsame) {
- /* ... take each un-collapsed alias */
- for (l = i; l != NULL; l = l->i_alias) {
- if (!l->i_collapsed &&
- (unit == WILD || unit == l->i_unit)) {
- if (p != NULL)
- *p++ = l;
- n++;
- }
- }
- }
- return (n);
- }
-
- static void
packlocs(void)
{
struct devi **p, *i;
int l,o;
extern int Pflag;
qsort(packed, npacked, sizeof *packed, loclencmp);
for (p = packed; (i = *p) != NULL; p++) {
! if ((l = i->i_atattr->a_loclen) > 0) {
if (Pflag) {
o = findvec(i->i_locs,
LOCHASH(i->i_locs[l - 1]), l,
--- 201,240 ----
}
npacked = n;
packed[n] = NULL;
}
/*
* Return true if two aliases are "the same". In this case, they need
! * to have the same parent spec, have the same config flags, and have
! * the same locators.
*/
static int
sameas(struct devi *i1, struct devi *i2)
{
const char **p1, **p2;
! if (i1->i_pspec != i2->i_pspec)
return (0);
if (i1->i_cfflags != i2->i_cfflags)
return (0);
for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++)
if (*p1++ == 0)
return (1);
! return (0);
}
static void
packlocs(void)
{
+ struct pspec *ps;
struct devi **p, *i;
int l,o;
extern int Pflag;
qsort(packed, npacked, sizeof *packed, loclencmp);
for (p = packed; (i = *p) != NULL; p++) {
! if ((ps = i->i_pspec) != NULL &&
! (l = ps->p_iattr->a_loclen) > 0) {
if (Pflag) {
o = findvec(i->i_locs,
LOCHASH(i->i_locs[l - 1]), l,
***************
*** 374,404 ****
resettails();
}
- static void
- packpvec(void)
- {
- struct devi **p, *i, **par;
- int l, v, o;
- short *vec;
-
- vec = emalloc(longest_pvec * sizeof(*vec));
- qsort(packed, npacked, sizeof *packed, pvlencmp);
- for (p = packed; (i = *p) != NULL; p++) {
- l = i->i_pvlen;
- if (l > longest_pvec) panic("packpvec");
- par = i->i_parents;
- for (v = 0; v < l; v++)
- vec[v] = par[v]->i_cfindex;
- if (l == 0 ||
- (o = findvec(vec, PVHASH(vec[l - 1]), l,
- samepv, parents.used)) < 0)
- o = addpv(vec, l);
- i->i_pvoff = o;
- }
- free(vec);
- resettails();
- }
-
/*
* Return the index at which the given vector already exists, or -1
* if it is not anywhere in the current set. If we return -1, we assume
--- 249,254 ----
***************
*** 462,529 ****
static int
loclencmp(const void *a, const void *b)
{
int l1, l2;
-
- l1 = (*(struct devi **)a)->i_atattr->a_loclen;
- l2 = (*(struct devi **)b)->i_atattr->a_loclen;
- return (l2 - l1);
- }
-
- /*
- * Comparison function for parent vectors.
- */
- static int
- samepv(const void *ptr, int off, int len)
- {
- short *p, *q;
-
- for (p = &parents.vec[off], q = (short *)ptr; --len >= 0;)
- if (*p++ != *q++)
- return (0); /* different */
- return (1); /* same */
- }
! /*
! * Add the given parent vectors at the end of the global pv[] table.
! */
! static int
! addpv(short *pv, int len)
! {
! short *p;
! int ret;
! static int firstend = -1;
!
! /*
! * If the vector is empty, reuse the first -1. It will be
! * there if there are any nonempty vectors at all, since we
! * do the longest first. If there are no nonempty vectors,
! * something is probably wrong, but we will ignore that here.
! */
! if (len == 0 && firstend >= 0)
! return (firstend);
! len++; /* account for trailing -1 */
! ret = parents.used;
! if ((parents.used = ret + len) > pvecspace)
! panic("addpv: overrun");
! for (p = &parents.vec[ret]; --len > 0;)
! *p++ = *pv++;
! *p = -1;
! if (firstend < 0)
! firstend = parents.used - 1;
! return (ret);
! }
! /*
! * Comparison function for qsort-by-parent-vector-length, longest first.
! * We rashly assume that subtraction of these lengths does not overflow.
! */
! static int
! pvlencmp(const void *a, const void *b)
! {
! int l1, l2;
- l1 = (*(struct devi **)a)->i_pvlen;
- l2 = (*(struct devi **)b)->i_pvlen;
return (l2 - l1);
}
--- 312,326 ----
static int
loclencmp(const void *a, const void *b)
{
+ struct pspec *p1, *p2;
int l1, l2;
! p1 = (*(struct devi **)a)->i_pspec;
! l1 = p1 != NULL ? p1->p_iattr->a_loclen : 0;
! p2 = (*(struct devi **)b)->i_pspec;
! l2 = p2 != NULL ? p2->p_iattr->a_loclen : 0;
return (l2 - l1);
}
Index: usr.sbin/config/sem.c
===================================================================
RCS file: /cvsroot/syssrc/usr.sbin/config/sem.c,v
retrieving revision 1.32
diff -c -r1.32 sem.c
*** usr.sbin/config/sem.c 2002/09/11 06:20:10 1.32
--- usr.sbin/config/sem.c 2002/09/25 15:13:33
***************
*** 73,78 ****
--- 73,79 ----
static struct nvlist *addtoattr(struct nvlist *, struct devbase *);
static int resolve(struct nvlist **, const char *, const char *,
struct nvlist *, int);
+ static struct pspec *getpspec(struct attr *, struct devbase *, int);
static struct devi *newdevi(const char *, int, struct devbase *d);
static struct devi *getdevi(const char *);
static const char *concat(const char *, int);
***************
*** 98,103 ****
--- 99,106 ----
TAILQ_INIT(&alldevas);
+ TAILQ_INIT(&allpspecs);
+
cfhashtab = ht_new();
TAILQ_INIT(&allcf);
***************
*** 802,809 ****
i->i_asame = NULL;
i->i_alias = NULL;
i->i_at = NULL;
! i->i_atattr = NULL;
! i->i_atdev = NULL;
i->i_atdeva = NULL;
i->i_locs = NULL;
i->i_cfflags = 0;
--- 805,811 ----
i->i_asame = NULL;
i->i_alias = NULL;
i->i_at = NULL;
! i->i_pspec = NULL;
i->i_atdeva = NULL;
i->i_locs = NULL;
i->i_cfflags = 0;
***************
*** 821,826 ****
--- 823,829 ----
adddev(const char *name, const char *at, struct nvlist *loclist, int flags)
{
struct devi *i; /* the new instance */
+ struct pspec *p; /* and its pspec */
struct attr *attr; /* attribute that allows attach */
struct devbase *ib; /* i->i_base */
struct devbase *ab; /* not NULL => at another dev */
***************
*** 835,840 ****
--- 838,844 ----
iba = NULL;
if (at == NULL) {
/* "at root" */
+ p = NULL;
if ((i = getdevi(name)) == NULL)
goto bad;
/*
***************
*** 863,869 ****
if ((i = getdevi(name)) == NULL)
goto bad;
ib = i->i_base;
- cp = intern(atbuf);
/*
* Devices can attach to two types of things: Attributes,
--- 867,872 ----
***************
*** 884,889 ****
--- 887,893 ----
* but is actually named in the config file, we still
* have to remember its devbase.
*/
+ cp = intern(atbuf);
/* Figure out parent's devbase, to satisfy case (3). */
ab = ht_lookup(devbasetab, cp);
***************
*** 922,927 ****
--- 926,938 ----
goto bad;
findattachment:
+ /*
+ * Find the parent spec. If a matching one has not yet been
+ * created, create one.
+ */
+ p = getpspec(attr, ab, atunit);
+ p->p_devs = newnv(NULL, NULL, i, 0, p->p_devs);
+
/* find out which attachment it uses */
hit = 0;
for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame)
***************
*** 935,944 ****
if ((i->i_locs = fixloc(name, attr, loclist)) == NULL)
goto bad;
i->i_at = at;
! i->i_atattr = attr;
! i->i_atdev = ab;
i->i_atdeva = iba;
- i->i_atunit = atunit;
i->i_cfflags = flags;
*iba->d_ipp = i;
--- 946,953 ----
if ((i->i_locs = fixloc(name, attr, loclist)) == NULL)
goto bad;
i->i_at = at;
! i->i_pspec = p;
i->i_atdeva = iba;
i->i_cfflags = flags;
*iba->d_ipp = i;
***************
*** 1086,1091 ****
--- 1095,1128 ----
TAILQ_FOREACH(i, &allpseudo, i_next)
selectbase(i->i_base, NULL);
+ }
+
+ /*
+ * Look up a parent spec, creating a new one if it does not exist.
+ */
+ static struct pspec *
+ getpspec(struct attr *attr, struct devbase *ab, int atunit)
+ {
+ struct pspec *p;
+
+ TAILQ_FOREACH(p, &allpspecs, p_list) {
+ if (p->p_iattr == attr &&
+ p->p_atdev == ab &&
+ p->p_atunit == atunit)
+ return (p);
+ }
+
+ p = emalloc(sizeof(*p));
+ memset(p, 0, sizeof(*p));
+
+ p->p_iattr = attr;
+ p->p_atdev = ab;
+ p->p_atunit = atunit;
+ p->p_inst = npspecs++;
+
+ TAILQ_INSERT_TAIL(&allpspecs, p, p_list);
+
+ return (p);
}
/*
--ZGiS0Q5IWpPtfppv--