Skip to content

Commit

Permalink
dmaengine/ste_dma40: fix Oops due to double free of client descriptor
Browse files Browse the repository at this point in the history
The client list may exist in two lists at the same time. This makes free
fail since the same desc is freed multiple times. Remove desc from
client list when adding it to the pending queue. Move free of client owned
descriptors from free_dma() to terminate_all().

Unable to handle kernel paging request at virtual address 00100104
pgd = dea8c000
[00100104] *pgd=1ea62831, *pte=00000000, *ppte=00000000
Internal error: Oops: 817 [#1] PREEMPT SMP
Modules linked in:
CPU: 0    Not tainted  (3.1.0-rc3+ #58)
PC is at d40_free_chan_resources+0x64/0x330

Signed-off-by: Per Forlin <[email protected]>
Acked-by: Linus Walleij <[email protected]>
Signed-off-by: Vinod Koul <[email protected]>
  • Loading branch information
perfor authored and Vinod Koul committed Sep 5, 2011
1 parent 3b3d5b0 commit 7404368
Showing 1 changed file with 12 additions and 10 deletions.
22 changes: 12 additions & 10 deletions drivers/dma/ste_dma40.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,8 +644,11 @@ static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
return d;
}

/* remove desc from current queue and add it to the pending_queue */
static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc)
{
d40_desc_remove(desc);
desc->is_in_client_list = false;
list_add_tail(&desc->node, &d40c->pending_queue);
}

Expand Down Expand Up @@ -803,6 +806,7 @@ static int d40_channel_execute_command(struct d40_chan *d40c,
static void d40_term_all(struct d40_chan *d40c)
{
struct d40_desc *d40d;
struct d40_desc *_d;

/* Release active descriptors */
while ((d40d = d40_first_active_get(d40c))) {
Expand All @@ -822,6 +826,14 @@ static void d40_term_all(struct d40_chan *d40c)
d40_desc_free(d40c, d40d);
}

/* Release client owned descriptors */
if (!list_empty(&d40c->client))
list_for_each_entry_safe(d40d, _d, &d40c->client, node) {
d40_desc_remove(d40d);
d40_desc_free(d40c, d40d);
}


d40c->pending_tx = 0;
d40c->busy = false;
}
Expand Down Expand Up @@ -1594,20 +1606,10 @@ static int d40_free_dma(struct d40_chan *d40c)
u32 event;
struct d40_phy_res *phy = d40c->phy_chan;
bool is_src;
struct d40_desc *d;
struct d40_desc *_d;


/* Terminate all queued and active transfers */
d40_term_all(d40c);

/* Release client owned descriptors */
if (!list_empty(&d40c->client))
list_for_each_entry_safe(d, _d, &d40c->client, node) {
d40_desc_remove(d);
d40_desc_free(d40c, d);
}

if (phy == NULL) {
chan_err(d40c, "phy == null\n");
return -EINVAL;
Expand Down

0 comments on commit 7404368

Please sign in to comment.