| From e9bb8b32dc7195d7984c3c871ae283e9d9ca0300 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 30 Jul 2020 17:01:18 +0200 |
| Subject: s390/qeth: tolerate pre-filled RX buffer |
| |
| From: Julian Wiedmann <jwi@linux.ibm.com> |
| |
| [ Upstream commit eff73e16ee116f6eafa2be48fab42659a27cb453 ] |
| |
| When preparing a buffer for RX refill, tolerate that it already has a |
| pool_entry attached. Otherwise we could easily leak such a pool_entry |
| when re-driving the RX refill after an error (from eg. do_qdio()). |
| |
| This needs some minor adjustment in the code that drains RX buffer(s) |
| prior to RX refill and during teardown, so that ->pool_entry is NULLed |
| accordingly. |
| |
| 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: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/s390/net/qeth_core_main.c | 20 ++++++++++++++------ |
| 1 file changed, 14 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c |
| index 60d675fefac7d..40ddd17864304 100644 |
| --- a/drivers/s390/net/qeth_core_main.c |
| +++ b/drivers/s390/net/qeth_core_main.c |
| @@ -202,12 +202,17 @@ EXPORT_SYMBOL_GPL(qeth_threads_running); |
| void qeth_clear_working_pool_list(struct qeth_card *card) |
| { |
| struct qeth_buffer_pool_entry *pool_entry, *tmp; |
| + struct qeth_qdio_q *queue = card->qdio.in_q; |
| + unsigned int i; |
| |
| QETH_CARD_TEXT(card, 5, "clwrklst"); |
| list_for_each_entry_safe(pool_entry, tmp, |
| &card->qdio.in_buf_pool.entry_list, list){ |
| list_del(&pool_entry->list); |
| } |
| + |
| + for (i = 0; i < ARRAY_SIZE(queue->bufs); i++) |
| + queue->bufs[i].pool_entry = NULL; |
| } |
| EXPORT_SYMBOL_GPL(qeth_clear_working_pool_list); |
| |
| @@ -2671,7 +2676,7 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry( |
| static int qeth_init_input_buffer(struct qeth_card *card, |
| struct qeth_qdio_buffer *buf) |
| { |
| - struct qeth_buffer_pool_entry *pool_entry; |
| + struct qeth_buffer_pool_entry *pool_entry = buf->pool_entry; |
| int i; |
| |
| if ((card->options.cq == QETH_CQ_ENABLED) && (!buf->rx_skb)) { |
| @@ -2682,9 +2687,13 @@ static int qeth_init_input_buffer(struct qeth_card *card, |
| return -ENOMEM; |
| } |
| |
| - pool_entry = qeth_find_free_buffer_pool_entry(card); |
| - if (!pool_entry) |
| - return -ENOBUFS; |
| + if (!pool_entry) { |
| + pool_entry = qeth_find_free_buffer_pool_entry(card); |
| + if (!pool_entry) |
| + return -ENOBUFS; |
| + |
| + buf->pool_entry = pool_entry; |
| + } |
| |
| /* |
| * since the buffer is accessed only from the input_tasklet |
| @@ -2692,8 +2701,6 @@ static int qeth_init_input_buffer(struct qeth_card *card, |
| * the QETH_IN_BUF_REQUEUE_THRESHOLD we should never run out off |
| * buffers |
| */ |
| - |
| - buf->pool_entry = pool_entry; |
| for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { |
| buf->buffer->element[i].length = PAGE_SIZE; |
| buf->buffer->element[i].addr = |
| @@ -5521,6 +5528,7 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) |
| if (done) { |
| QETH_CARD_STAT_INC(card, rx_bufs); |
| qeth_put_buffer_pool_entry(card, buffer->pool_entry); |
| + buffer->pool_entry = NULL; |
| qeth_queue_input_buffer(card, card->rx.b_index); |
| card->rx.b_count--; |
| |
| -- |
| 2.25.1 |
| |