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:
parent
d4ca0466e8
commit
8b70574df1
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue