Skip to content

Commit

Permalink
s390/qeth: fix memory leak after failed TX Buffer allocation
Browse files Browse the repository at this point in the history
commit e7a36d2 upstream.

When qeth_alloc_qdio_queues() fails to allocate one of the buffers that
back an Output Queue, the 'out_freeoutqbufs' path will free all
previously allocated buffers for this queue. But it misses to free the
half-finished queue struct itself.

Move the buffer allocation into qeth_alloc_output_queue(), and deal with
such errors internally.

Fixes: 0da9581 ("qeth: exploit asynchronous delivery of storage blocks")
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
julianwiedmann authored and gregkh committed Mar 17, 2021
1 parent cc1438d commit d76d8e4
Showing 1 changed file with 17 additions and 18 deletions.
35 changes: 17 additions & 18 deletions drivers/s390/net/qeth_core_main.c
Expand Up @@ -2630,15 +2630,28 @@ static void qeth_free_output_queue(struct qeth_qdio_out_q *q)
static struct qeth_qdio_out_q *qeth_alloc_output_queue(void)
{
struct qeth_qdio_out_q *q = kzalloc(sizeof(*q), GFP_KERNEL);
unsigned int i;

if (!q)
return NULL;

if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q)) {
kfree(q);
return NULL;
if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q))
goto err_qdio_bufs;

for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
if (qeth_init_qdio_out_buf(q, i))
goto err_out_bufs;
}

return q;

err_out_bufs:
while (i > 0)
kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[--i]);
qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q);
err_qdio_bufs:
kfree(q);
return NULL;
}

static void qeth_tx_completion_timer(struct timer_list *timer)
Expand All @@ -2651,7 +2664,7 @@ static void qeth_tx_completion_timer(struct timer_list *timer)

static int qeth_alloc_qdio_queues(struct qeth_card *card)
{
int i, j;
unsigned int i;

QETH_CARD_TEXT(card, 2, "allcqdbf");

Expand Down Expand Up @@ -2685,13 +2698,6 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card)
queue->coalesce_usecs = QETH_TX_COALESCE_USECS;
queue->max_coalesced_frames = QETH_TX_MAX_COALESCED_FRAMES;
queue->priority = QETH_QIB_PQUE_PRIO_DEFAULT;

/* give outbound qeth_qdio_buffers their qdio_buffers */
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
WARN_ON(queue->bufs[j]);
if (qeth_init_qdio_out_buf(queue, j))
goto out_freeoutqbufs;
}
}

/* completion */
Expand All @@ -2700,13 +2706,6 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card)

return 0;

out_freeoutqbufs:
while (j > 0) {
--j;
kmem_cache_free(qeth_qdio_outbuf_cache,
card->qdio.out_qs[i]->bufs[j]);
card->qdio.out_qs[i]->bufs[j] = NULL;
}
out_freeoutq:
while (i > 0) {
qeth_free_output_queue(card->qdio.out_qs[--i]);
Expand Down

0 comments on commit d76d8e4

Please sign in to comment.