summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2011-06-20 17:05:47 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2011-06-20 17:05:47 +0000
commitcc261b1574c30dd0d7cb42f3e94172e950f444cb (patch)
tree5ca9c00b7f65548a2f2473925b9d6aad64a79d21 /sys
parent346ec16a196f8c215a22811c7a6c9cce7004588b (diff)
serialize attach and detach of device sub-trees -- only one device
sub-tree may attach or detach at a time. attach and detach will sleep against each other. this is fixing (working around?) some bizzare corner cases that have been seen (but not fully diagnosed) where the device trees, disk registration subsystem, and other things could get messed up. one could argue though that this serialization is a very good thing; it is easier than adding piles of locks in various other places. ok matthew jsing
Diffstat (limited to 'sys')
-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