]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
s390/qeth: tolerate pre-filled RX buffer
authorJulian Wiedmann <jwi@linux.ibm.com>
Thu, 30 Jul 2020 15:01:18 +0000 (17:01 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 31 Jul 2020 23:44:35 +0000 (16:44 -0700)
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>
drivers/s390/net/qeth_core_main.c

index 8a76022fceda412dbcc07825c9a23e9148af79aa..b356ee5de9f8d02e7732b1b21ab35e97b635238c 100644 (file)
@@ -204,12 +204,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);
 
@@ -2965,7 +2970,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)) {
@@ -2976,9 +2981,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
@@ -2986,8 +2995,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 =
@@ -5771,6 +5778,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--;