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>
This commit is contained in:
parent
860dd64c43
commit
bc0e734516
|
@ -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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue