From 58148c0ad35f827e634ee5709ad70eea56c23875 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Mon, 19 Oct 2015 13:24:48 -0700 Subject: [PATCH] CHROMIUM: dmaengine: tegra-adma: Fix another race between tasklet/terminate_all While commit 370626692e0c ("CHROMIUM: dmaengine: tegra-adma: fix race between tasklet/terminate_all (take 2)") fixed one of the races between the ADMA tasklet and tegra_adma_terminate_all(), another one still remains: the ADMA tasklet (and the DMA callback) may still be running on another CPU after tegra_adma_terminate_all() returns. This can result in a use-after-free in the snd_pcm_release_substream() path when the context used in the DMA callback (struct snd_pcm_runtime) is freed after terminating the DMA. To fix this, kill the ADMA tasklet before returning from tegra_adma_terminate_all() as long as we're not in the tasklet itself. BUG=chrome-os-partner:46247 TEST=Play/stop audio repeatedly on Smaug; no issues seen. Change-Id: Iaa8f7d53179d254c74abc1a40f1c0ed64c51d60f Signed-off-by: Andrew Bresticker Reviewed-on: https://chromium-review.googlesource.com/307104 Reviewed-by: Maneet Singh Reviewed-by: Anatol Pomazau --- drivers/dma/tegra210-adma.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 43431075c6442..73ba3ec8ced83 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -737,6 +737,15 @@ static void tegra_adma_terminate_all(struct dma_chan *dc) */ tdc->callback_count = 0; + /* Make sure the tasklet has stopped running before we return. */ + if (!in_interrupt()) { + tdc->busy = true; + spin_unlock_irqrestore(&tdc->lock, flags); + tasklet_kill(&tdc->tasklet); + spin_lock_irqsave(&tdc->lock, flags); + tdc->busy = false; + } + spin_unlock_irqrestore(&tdc->lock, flags); }