Commit bc0e7345 authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Vinod Koul

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: default avatarLars-Peter Clausen <lars@metafoo.de>
Reviewed-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parent 860dd64c
...@@ -202,13 +202,13 @@ int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ...@@ -202,13 +202,13 @@ int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (runtime->info & SNDRV_PCM_INFO_PAUSE) if (runtime->info & SNDRV_PCM_INFO_PAUSE)
dmaengine_pause(prtd->dma_chan); dmaengine_pause(prtd->dma_chan);
else else
dmaengine_terminate_all(prtd->dma_chan); dmaengine_terminate_async(prtd->dma_chan);
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dmaengine_pause(prtd->dma_chan); dmaengine_pause(prtd->dma_chan);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
dmaengine_terminate_all(prtd->dma_chan); dmaengine_terminate_async(prtd->dma_chan);
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -346,6 +346,7 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) ...@@ -346,6 +346,7 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
{ {
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
dmaengine_synchronize(prtd->dma_chan);
kfree(prtd); kfree(prtd);
return 0; return 0;
...@@ -362,9 +363,11 @@ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream) ...@@ -362,9 +363,11 @@ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
{ {
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
dmaengine_synchronize(prtd->dma_chan);
dma_release_channel(prtd->dma_chan); dma_release_channel(prtd->dma_chan);
kfree(prtd);
return snd_dmaengine_pcm_close(substream); return 0;
} }
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan); EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment