Commit 4fbd804e authored by Maxime Ripard's avatar Maxime Ripard Committed by Vinod Koul

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: default avatarDan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parent 174427c1
...@@ -562,8 +562,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy( ...@@ -562,8 +562,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli); v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
if (!v_lli) { if (!v_lli) {
dev_err(sdev->slave.dev, "Failed to alloc lli memory\n"); dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
kfree(txd); goto err_txd_free;
return NULL;
} }
ret = sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig); 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,6 +582,8 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
err_dma_free: err_dma_free:
dma_pool_free(sdev->pool, v_lli, p_lli); dma_pool_free(sdev->pool, v_lli, p_lli);
err_txd_free:
kfree(txd);
return NULL; return NULL;
} }
...@@ -614,17 +615,15 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg( ...@@ -614,17 +615,15 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
for_each_sg(sgl, sg, sg_len, i) { for_each_sg(sgl, sg, sg_len, i) {
v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli); v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
if (!v_lli) { if (!v_lli)
kfree(txd); goto err_lli_free;
return NULL;
}
if (dir == DMA_MEM_TO_DEV) { if (dir == DMA_MEM_TO_DEV) {
ret = sun6i_dma_cfg_lli(v_lli, sg_dma_address(sg), ret = sun6i_dma_cfg_lli(v_lli, sg_dma_address(sg),
sconfig->dst_addr, sg_dma_len(sg), sconfig->dst_addr, sg_dma_len(sg),
sconfig); sconfig);
if (ret) if (ret)
goto err_dma_free; goto err_cur_lli_free;
v_lli->cfg |= DMA_CHAN_CFG_DST_IO_MODE | v_lli->cfg |= DMA_CHAN_CFG_DST_IO_MODE |
DMA_CHAN_CFG_SRC_LINEAR_MODE | DMA_CHAN_CFG_SRC_LINEAR_MODE |
...@@ -642,7 +641,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg( ...@@ -642,7 +641,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
sg_dma_address(sg), sg_dma_len(sg), sg_dma_address(sg), sg_dma_len(sg),
sconfig); sconfig);
if (ret) if (ret)
goto err_dma_free; goto err_cur_lli_free;
v_lli->cfg |= DMA_CHAN_CFG_DST_LINEAR_MODE | v_lli->cfg |= DMA_CHAN_CFG_DST_LINEAR_MODE |
DMA_CHAN_CFG_SRC_IO_MODE | DMA_CHAN_CFG_SRC_IO_MODE |
...@@ -665,8 +664,12 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg( ...@@ -665,8 +664,12 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
return vchan_tx_prep(&vchan->vc, &txd->vd, flags); return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
err_dma_free: err_cur_lli_free:
dma_pool_free(sdev->pool, v_lli, p_lli); dma_pool_free(sdev->pool, v_lli, p_lli);
err_lli_free:
for (prev = txd->v_lli; prev; prev = prev->v_lli_next)
dma_pool_free(sdev->pool, prev, virt_to_phys(prev));
kfree(txd);
return NULL; return NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment