lkml.org 
[lkml]   [2019]   [Nov]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.3 096/193] dmaengine: sprd: Fix the possible memory leak issue
    Date
    From: Baolin Wang <baolin.wang@linaro.org>

    [ Upstream commit ec1ac309596a7bdf206743b092748205f6cd5720 ]

    If we terminate the channel to free all descriptors associated with this
    channel, we will leak the memory of current descriptor if the current
    descriptor is not completed, since it had been deteled from the desc_issued
    list and have not been added into the desc_completed list.

    Thus we should check if current descriptor is completed or not, when freeing
    the descriptors associated with one channel, if not, we should free it to
    avoid this issue.

    Fixes: 9b3b8171f7f4 ("dmaengine: sprd: Add Spreadtrum DMA driver")
    Reported-by: Zhenfang Wang <zhenfang.wang@unisoc.com>
    Tested-by: Zhenfang Wang <zhenfang.wang@unisoc.com>
    Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
    Link: https://lore.kernel.org/r/170dbbc6d5366b6fa974ce2d366652e23a334251.1570609788.git.baolin.wang@linaro.org
    Signed-off-by: Vinod Koul <vkoul@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/dma/sprd-dma.c | 15 +++++++++++++++
    1 file changed, 15 insertions(+)

    diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
    index a4a91f233121a..8546ad0347208 100644
    --- a/drivers/dma/sprd-dma.c
    +++ b/drivers/dma/sprd-dma.c
    @@ -212,6 +212,7 @@ struct sprd_dma_dev {
    struct sprd_dma_chn channels[0];
    };

    +static void sprd_dma_free_desc(struct virt_dma_desc *vd);
    static bool sprd_dma_filter_fn(struct dma_chan *chan, void *param);
    static struct of_dma_filter_info sprd_dma_info = {
    .filter_fn = sprd_dma_filter_fn,
    @@ -613,12 +614,19 @@ static int sprd_dma_alloc_chan_resources(struct dma_chan *chan)
    static void sprd_dma_free_chan_resources(struct dma_chan *chan)
    {
    struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
    + struct virt_dma_desc *cur_vd = NULL;
    unsigned long flags;

    spin_lock_irqsave(&schan->vc.lock, flags);
    + if (schan->cur_desc)
    + cur_vd = &schan->cur_desc->vd;
    +
    sprd_dma_stop(schan);
    spin_unlock_irqrestore(&schan->vc.lock, flags);

    + if (cur_vd)
    + sprd_dma_free_desc(cur_vd);
    +
    vchan_free_chan_resources(&schan->vc);
    pm_runtime_put(chan->device->dev);
    }
    @@ -1031,15 +1039,22 @@ static int sprd_dma_resume(struct dma_chan *chan)
    static int sprd_dma_terminate_all(struct dma_chan *chan)
    {
    struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
    + struct virt_dma_desc *cur_vd = NULL;
    unsigned long flags;
    LIST_HEAD(head);

    spin_lock_irqsave(&schan->vc.lock, flags);
    + if (schan->cur_desc)
    + cur_vd = &schan->cur_desc->vd;
    +
    sprd_dma_stop(schan);

    vchan_get_all_descriptors(&schan->vc, &head);
    spin_unlock_irqrestore(&schan->vc.lock, flags);

    + if (cur_vd)
    + sprd_dma_free_desc(cur_vd);
    +
    vchan_dma_desc_free_list(&schan->vc, &head);
    return 0;
    }
    --
    2.20.1


    \
     
     \ /
      Last update: 2019-11-11 20:01    [W:4.062 / U:0.068 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site