Skip to content

Commit

Permalink
ASoC: Fix component lists locking
Browse files Browse the repository at this point in the history
Any access to the component_list, codec_list and platform_list needs to be
properly locked by the client_mutex. Otherwise undefined behavior can occur
if the list is modified in one thread and concurrently accessed from another
thread.

This patch adds the missing locking to the debugfs file handlers that
display the registered components, as well as the various components
unregister functions.

Furthermore the client_lock is now held for the whole
snd_soc_instantiate_card() sequence to make sure that component removal does
not race against the card registration.

Reported-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Lars-Peter Clausen authored and Mark Brown committed Mar 8, 2015
1 parent c517d83 commit 34e81ab
Showing 1 changed file with 30 additions and 11 deletions.
41 changes: 30 additions & 11 deletions sound/soc/soc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
if (!buf)
return -ENOMEM;

mutex_lock(&client_mutex);

list_for_each_entry(codec, &codec_list, list) {
len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
codec->component.name);
Expand All @@ -358,6 +360,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
}
}

mutex_unlock(&client_mutex);

if (ret >= 0)
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);

Expand All @@ -382,6 +386,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
if (!buf)
return -ENOMEM;

mutex_lock(&client_mutex);

list_for_each_entry(component, &component_list, list) {
list_for_each_entry(dai, &component->dai_list, list) {
len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
Expand All @@ -395,6 +401,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
}
}

mutex_unlock(&client_mutex);

ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);

kfree(buf);
Expand All @@ -418,6 +426,8 @@ static ssize_t platform_list_read_file(struct file *file,
if (!buf)
return -ENOMEM;

mutex_lock(&client_mutex);

list_for_each_entry(platform, &platform_list, list) {
len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
platform->component.name);
Expand All @@ -429,6 +439,8 @@ static ssize_t platform_list_read_file(struct file *file,
}
}

mutex_unlock(&client_mutex);

ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);

kfree(buf);
Expand Down Expand Up @@ -836,6 +848,8 @@ static struct snd_soc_component *soc_find_component(
{
struct snd_soc_component *component;

lockdep_assert_held(&client_mutex);

list_for_each_entry(component, &component_list, list) {
if (of_node) {
if (component->dev->of_node == of_node)
Expand All @@ -854,6 +868,8 @@ static struct snd_soc_dai *snd_soc_find_dai(
struct snd_soc_component *component;
struct snd_soc_dai *dai;

lockdep_assert_held(&client_mutex);

/* Find CPU DAI from registered DAIs*/
list_for_each_entry(component, &component_list, list) {
if (dlc->of_node && component->dev->of_node != dlc->of_node)
Expand Down Expand Up @@ -1508,6 +1524,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
struct snd_soc_codec *codec;
int ret, i, order;

mutex_lock(&client_mutex);
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);

/* bind DAIs */
Expand Down Expand Up @@ -1662,6 +1679,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
card->instantiated = 1;
snd_soc_dapm_sync(&card->dapm);
mutex_unlock(&card->mutex);
mutex_unlock(&client_mutex);

return 0;

Expand All @@ -1680,6 +1698,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)

base_error:
mutex_unlock(&card->mutex);
mutex_unlock(&client_mutex);

return ret;
}
Expand Down Expand Up @@ -2713,13 +2732,6 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
list_del(&component->list);
}

static void snd_soc_component_del(struct snd_soc_component *component)
{
mutex_lock(&client_mutex);
snd_soc_component_del_unlocked(component);
mutex_unlock(&client_mutex);
}

int snd_soc_register_component(struct device *dev,
const struct snd_soc_component_driver *cmpnt_drv,
struct snd_soc_dai_driver *dai_drv,
Expand Down Expand Up @@ -2767,14 +2779,17 @@ void snd_soc_unregister_component(struct device *dev)
{
struct snd_soc_component *cmpnt;

mutex_lock(&client_mutex);
list_for_each_entry(cmpnt, &component_list, list) {
if (dev == cmpnt->dev && cmpnt->registered_as_component)
goto found;
}
mutex_unlock(&client_mutex);
return;

found:
snd_soc_component_del(cmpnt);
snd_soc_component_del_unlocked(cmpnt);
mutex_unlock(&client_mutex);
snd_soc_component_cleanup(cmpnt);
kfree(cmpnt);
}
Expand Down Expand Up @@ -2882,10 +2897,14 @@ struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
{
struct snd_soc_platform *platform;

mutex_lock(&client_mutex);
list_for_each_entry(platform, &platform_list, list) {
if (dev == platform->dev)
if (dev == platform->dev) {
mutex_unlock(&client_mutex);
return platform;
}
}
mutex_unlock(&client_mutex);

return NULL;
}
Expand Down Expand Up @@ -3090,15 +3109,15 @@ void snd_soc_unregister_codec(struct device *dev)
{
struct snd_soc_codec *codec;

mutex_lock(&client_mutex);
list_for_each_entry(codec, &codec_list, list) {
if (dev == codec->dev)
goto found;
}
mutex_unlock(&client_mutex);
return;

found:

mutex_lock(&client_mutex);
list_del(&codec->list);
snd_soc_component_del_unlocked(&codec->component);
mutex_unlock(&client_mutex);
Expand Down

0 comments on commit 34e81ab

Please sign in to comment.