aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2014-07-30 04:30:23 -0400
committerVinod Koul <vinod.koul@intel.com>2014-07-30 09:44:17 -0400
commit4fbd804e009ae9dff29dcb1fbfa0aaffd3992880 (patch)
tree13ca8845a4d581ce90a25e779cb87667d078babf /drivers/dma
parent174427c1bb9e7810743f55a90a64da2c29d67b0b (diff)
dmaengine: sun6i: Fix memory leaks
The sun6i_dma_prep_memcpy and sun6i_dma_prep_slave_sg functions were both leaking the descriptor they allocated if an error was happening after a successful dma_pool_alloc call. It also fixes a memleak that was happening in the scatter gather list traversal, that was allocating as much descriptor as there was scatter gather items, but only freeing the current descriptor if an error was to arise. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/sun6i-dma.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 63a1db38894e..1f92a56fd2b6 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -562,8 +562,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
562 v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli); 562 v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
563 if (!v_lli) { 563 if (!v_lli) {
564 dev_err(sdev->slave.dev, "Failed to alloc lli memory\n"); 564 dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
565 kfree(txd); 565 goto err_txd_free;
566 return NULL;
567 } 566 }
568 567
569 ret = sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig); 568 ret = sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig);
@@ -583,6 +582,8 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
583 582
584err_dma_free: 583err_dma_free:
585 dma_pool_free(sdev->pool, v_lli, p_lli); 584 dma_pool_free(sdev->pool, v_lli, p_lli);
585err_txd_free:
586 kfree(txd);
586 return NULL; 587 return NULL;
587} 588}
588 589
@@ -614,17 +615,15 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
614 615
615 for_each_sg(sgl, sg, sg_len, i) { 616 for_each_sg(sgl, sg, sg_len, i) {
616 v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli); 617 v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
617 if (!v_lli) { 618 if (!v_lli)
618 kfree(txd); 619 goto err_lli_free;
619 return NULL;
620 }
621 620
622 if (dir == DMA_MEM_TO_DEV) { 621 if (dir == DMA_MEM_TO_DEV) {
623 ret = sun6i_dma_cfg_lli(v_lli, sg_dma_address(sg), 622 ret = sun6i_dma_cfg_lli(v_lli, sg_dma_address(sg),
624 sconfig->dst_addr, sg_dma_len(sg), 623 sconfig->dst_addr, sg_dma_len(sg),
625 sconfig); 624 sconfig);
626 if (ret) 625 if (ret)
627 goto err_dma_free; 626 goto err_cur_lli_free;
628 627
629 v_lli->cfg |= DMA_CHAN_CFG_DST_IO_MODE | 628 v_lli->cfg |= DMA_CHAN_CFG_DST_IO_MODE |
630 DMA_CHAN_CFG_SRC_LINEAR_MODE | 629 DMA_CHAN_CFG_SRC_LINEAR_MODE |
@@ -642,7 +641,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
642 sg_dma_address(sg), sg_dma_len(sg), 641 sg_dma_address(sg), sg_dma_len(sg),
643 sconfig); 642 sconfig);
644 if (ret) 643 if (ret)
645 goto err_dma_free; 644 goto err_cur_lli_free;
646 645
647 v_lli->cfg |= DMA_CHAN_CFG_DST_LINEAR_MODE | 646 v_lli->cfg |= DMA_CHAN_CFG_DST_LINEAR_MODE |
648 DMA_CHAN_CFG_SRC_IO_MODE | 647 DMA_CHAN_CFG_SRC_IO_MODE |
@@ -665,8 +664,12 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
665 664
666 return vchan_tx_prep(&vchan->vc, &txd->vd, flags); 665 return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
667 666
668err_dma_free: 667err_cur_lli_free:
669 dma_pool_free(sdev->pool, v_lli, p_lli); 668 dma_pool_free(sdev->pool, v_lli, p_lli);
669err_lli_free:
670 for (prev = txd->v_lli; prev; prev = prev->v_lli_next)
671 dma_pool_free(sdev->pool, prev, virt_to_phys(prev));
672 kfree(txd);
670 return NULL; 673 return NULL;
671} 674}
672 675