From 5d61f0ba6524dcbad198126e5793157c8afdea91 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Aug 2017 12:04:07 +0200 Subject: [PATCH] ASoC: pcm: Sync delayed work before releasing resources When ASoC driver is unbound dynamically during its operation (i.e. a kind of hot-unplug), we may hit Oops due to the resource access after the release by a delayed work, something like: Unable to handle kernel paging request at virtual address dead000000000220 .... PC is at soc_dapm_dai_stream_event.isra.14+0x20/0xd0 LR is at snd_soc_dapm_stream_event+0x74/0xa8 .... [] soc_dapm_dai_stream_event.isra.14+0x20/0xd0 [] snd_soc_dapm_stream_event+0x74/0xa8 [] close_delayed_work+0x3c/0x50 [] process_one_work+0x1ac/0x318 [] worker_thread+0x48/0x420 [] kthread+0xfc/0x128 [] ret_from_fork+0x10/0x18 For fixing the race, this patch adds a sync-point in pcm private_free callback to finish the delayed work before actually releasing the resources. Reported-by: Hiep Cao Minh Reported-by: Kuninori Morimoto Tested-by: Kuninori Morimoto Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 94b88b897c3b..c0f0b09cb433 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2632,6 +2632,17 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) return ret; } +static void soc_pcm_private_free(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_platform *platform = rtd->platform; + + /* need to sync the delayed work before releasing resources */ + flush_delayed_work(&rtd->delayed_work); + if (platform->driver->pcm_free) + platform->driver->pcm_free(pcm); +} + /* create a new pcm */ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) { @@ -2757,7 +2768,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } } - pcm->private_free = platform->driver->pcm_free; + pcm->private_free = soc_pcm_private_free; out: dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,