Commit 5d61f0ba authored by Takashi Iwai's avatar Takashi Iwai Committed by Mark Brown

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: default avatarHiep Cao Minh <cm-hiep@jinso.co.jp>
Reported-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 2bd6bf03
...@@ -2632,6 +2632,17 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) ...@@ -2632,6 +2632,17 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
return ret; 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 */ /* create a new pcm */
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) 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) ...@@ -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: out:
dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
(rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
......
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