summaryrefslogtreecommitdiff
path: root/sys/kern/subr_autoconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/subr_autoconf.c')
-rw-r--r--sys/kern/subr_autoconf.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c
index 8f641ee706d..57324b0bfb5 100644
--- a/sys/kern/subr_autoconf.c
+++ b/sys/kern/subr_autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_autoconf.c,v 1.64 2011/06/01 03:25:01 matthew Exp $ */
+/* $OpenBSD: subr_autoconf.c,v 1.65 2011/06/20 17:05:46 deraadt Exp $ */
/* $NetBSD: subr_autoconf.c,v 1.21 1996/04/04 06:06:18 cgd Exp $ */
/*
@@ -51,6 +51,7 @@
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/proc.h>
+#include <sys/mutex.h>
#include "hotplug.h"
@@ -100,6 +101,14 @@ struct devicelist alldevs; /* list of all devices */
__volatile int config_pending; /* semaphore for mountroot */
+struct mutex autoconf_attdet_mtx = MUTEX_INITIALIZER(IPL_HIGH);
+/*
+ * If > 0, devices are being attached and any thread which tries to
+ * detach will sleep; if < 0 devices are being detached and any
+ * thread which tries to attach will sleep.
+ */
+int autoconf_attdet;
+
/*
* Initialize autoconfiguration data structures. This occurs before console
* initialization as that might require use of this subsystem. Furthermore
@@ -339,6 +348,13 @@ config_attach(struct device *parent, void *match, void *aux, cfprint_t print)
struct cfattach *ca;
struct cftable *t;
+ mtx_enter(&autoconf_attdet_mtx);
+ while (autoconf_attdet < 0)
+ msleep(&autoconf_attdet, &autoconf_attdet_mtx,
+ PWAIT, "autoconf", 0);
+ autoconf_attdet++;
+ mtx_leave(&autoconf_attdet_mtx);
+
if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
dev = match;
cf = dev->dv_cfdata;
@@ -398,6 +414,11 @@ config_attach(struct device *parent, void *match, void *aux, cfprint_t print)
if (!cold)
hotplug_device_attach(cd->cd_class, dev->dv_xname);
#endif
+
+ mtx_enter(&autoconf_attdet_mtx);
+ if (--autoconf_attdet == 0)
+ wakeup(&autoconf_attdet);
+ mtx_leave(&autoconf_attdet_mtx);
return (dev);
}
@@ -495,6 +516,13 @@ config_detach(struct device *dev, int flags)
char devname[16];
#endif
+ mtx_enter(&autoconf_attdet_mtx);
+ while (autoconf_attdet > 0)
+ msleep(&autoconf_attdet, &autoconf_attdet_mtx,
+ PWAIT, "autoconf", 0);
+ autoconf_attdet--;
+ mtx_leave(&autoconf_attdet_mtx);
+
#if NHOTPLUG > 0
strlcpy(devname, dev->dv_xname, sizeof(devname));
#endif
@@ -529,7 +557,7 @@ config_detach(struct device *dev, int flags)
}
if (rv != 0) {
if ((flags & DETACH_FORCE) == 0)
- return (rv);
+ goto done;
else
panic("config_detach: forced detach of %s failed (%d)",
dev->dv_xname, rv);
@@ -611,7 +639,12 @@ config_detach(struct device *dev, int flags)
/*
* Return success.
*/
- return (0);
+done:
+ mtx_enter(&autoconf_attdet_mtx);
+ if (++autoconf_attdet == 0)
+ wakeup(&autoconf_attdet);
+ mtx_leave(&autoconf_attdet_mtx);
+ return (rv);
}
int