summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorderaadt <deraadt@openbsd.org>2011-06-20 17:05:46 +0000
committerderaadt <deraadt@openbsd.org>2011-06-20 17:05:46 +0000
commitdc6499960f1abce9a2bb5341f1d54c92a08fe7e6 (patch)
tree759e41d19f6f5456fb96ccf9da61d3286539147f
parentfor now, move back to a private rw_lock rather than the disk_lock. (diff)
downloadwireguard-openbsd-dc6499960f1abce9a2bb5341f1d54c92a08fe7e6.tar.xz
wireguard-openbsd-dc6499960f1abce9a2bb5341f1d54c92a08fe7e6.zip
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
-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