diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2006-01-13 19:22:55 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2006-01-13 19:22:55 +0000 |
commit | 6e6cf05222ec1e4d570bd957df48308eaabd15d0 (patch) | |
tree | 329d55959b1ba6ae004075885ed955d9b5947720 /sys | |
parent | 190cf798b224fa02fcd735f6f6638b4cc23877c2 (diff) |
In config_detach_children(), after detaching a device, restart the device
list walk from its parent device, as the device which was following it may
have been one of its children, and thus gone as well. Found the hard way
using the strict queue macros.
Feedback and help toby@, ok deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/subr_autoconf.c | 40 |
1 files changed, 24 insertions, 16 deletions
diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c index bced38e75c3..fc58c93f7eb 100644 --- a/sys/kern/subr_autoconf.c +++ b/sys/kern/subr_autoconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_autoconf.c,v 1.41 2005/12/09 09:09:52 jsg Exp $ */ +/* $OpenBSD: subr_autoconf.c,v 1.42 2006/01/13 19:22:54 miod Exp $ */ /* $NetBSD: subr_autoconf.c,v 1.21 1996/04/04 06:06:18 cgd Exp $ */ /* @@ -716,24 +716,32 @@ config_pending_decr(void) int config_detach_children(struct device *parent, int flags) { - struct device *dev, *next_dev; - int rv = 0; + struct device *dev, *next_dev, *prev_dev; + int rv = 0; - /* The config_detach routine may sleep, meaning devices - may be added to the queue. However, all devices will - be added to the tail of the queue, the queue won't - be re-organized, and the subtree of parent here should be locked - for purposes of adding/removing children. - */ - for (dev = TAILQ_FIRST(&alldevs); - dev != NULL; dev = next_dev) { - next_dev = TAILQ_NEXT(dev, dv_list); - if (dev->dv_parent == parent && - (rv = config_detach(dev, flags))) - return (rv); + /* + * The config_detach routine may sleep, meaning devices + * may be added to the queue. However, all devices will + * be added to the tail of the queue, the queue won't + * be re-organized, and the subtree of parent here should be locked + * for purposes of adding/removing children. + * + * Note that we can not afford trying to walk the device list + * once - our ``next'' device might be a child of the device + * we are about to detach, so it would disappear. + * Just play it safe and restart from the parent. + */ + for (prev_dev = NULL, dev = TAILQ_FIRST(&alldevs); + dev != NULL; dev = next_dev) { + if (dev->dv_parent == parent) { + if ((rv = config_detach(dev, flags)) != 0) + return (rv); + next_dev = prev_dev ? prev_dev : TAILQ_FIRST(&alldevs); + } else + next_dev = TAILQ_NEXT(prev_dev = dev, dv_list); } - return (rv); + return (0); } int |