aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIra Snyder <iws@ovro.caltech.edu>2009-05-15 12:59:46 -0400
committerLi Yang <leoli@freescale.com>2009-05-22 04:54:42 -0400
commit2e077f8e8337e52eef3c39c24c31e103b11a0326 (patch)
tree686c9965c8304f5b6d59d3538e989674467ee129
parent776c8943f2766f2819fafd88fdfbaf418ecd6e41 (diff)
fsldma: fix memory leak on error path in fsl_dma_prep_memcpy()
When preparing a memcpy operation, if the kernel fails to allocate memory for a link descriptor after the first link descriptor has already been allocated, then some memory will never be released. Fix the problem by walking the list of allocated descriptors backwards, and freeing the allocated descriptors back into the DMA pool. Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu> Signed-off-by: Li Yang <leoli@freescale.com>
-rw-r--r--drivers/dma/fsldma.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index ff9194d7ebb7..15783102bf17 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -462,8 +462,8 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
462{ 462{
463 struct fsl_dma_chan *fsl_chan; 463 struct fsl_dma_chan *fsl_chan;
464 struct fsl_desc_sw *first = NULL, *prev = NULL, *new; 464 struct fsl_desc_sw *first = NULL, *prev = NULL, *new;
465 struct list_head *list;
465 size_t copy; 466 size_t copy;
466 LIST_HEAD(link_chain);
467 467
468 if (!chan) 468 if (!chan)
469 return NULL; 469 return NULL;
@@ -480,7 +480,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
480 if (!new) { 480 if (!new) {
481 dev_err(fsl_chan->dev, 481 dev_err(fsl_chan->dev,
482 "No free memory for link descriptor\n"); 482 "No free memory for link descriptor\n");
483 return NULL; 483 goto fail;
484 } 484 }
485#ifdef FSL_DMA_LD_DEBUG 485#ifdef FSL_DMA_LD_DEBUG
486 dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new); 486 dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new);
@@ -515,7 +515,19 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
515 /* Set End-of-link to the last link descriptor of new list*/ 515 /* Set End-of-link to the last link descriptor of new list*/
516 set_ld_eol(fsl_chan, new); 516 set_ld_eol(fsl_chan, new);
517 517
518 return first ? &first->async_tx : NULL; 518 return &first->async_tx;
519
520fail:
521 if (!first)
522 return NULL;
523
524 list = &first->async_tx.tx_list;
525 list_for_each_entry_safe_reverse(new, prev, list, node) {
526 list_del(&new->node);
527 dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
528 }
529
530 return NULL;
519} 531}
520 532
521/** 533/**