aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-08-25 12:04:07 +0200
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2018-09-06 13:06:21 +0100
commitdaf0270b311e39af442766c7297b5d676d1845c7 (patch)
tree4bf69fdf605eee24cb0edaec909b935f6e5ad406
parent60444389f5df476ece5180df61bb2deb3ccbb571 (diff)
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 .... [<ffff000008715610>] soc_dapm_dai_stream_event.isra.14+0x20/0xd0 [<ffff00000871989c>] snd_soc_dapm_stream_event+0x74/0xa8 [<ffff00000871b23c>] close_delayed_work+0x3c/0x50 [<ffff0000080bbd6c>] process_one_work+0x1ac/0x318 [<ffff0000080bbf20>] worker_thread+0x48/0x420 [<ffff0000080c201c>] kthread+0xfc/0x128 [<ffff0000080842f0>] 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 <cm-hiep@jinso.co.jp> Reported-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Tested-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/soc-pcm.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 23c251a6c5875..09fed7014ed84 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -2630,6 +2630,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)
{
@@ -2755,7 +2766,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,