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

Reply via email to