summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authordyoung <dyoung@NetBSD.org>2009-04-03 21:31:08 +0000
committerdyoung <dyoung@NetBSD.org>2009-04-03 21:31:08 +0000
commit211e21b653284b9e3e73b113efe786fd3b640c3f (patch)
treed1924f4e35fee2f5b82de9502b4a4d07f2cc35d2 /sys/dev
parent5e464841abc2cc507cc03043e254716018fce789 (diff)
Stop dereferencing a dangling device_t pointer and crashing: skip the
drives flagged DRIVE_ATAPI in atabus_activate(,DVACT_DEACTIVATE) just as we skip them in atabus_detach() and in atabus_childdetched(). Make atabus_detach() parallel attachment more closely by calling config_detach() on the child chp->ata_drives[i] instead of on chp->ch_drive[i].drv_softc. Assert that ata_drives[i] and ch_drive[i].drv_softc are equal, and set them both to NULL in atabus_childdetached().
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ata/ata.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/sys/dev/ata/ata.c b/sys/dev/ata/ata.c
index c338d497377..d674c3061da 100644
--- a/sys/dev/ata/ata.c
+++ b/sys/dev/ata/ata.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ata.c,v 1.103 2009/04/02 00:09:32 dyoung Exp $ */
+/* $NetBSD: ata.c,v 1.104 2009/04/03 21:31:08 dyoung Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.103 2009/04/02 00:09:32 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.104 2009/04/03 21:31:08 dyoung Exp $");
#include "opt_ata.h"
@@ -498,6 +498,8 @@ atabus_activate(device_t self, enum devact act)
}
for (i = 0; i < chp->ch_ndrive; i++) {
+ if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
+ continue;
if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
ATADEBUG_PRINT(("atabus_activate: %s: "
"deactivating %s\n", device_xname(self),
@@ -557,6 +559,7 @@ atabus_detach(device_t self, int flags)
error = config_detach(dev, flags);
if (error)
goto out;
+ KASSERT(chp->atapibus == NULL);
}
/*
@@ -565,20 +568,23 @@ atabus_detach(device_t self, int flags)
for (i = 0; i < chp->ch_ndrive; i++) {
if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
continue;
- if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
- ATADEBUG_PRINT(("atabus_detach: %s: detaching %s\n",
- device_xname(self), device_xname(dev)),
+ if ((dev = chp->ata_drives[i]) != NULL) {
+ ATADEBUG_PRINT(("%s.%d: %s: detaching %s\n", __func__,
+ __LINE__, device_xname(self), device_xname(dev)),
DEBUG_DETACH);
+ KASSERT(chp->ch_drive[i].drv_softc ==
+ chp->ata_drives[i]);
error = config_detach(dev, flags);
if (error)
goto out;
+ KASSERT(chp->ata_drives[i] == NULL);
}
}
out:
#ifdef ATADEBUG
if (dev != NULL && error != 0)
- ATADEBUG_PRINT(("atabus_detach: %s: error %d detaching %s\n",
+ ATADEBUG_PRINT(("%s: %s: error %d detaching %s\n", __func__,
device_xname(self), error, device_xname(dev)),
DEBUG_DETACH);
#endif /* ATADEBUG */
@@ -589,6 +595,7 @@ atabus_detach(device_t self, int flags)
void
atabus_childdetached(device_t self, device_t child)
{
+ bool found = false;
struct atabus_softc *sc = device_private(self);
struct ata_channel *chp = sc->sc_chan;
int i;
@@ -598,7 +605,7 @@ atabus_childdetached(device_t self, device_t child)
*/
if (child == chp->atapibus) {
chp->atapibus = NULL;
- return;
+ found = true;
}
/*
@@ -607,14 +614,19 @@ atabus_childdetached(device_t self, device_t child)
for (i = 0; i < chp->ch_ndrive; i++) {
if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
continue;
- if (child == chp->ch_drive[i].drv_softc) {
+ if (child == chp->ata_drives[i]) {
+ KASSERT(chp->ata_drives[i] ==
+ chp->ch_drive[i].drv_softc);
+ chp->ata_drives[i] = NULL;
chp->ch_drive[i].drv_softc = NULL;
chp->ch_drive[i].drive_flags = 0;
- return;
+ found = true;
}
}
- aprint_error_dev(self, "unknown child %p", (const void *)child);
+ if (!found)
+ panic("%s: unknown child %p", device_xname(self),
+ (const void *)child);
}
CFATTACH_DECL3_NEW(atabus, sizeof(struct atabus_softc),