[alsa-devel] [PATCH v2] ASoC: core: move DAI pre-links initiation to snd_soc_instantiate_card
Kernel crashes when an ASoC component rebinding.
The dai_link->platforms has been reset to NULL by soc_cleanup_platform() in soc_cleanup_card_resources() when un-registering component. However, it has no chance to re-allocate the dai_link->platforms when registering the component again.
Move the DAI pre-links initiation from snd_soc_register_card() to snd_soc_instantiate_card() to make sure all DAI pre-links get initiated when component rebinding.
As an example, by using the following commands: - echo -n max98357a > /sys/bus/platform/drivers/max98357a/unbind - echo -n max98357a > /sys/bus/platform/drivers/max98357a/bind
Got the error message: "Unable to handle kernel NULL pointer dereference at virtual address".
The call trace: snd_soc_is_matching_component+0x30/0x6c soc_bind_dai_link+0x16c/0x240 snd_soc_bind_card+0x1e4/0xb10 snd_soc_add_component+0x270/0x300 snd_soc_register_component+0x54/0x6c
Signed-off-by: Tzung-Bi Shih tzungbi@google.com --- Changes from v1 (https://patchwork.kernel.org/patch/10968311/): - reserve original logic as much as possible - only acquire client_mutex - do not call soc_cleanup_card_resources() if soc_init_dai_link() returns fail, in the case some context (e.g. card->dapm) may have not initialized yet
Difference from original logic: - soc_init_dai_link() would be called several times (e.g. -EPROBE_DEFER)
sound/soc/soc-core.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7abb017a83f3..9191d2bec489 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2070,6 +2070,16 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) int ret, i, order;
mutex_lock(&client_mutex); + for_each_card_prelinks(card, i, dai_link) { + ret = soc_init_dai_link(card, dai_link); + if (ret) { + soc_cleanup_platform(card); + dev_err(card->dev, "ASoC: failed to init link %s: %d\n", + dai_link->name, ret); + mutex_unlock(&client_mutex); + return ret; + } + } mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
card->dapm.bias_level = SND_SOC_BIAS_OFF; @@ -2794,26 +2804,9 @@ static int snd_soc_bind_card(struct snd_soc_card *card) */ int snd_soc_register_card(struct snd_soc_card *card) { - int i, ret; - struct snd_soc_dai_link *link; - if (!card->name || !card->dev) return -EINVAL;
- mutex_lock(&client_mutex); - for_each_card_prelinks(card, i, link) { - - ret = soc_init_dai_link(card, link); - if (ret) { - soc_cleanup_platform(card); - dev_err(card->dev, "ASoC: failed to init link %s\n", - link->name); - mutex_unlock(&client_mutex); - return ret; - } - } - mutex_unlock(&client_mutex); - dev_set_drvdata(card->dev, card);
snd_soc_initialize_card_lists(card);
The patch
ASoC: core: move DAI pre-links initiation to snd_soc_instantiate_card
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 70fc53734e71ce51f46dfcfd1a1c319e1cfe080c Mon Sep 17 00:00:00 2001
From: Tzung-Bi Shih tzungbi@google.com Date: Tue, 4 Jun 2019 11:31:02 +0800 Subject: [PATCH] ASoC: core: move DAI pre-links initiation to snd_soc_instantiate_card
Kernel crashes when an ASoC component rebinding.
The dai_link->platforms has been reset to NULL by soc_cleanup_platform() in soc_cleanup_card_resources() when un-registering component. However, it has no chance to re-allocate the dai_link->platforms when registering the component again.
Move the DAI pre-links initiation from snd_soc_register_card() to snd_soc_instantiate_card() to make sure all DAI pre-links get initiated when component rebinding.
As an example, by using the following commands: - echo -n max98357a > /sys/bus/platform/drivers/max98357a/unbind - echo -n max98357a > /sys/bus/platform/drivers/max98357a/bind
Got the error message: "Unable to handle kernel NULL pointer dereference at virtual address".
The call trace: snd_soc_is_matching_component+0x30/0x6c soc_bind_dai_link+0x16c/0x240 snd_soc_bind_card+0x1e4/0xb10 snd_soc_add_component+0x270/0x300 snd_soc_register_component+0x54/0x6c
Signed-off-by: Tzung-Bi Shih tzungbi@google.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/soc-core.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 46042d41b79b..3fecd957995e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2072,6 +2072,16 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) int ret, i, order;
mutex_lock(&client_mutex); + for_each_card_prelinks(card, i, dai_link) { + ret = soc_init_dai_link(card, dai_link); + if (ret) { + soc_cleanup_platform(card); + dev_err(card->dev, "ASoC: failed to init link %s: %d\n", + dai_link->name, ret); + mutex_unlock(&client_mutex); + return ret; + } + } mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
card->dapm.bias_level = SND_SOC_BIAS_OFF; @@ -2796,26 +2806,9 @@ static int snd_soc_bind_card(struct snd_soc_card *card) */ int snd_soc_register_card(struct snd_soc_card *card) { - int i, ret; - struct snd_soc_dai_link *link; - if (!card->name || !card->dev) return -EINVAL;
- mutex_lock(&client_mutex); - for_each_card_prelinks(card, i, link) { - - ret = soc_init_dai_link(card, link); - if (ret) { - soc_cleanup_platform(card); - dev_err(card->dev, "ASoC: failed to init link %s\n", - link->name); - mutex_unlock(&client_mutex); - return ret; - } - } - mutex_unlock(&client_mutex); - dev_set_drvdata(card->dev, card);
snd_soc_initialize_card_lists(card);
participants (2)
-
Mark Brown
-
Tzung-Bi Shih