qeth: crash during reboot after failing online setting
authorUrsula Braun <braunu@de.ibm.com>
Wed, 29 Aug 2007 09:26:56 +0000 (11:26 +0200)
committerJeff Garzik <jeff@garzik.org>
Fri, 31 Aug 2007 10:52:58 +0000 (06:52 -0400)
Online setting of a qeth device may fail for instance because of:
- out-of-memory condition when allocating qdio queues
- IDX ACTIVATE problem
- ...
Such a device is still returned in a driver_for_each_device loop
processed in qeth_reboot_event(), which calls
qeth_clear_qdio_buffers(). Make sure qeth_clear_output_buffer() is
called only, if the qdio queues have been successfully allocated
during initialization of a qeth device.

Signed-off-by: Ursula Braun <braunu@de.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/s390/net/qeth_main.c

index 443cde1..45a8b9f 100644 (file)
@@ -3356,10 +3356,12 @@ out_freeoutq:
        while (i > 0)
                kfree(card->qdio.out_qs[--i]);
        kfree(card->qdio.out_qs);
+       card->qdio.out_qs = NULL;
 out_freepool:
        qeth_free_buffer_pool(card);
 out_freeinq:
        kfree(card->qdio.in_q);
+       card->qdio.in_q = NULL;
 out_nomem:
        atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED);
        return -ENOMEM;
@@ -3375,16 +3377,20 @@ qeth_free_qdio_buffers(struct qeth_card *card)
                QETH_QDIO_UNINITIALIZED)
                return;
        kfree(card->qdio.in_q);
+       card->qdio.in_q = NULL;
        /* inbound buffer pool */
        qeth_free_buffer_pool(card);
        /* free outbound qdio_qs */
-       for (i = 0; i < card->qdio.no_out_queues; ++i){
-               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
-                       qeth_clear_output_buffer(card->qdio.out_qs[i],
-                                       &card->qdio.out_qs[i]->bufs[j]);
-               kfree(card->qdio.out_qs[i]);
+       if (card->qdio.out_qs) {
+               for (i = 0; i < card->qdio.no_out_queues; ++i) {
+                       for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
+                               qeth_clear_output_buffer(card->qdio.out_qs[i],
+                                               &card->qdio.out_qs[i]->bufs[j]);
+                       kfree(card->qdio.out_qs[i]);
+               }
+               kfree(card->qdio.out_qs);
+               card->qdio.out_qs = NULL;
        }
-       kfree(card->qdio.out_qs);
 }
 
 static void
@@ -3395,7 +3401,7 @@ qeth_clear_qdio_buffers(struct qeth_card *card)
        QETH_DBF_TEXT(trace, 2, "clearqdbf");
        /* clear outbound buffers to free skbs */
        for (i = 0; i < card->qdio.no_out_queues; ++i)
-               if (card->qdio.out_qs[i]){
+               if (card->qdio.out_qs && card->qdio.out_qs[i]) {
                        for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
                                qeth_clear_output_buffer(card->qdio.out_qs[i],
                                                &card->qdio.out_qs[i]->bufs[j]);