| From 23ca1a2e075607ddd02202a624e71462296dd0fc Mon Sep 17 00:00:00 2001 |
| From: Julian Wiedmann <jwi@linux.ibm.com> |
| Date: Mon, 23 Dec 2019 15:03:21 +0100 |
| Subject: [PATCH] s390/qeth: fix qdio teardown after early init error |
| |
| commit 8b5026bc16938920e4780b9094c3bf20e1e0939d upstream. |
| |
| qeth_l?_set_online() goes through a number of initialization steps, and |
| on any error uses qeth_l?_stop_card() to tear down the residual state. |
| |
| The first initialization step is qeth_core_hardsetup_card(). When this |
| fails after having established a QDIO context on the device |
| (ie. somewhere after qeth_mpc_initialize()), qeth_l?_stop_card() doesn't |
| shut down this QDIO context again (since the card state hasn't |
| progressed from DOWN at this stage). |
| |
| Even worse, we then call qdio_free() as final teardown step to free the |
| QDIO data structures - while some of them are still hooked into wider |
| QDIO infrastructure such as the IRQ list. This is inevitably followed by |
| use-after-frees and other nastyness. |
| |
| Fix this by unconditionally calling qeth_qdio_clear_card() to shut down |
| the QDIO context, and also to halt/clear any pending activity on the |
| various IO channels. |
| Remove the naive attempt at handling the teardown in |
| qeth_mpc_initialize(), it clearly doesn't suffice and we're handling it |
| properly now in the wider teardown code. |
| |
| Fixes: 4a71df50047f ("qeth: new qeth device driver") |
| Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c |
| index 720d750c6877..278444124adf 100644 |
| --- a/drivers/s390/net/qeth_core_main.c |
| +++ b/drivers/s390/net/qeth_core_main.c |
| @@ -2538,50 +2538,46 @@ static int qeth_mpc_initialize(struct qeth_card *card) |
| rc = qeth_cm_enable(card); |
| if (rc) { |
| QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
| - goto out_qdio; |
| + return rc; |
| } |
| rc = qeth_cm_setup(card); |
| if (rc) { |
| QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); |
| - goto out_qdio; |
| + return rc; |
| } |
| rc = qeth_ulp_enable(card); |
| if (rc) { |
| QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); |
| - goto out_qdio; |
| + return rc; |
| } |
| rc = qeth_ulp_setup(card); |
| if (rc) { |
| QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); |
| - goto out_qdio; |
| + return rc; |
| } |
| rc = qeth_alloc_qdio_queues(card); |
| if (rc) { |
| QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); |
| - goto out_qdio; |
| + return rc; |
| } |
| rc = qeth_qdio_establish(card); |
| if (rc) { |
| QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); |
| qeth_free_qdio_queues(card); |
| - goto out_qdio; |
| + return rc; |
| } |
| rc = qeth_qdio_activate(card); |
| if (rc) { |
| QETH_DBF_TEXT_(SETUP, 2, "7err%d", rc); |
| - goto out_qdio; |
| + return rc; |
| } |
| rc = qeth_dm_act(card); |
| if (rc) { |
| QETH_DBF_TEXT_(SETUP, 2, "8err%d", rc); |
| - goto out_qdio; |
| + return rc; |
| } |
| |
| return 0; |
| -out_qdio: |
| - qeth_qdio_clear_card(card, !IS_IQD(card)); |
| - qdio_free(CARD_DDEV(card)); |
| - return rc; |
| } |
| |
| void qeth_print_status_message(struct qeth_card *card) |
| diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c |
| index a59e6e1c2642..2e2cf4f16067 100644 |
| --- a/drivers/s390/net/qeth_l2_main.c |
| +++ b/drivers/s390/net/qeth_l2_main.c |
| @@ -287,7 +287,6 @@ static void qeth_l2_stop_card(struct qeth_card *card) |
| card->state = CARD_STATE_HARDSETUP; |
| } |
| if (card->state == CARD_STATE_HARDSETUP) { |
| - qeth_qdio_clear_card(card, 0); |
| qeth_drain_output_queues(card); |
| qeth_clear_working_pool_list(card); |
| card->state = CARD_STATE_DOWN; |
| @@ -297,6 +296,7 @@ static void qeth_l2_stop_card(struct qeth_card *card) |
| qeth_clear_cmd_buffers(&card->write); |
| } |
| |
| + qeth_qdio_clear_card(card, 0); |
| flush_workqueue(card->event_wq); |
| card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; |
| card->info.promisc_mode = 0; |
| diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c |
| index a80b4ecc8c8e..7b898d4b2b02 100644 |
| --- a/drivers/s390/net/qeth_l3_main.c |
| +++ b/drivers/s390/net/qeth_l3_main.c |
| @@ -1431,7 +1431,6 @@ static void qeth_l3_stop_card(struct qeth_card *card) |
| card->state = CARD_STATE_HARDSETUP; |
| } |
| if (card->state == CARD_STATE_HARDSETUP) { |
| - qeth_qdio_clear_card(card, 0); |
| qeth_drain_output_queues(card); |
| qeth_clear_working_pool_list(card); |
| card->state = CARD_STATE_DOWN; |
| @@ -1441,6 +1440,7 @@ static void qeth_l3_stop_card(struct qeth_card *card) |
| qeth_clear_cmd_buffers(&card->write); |
| } |
| |
| + qeth_qdio_clear_card(card, 0); |
| flush_workqueue(card->event_wq); |
| card->info.promisc_mode = 0; |
| } |
| -- |
| 2.7.4 |
| |