Module Name: src
Committed By: dyoung
Date: Fri Apr 3 21:31:08 UTC 2009
Modified Files:
src/sys/dev/ata: ata.c
Log Message:
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().
To generate a diff of this commit:
cvs rdiff -u -r1.103 -r1.104 src/sys/dev/ata/ata.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ata/ata.c
diff -u src/sys/dev/ata/ata.c:1.103 src/sys/dev/ata/ata.c:1.104
--- src/sys/dev/ata/ata.c:1.103 Thu Apr 2 00:09:32 2009
+++ src/sys/dev/ata/ata.c Fri Apr 3 21:31:08 2009
@@ -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 @@
}
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 @@
error = config_detach(dev, flags);
if (error)
goto out;
+ KASSERT(chp->atapibus == NULL);
}
/*
@@ -565,20 +568,23 @@
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 @@
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 @@
*/
if (child == chp->atapibus) {
chp->atapibus = NULL;
- return;
+ found = true;
}
/*
@@ -607,14 +614,19 @@
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),