diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2011-06-20 17:05:47 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2011-06-20 17:05:47 +0000 |
commit | cc261b1574c30dd0d7cb42f3e94172e950f444cb (patch) | |
tree | 5ca9c00b7f65548a2f2473925b9d6aad64a79d21 /sys | |
parent | 346ec16a196f8c215a22811c7a6c9cce7004588b (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.c | 39 |
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 |