mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 02:21:52 +09:00
s390/qeth: fix memory leak after failed TX Buffer allocation
commite7a36d27f6upstream. 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:0da9581ddb("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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
345d90cd74
commit
84ef8a8cb7
@@ -2632,15 +2632,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)
|
||||
@@ -2653,7 +2666,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");
|
||||
|
||||
@@ -2687,13 +2700,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 */
|
||||
@@ -2702,13 +2708,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]);
|
||||
|
||||
Reference in New Issue
Block a user