Module Name:    src
Committed By:   pooka
Date:           Thu Mar 25 19:23:18 UTC 2010

Modified Files:
        src/sys/kern: subr_autoconf.c
        src/sys/sys: device.h

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.203 -r1.204 src/sys/kern/subr_autoconf.c
cvs rdiff -u -r1.135 -r1.136 src/sys/sys/device.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/subr_autoconf.c
diff -u src/sys/kern/subr_autoconf.c:1.203 src/sys/kern/subr_autoconf.c:1.204
--- src/sys/kern/subr_autoconf.c:1.203	Wed Feb 24 22:38:10 2010
+++ src/sys/kern/subr_autoconf.c	Thu Mar 25 19:23:18 2010
@@ -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 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 @@
 void
 config_init(void)
 {
-	const struct cfattachinit *cfai;
-	int i, j;
 
 	KASSERT(config_initialized == false);
 
@@ -257,23 +340,10 @@
 
 	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_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)
 {

Index: src/sys/sys/device.h
diff -u src/sys/sys/device.h:1.135 src/sys/sys/device.h:1.136
--- src/sys/sys/device.h:1.135	Wed Feb 24 22:38:10 2010
+++ src/sys/sys/device.h	Thu Mar 25 19:23:18 2010
@@ -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 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);
 

Reply via email to