| From ec00ee75656cd8817b0c54e2184a313b42955c82 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 20 Nov 2020 10:09:39 +0100 |
| Subject: s390/qeth: fix tear down of async TX buffers |
| |
| From: Julian Wiedmann <jwi@linux.ibm.com> |
| |
| [ Upstream commit 7ed10e16e50daf74460f54bc922e27c6863c8d61 ] |
| |
| When qeth_iqd_tx_complete() detects that a TX buffer requires additional |
| async completion via QAOB, it might fail to replace the queue entry's |
| metadata (and ends up triggering recovery). |
| |
| Assume now that the device gets torn down, overruling the recovery. |
| If the QAOB notification then arrives before the tear down has |
| sufficiently progressed, the buffer state is changed to |
| QETH_QDIO_BUF_HANDLED_DELAYED by qeth_qdio_handle_aob(). |
| |
| The tear down code calls qeth_drain_output_queue(), where |
| qeth_cleanup_handled_pending() will then attempt to replace such a |
| buffer _again_. If it succeeds this time, the buffer ends up dangling in |
| its replacement's ->next_pending list ... where it will never be freed, |
| since there's no further call to qeth_cleanup_handled_pending(). |
| |
| But the second attempt isn't actually needed, we can simply leave the |
| buffer on the queue and re-use it after a potential recovery has |
| completed. The qeth_clear_output_buffer() in qeth_drain_output_queue() |
| will ensure that it's in a clean state again. |
| |
| Fixes: 72861ae792c2 ("qeth: recovery through asynchronous delivery") |
| Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/s390/net/qeth_core_main.c | 6 ------ |
| 1 file changed, 6 deletions(-) |
| |
| diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c |
| index f07e73eb37ebb..fad1c46d4b0e1 100644 |
| --- a/drivers/s390/net/qeth_core_main.c |
| +++ b/drivers/s390/net/qeth_core_main.c |
| @@ -426,12 +426,6 @@ static void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, int bidx, |
| |
| } |
| } |
| - if (forced_cleanup && (atomic_read(&(q->bufs[bidx]->state)) == |
| - QETH_QDIO_BUF_HANDLED_DELAYED)) { |
| - /* for recovery situations */ |
| - qeth_init_qdio_out_buf(q, bidx); |
| - QETH_CARD_TEXT(q->card, 2, "clprecov"); |
| - } |
| } |
| |
| |
| -- |
| 2.27.0 |
| |