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:
parent
5e464841ab
commit
211e21b653
|
@ -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),
|
||||
|
|
Loading…
Reference in New Issue