The members in the LLI list is released in an incorrect way. Read and store the next member before releasing it to avoid accessing the freed memory. Fixes: a90e173f3faf ("dmaengine: sun6i: Add cyclic capability") Signed-off-by: Pan Bian <bianpan2016@xxxxxxx> --- drivers/dma/sun6i-dma.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index 06cd7f867f7c..096aad7e75bb 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -687,7 +687,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg( struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); struct sun6i_vchan *vchan = to_sun6i_vchan(chan); struct dma_slave_config *sconfig = &vchan->cfg; - struct sun6i_dma_lli *v_lli, *prev = NULL; + struct sun6i_dma_lli *v_lli, *next, *prev = NULL; struct sun6i_desc *txd; struct scatterlist *sg; dma_addr_t p_lli; @@ -752,8 +752,12 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg( return vchan_tx_prep(&vchan->vc, &txd->vd, flags); err_lli_free: - for (prev = txd->v_lli; prev; prev = prev->v_lli_next) - dma_pool_free(sdev->pool, prev, virt_to_phys(prev)); + v_lli = txd->v_lli; + while (v_lli) { + next = v_lli->v_lli_next; + dma_pool_free(sdev->pool, v_lli, virt_to_phys(v_lli)); + v_lli = next; + } kfree(txd); return NULL; } @@ -769,7 +773,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic( struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); struct sun6i_vchan *vchan = to_sun6i_vchan(chan); struct dma_slave_config *sconfig = &vchan->cfg; - struct sun6i_dma_lli *v_lli, *prev = NULL; + struct sun6i_dma_lli *v_lli, *next, *prev = NULL; struct sun6i_desc *txd; dma_addr_t p_lli; u32 lli_cfg; @@ -820,8 +824,12 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic( return vchan_tx_prep(&vchan->vc, &txd->vd, flags); err_lli_free: - for (prev = txd->v_lli; prev; prev = prev->v_lli_next) - dma_pool_free(sdev->pool, prev, virt_to_phys(prev)); + v_lli = txd->v_lli; + while (v_lli) { + next = v_lli->v_lli_next; + dma_pool_free(sdev->pool, v_lli, virt_to_phys(v_lli)); + v_lli = next; + } kfree(txd); return NULL; } -- 2.7.4