If a request already in the queue is passed to tegra_dma_enqueue_req, tegra_dma_req.node->{next,prev} will end up pointing to itself instead of at tegra_dma_channel.list, which is the way a the end-of-list should be set up. When the DMA request completes and is list_del'd, the list head will still point at it, yet the node's next/prev will contain the list poison values. When the next DMA request completes, a kernel panic will occur when those poison values are dereferenced. This makes the DMA driver more robust in the face of buggy clients. Signed-off-by: Stephen Warren <swarren@xxxxxxxxxxxxx> --- This is for branch for-next arch/arm/mach-tegra/dma.c | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index 760723c..59b2e97 100755 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -320,6 +320,8 @@ int tegra_dma_enqueue_req(struct tegra_dma_channel *ch, struct tegra_dma_req *req) { unsigned long irq_flags; + struct tegra_dma_req *_req; + int found = 0; int start_dma = 0; if (req->size > NV_DMA_MAX_TRASFER_SIZE || @@ -330,6 +332,18 @@ int tegra_dma_enqueue_req(struct tegra_dma_channel *ch, spin_lock_irqsave(&ch->lock, irq_flags); + list_for_each_entry(_req, &ch->list, node) { + if (req == _req) { + list_del(&req->node); + found = 1; + break; + } + } + if (found) { + spin_unlock_irqrestore(&ch->lock, irq_flags); + return -EEXIST; + } + req->bytes_transferred = 0; req->status = 0; req->buffer_status = 0; -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html