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().
This commit is contained in:
dyoung 2009-04-03 21:31:08 +00:00
parent 5e464841ab
commit 211e21b653
1 changed files with 22 additions and 10 deletions

View File

@ -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),