aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2015-10-20 05:46:31 -0400
committerVinod Koul <vinod.koul@intel.com>2015-11-15 21:58:52 -0500
commitbc0e7345168c0f7483d2d1da86285d89136417cd (patch)
tree9045e7f4f133da72296fdf13c9270db34d64906a
parent860dd64c4382709a276eb4b7ef36596579dba04a (diff)
ALSA: pcm_dmaengine: Properly synchronize DMA on shutdown
Use the new dmaengine_synchronize() function to make sure that all complete callbacks have finished running before the runtime data, which is accessed in the completed callback, is freed. This fixes a long standing use-after-free race condition that has been observed on some systems. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Reviewed-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--sound/core/pcm_dmaengine.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index fba365a78390..697c166acf05 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -202,13 +202,13 @@ int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
202 if (runtime->info & SNDRV_PCM_INFO_PAUSE) 202 if (runtime->info & SNDRV_PCM_INFO_PAUSE)
203 dmaengine_pause(prtd->dma_chan); 203 dmaengine_pause(prtd->dma_chan);
204 else 204 else
205 dmaengine_terminate_all(prtd->dma_chan); 205 dmaengine_terminate_async(prtd->dma_chan);
206 break; 206 break;
207 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 207 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
208 dmaengine_pause(prtd->dma_chan); 208 dmaengine_pause(prtd->dma_chan);
209 break; 209 break;
210 case SNDRV_PCM_TRIGGER_STOP: 210 case SNDRV_PCM_TRIGGER_STOP:
211 dmaengine_terminate_all(prtd->dma_chan); 211 dmaengine_terminate_async(prtd->dma_chan);
212 break; 212 break;
213 default: 213 default:
214 return -EINVAL; 214 return -EINVAL;
@@ -346,6 +346,7 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
346{ 346{
347 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); 347 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
348 348
349 dmaengine_synchronize(prtd->dma_chan);
349 kfree(prtd); 350 kfree(prtd);
350 351
351 return 0; 352 return 0;
@@ -362,9 +363,11 @@ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
362{ 363{
363 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); 364 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
364 365
366 dmaengine_synchronize(prtd->dma_chan);
365 dma_release_channel(prtd->dma_chan); 367 dma_release_channel(prtd->dma_chan);
368 kfree(prtd);
366 369
367 return snd_dmaengine_pcm_close(substream); 370 return 0;
368} 371}
369EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan); 372EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
370 373