Add init/fini for components (modules etc.). These eat the standard

driver/attach/data typically present and once some locking is grown
in here, these routines can be made to fail or succeed a component
attachment/detachment atomically.
This commit is contained in:
pooka 2010-03-25 19:23:18 +00:00
parent d4ca0466e8
commit 8b70574df1
2 changed files with 157 additions and 22 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: subr_autoconf.c,v 1.203 2010/02/24 22:38:10 dyoung Exp $ */
/* $NetBSD: subr_autoconf.c,v 1.204 2010/03/25 19:23:18 pooka Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@ -77,7 +77,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.203 2010/02/24 22:38:10 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.204 2010/03/25 19:23:18 pooka Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
@ -237,6 +237,91 @@ static callout_t config_twiddle_ch;
static void sysctl_detach_setup(struct sysctllog **);
typedef int (*cfdriver_fn)(struct cfdriver *);
static int
frob_cfdrivervec(struct cfdriver * const *cfdriverv,
cfdriver_fn drv_do, cfdriver_fn drv_undo,
const char *style, bool dopanic)
{
void (*pr)(const char *, ...) = dopanic ? panic : printf;
int i = 0, error = 0, e2;
for (i = 0; cfdriverv[i] != NULL; i++) {
if ((error = drv_do(cfdriverv[i])) != 0) {
pr("configure: `%s' driver %s failed: %d",
cfdriverv[i]->cd_name, style, error);
goto bad;
}
}
KASSERT(error == 0);
return 0;
bad:
printf("\n");
for (i--; i >= 0; i--) {
e2 = drv_undo(cfdriverv[i]);
KASSERT(e2 == 0);
}
return error;
}
typedef int (*cfattach_fn)(const char *, struct cfattach *);
static int
frob_cfattachvec(const struct cfattachinit *cfattachv,
cfattach_fn att_do, cfattach_fn att_undo,
const char *style, bool dopanic)
{
const struct cfattachinit *cfai = NULL;
void (*pr)(const char *, ...) = dopanic ? panic : printf;
int j = 0, error = 0, e2;
for (cfai = &cfattachv[0]; cfai->cfai_name != NULL; cfai++) {
for (j = 0; cfai->cfai_list[j] != NULL; j++) {
if ((error = att_do(cfai->cfai_name,
cfai->cfai_list[j]) != 0)) {
pr("configure: attachment `%s' "
"of `%s' driver %s failed: %d",
cfai->cfai_list[j]->ca_name,
cfai->cfai_name, style, error);
goto bad;
}
}
}
KASSERT(error == 0);
return 0;
bad:
/*
* Rollback in reverse order. dunno if super-important, but
* do that anyway. Although the code looks a little like
* someone did a little integration (in the math sense).
*/
printf("\n");
if (cfai) {
bool last;
for (last = false; last == false; ) {
if (cfai == &cfattachv[0])
last = true;
for (j--; j >= 0; j--) {
e2 = att_undo(cfai->cfai_name,
cfai->cfai_list[j]);
KASSERT(e2 == 0);
}
if (!last) {
cfai--;
for (j = 0; cfai->cfai_list[j] != NULL; j++)
;
}
}
}
return error;
}
/*
* Initialize the autoconfiguration data structures. Normally this
* is done by configure(), but some platforms need to do this very
@ -245,8 +330,6 @@ static void sysctl_detach_setup(struct sysctllog **);
void
config_init(void)
{
const struct cfattachinit *cfai;
int i, j;
KASSERT(config_initialized == false);
@ -257,23 +340,10 @@ config_init(void)
callout_init(&config_twiddle_ch, CALLOUT_MPSAFE);
/* allcfdrivers is statically initialized. */
for (i = 0; cfdriver_list_initial[i] != NULL; i++) {
if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0)
panic("configure: duplicate `%s' drivers",
cfdriver_list_initial[i]->cd_name);
}
for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) {
for (j = 0; cfai->cfai_list[j] != NULL; j++) {
if (config_cfattach_attach(cfai->cfai_name,
cfai->cfai_list[j]) != 0)
panic("configure: duplicate `%s' attachment "
"of `%s' driver",
cfai->cfai_list[j]->ca_name,
cfai->cfai_name);
}
}
frob_cfdrivervec(cfdriver_list_initial,
config_cfdriver_attach, NULL, "bootstrap", true);
frob_cfattachvec(cfattachinit,
config_cfattach_attach, NULL, "bootstrap", true);
initcftable.ct_cfdata = cfdata;
TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
@ -281,6 +351,67 @@ config_init(void)
config_initialized = true;
}
/*
* Init or fini drivers and attachments. Either all or none
* are processed (via rollback). It would be nice if this were
* atomic to outside consumers, but with the current state of
* locking ...
*/
int
config_init_component(struct cfdriver * const *cfdriverv,
const struct cfattachinit *cfattachv, struct cfdata *cfdatav)
{
int error;
if ((error = frob_cfdrivervec(cfdriverv,
config_cfdriver_attach, config_cfdriver_detach, "init", false))!= 0)
return error;
if ((error = frob_cfattachvec(cfattachv,
config_cfattach_attach, config_cfattach_detach,
"init", false)) != 0) {
frob_cfdrivervec(cfdriverv,
config_cfdriver_detach, NULL, "init rollback", true);
return error;
}
if ((error = config_cfdata_attach(cfdatav, 1)) != 0) {
frob_cfattachvec(cfattachv,
config_cfattach_detach, NULL, "init rollback", true);
frob_cfdrivervec(cfdriverv,
config_cfdriver_detach, NULL, "init rollback", true);
return error;
}
return 0;
}
int
config_fini_component(struct cfdriver * const *cfdriverv,
const struct cfattachinit *cfattachv, struct cfdata *cfdatav)
{
int error;
if ((error = config_cfdata_detach(cfdatav)) != 0)
return error;
if ((error = frob_cfattachvec(cfattachv,
config_cfattach_detach, config_cfattach_attach,
"fini", false)) != 0) {
if (config_cfdata_attach(cfdatav, 0) != 0)
panic("config_cfdata fini rollback failed");
return error;
}
if ((error = frob_cfdrivervec(cfdriverv,
config_cfdriver_detach, config_cfdriver_attach,
"fini", false)) != 0) {
frob_cfattachvec(cfattachv,
config_cfattach_attach, NULL, "fini rollback", true);
if (config_cfdata_attach(cfdatav, 0) != 0)
panic("config_cfdata fini rollback failed");
return error;
}
return 0;
}
void
config_init_mi(void)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: device.h,v 1.135 2010/02/24 22:38:10 dyoung Exp $ */
/* $NetBSD: device.h,v 1.136 2010/03/25 19:23:18 pooka Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@ -431,6 +431,10 @@ int getdisksize(struct vnode *, uint64_t *, unsigned *);
int config_handle_wedges(struct device *, int);
void config_init(void);
int config_init_component(struct cfdriver *const*,
const struct cfattachinit *, struct cfdata *);
int config_fini_component(struct cfdriver *const*,
const struct cfattachinit *, struct cfdata *);
void config_init_mi(void);
void drvctl_init(void);