diff options
author | Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com> | 2019-05-13 05:18:01 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2019-05-13 08:41:56 -0400 |
commit | ed180abba7f1fc3cf04ffa27767b1bcc8e8c842a (patch) | |
tree | 5e740e02d4fd92f1721d12ef0a7b0012d76b54a8 /sound/hda | |
parent | 891afcf2462d2cc4ef7caf94215358ca61fa32cb (diff) |
ALSA: hda: Fix race between creating and refreshing sysfs entries
hda_widget_sysfs_reinit() can free underlying codec->widgets structure
on which widget_tree_create() operates. Add locking to prevent such
issues from happening.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=110382
Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/hda')
-rw-r--r-- | sound/hda/hdac_device.c | 7 | ||||
-rw-r--r-- | sound/hda/hdac_sysfs.c | 3 |
2 files changed, 10 insertions, 0 deletions
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 95b073ee4b32..4769f4c03e14 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c | |||
@@ -55,6 +55,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, | |||
55 | codec->bus = bus; | 55 | codec->bus = bus; |
56 | codec->addr = addr; | 56 | codec->addr = addr; |
57 | codec->type = HDA_DEV_CORE; | 57 | codec->type = HDA_DEV_CORE; |
58 | mutex_init(&codec->widget_lock); | ||
58 | pm_runtime_set_active(&codec->dev); | 59 | pm_runtime_set_active(&codec->dev); |
59 | pm_runtime_get_noresume(&codec->dev); | 60 | pm_runtime_get_noresume(&codec->dev); |
60 | atomic_set(&codec->in_pm, 0); | 61 | atomic_set(&codec->in_pm, 0); |
@@ -141,7 +142,9 @@ int snd_hdac_device_register(struct hdac_device *codec) | |||
141 | err = device_add(&codec->dev); | 142 | err = device_add(&codec->dev); |
142 | if (err < 0) | 143 | if (err < 0) |
143 | return err; | 144 | return err; |
145 | mutex_lock(&codec->widget_lock); | ||
144 | err = hda_widget_sysfs_init(codec); | 146 | err = hda_widget_sysfs_init(codec); |
147 | mutex_unlock(&codec->widget_lock); | ||
145 | if (err < 0) { | 148 | if (err < 0) { |
146 | device_del(&codec->dev); | 149 | device_del(&codec->dev); |
147 | return err; | 150 | return err; |
@@ -158,7 +161,9 @@ EXPORT_SYMBOL_GPL(snd_hdac_device_register); | |||
158 | void snd_hdac_device_unregister(struct hdac_device *codec) | 161 | void snd_hdac_device_unregister(struct hdac_device *codec) |
159 | { | 162 | { |
160 | if (device_is_registered(&codec->dev)) { | 163 | if (device_is_registered(&codec->dev)) { |
164 | mutex_lock(&codec->widget_lock); | ||
161 | hda_widget_sysfs_exit(codec); | 165 | hda_widget_sysfs_exit(codec); |
166 | mutex_unlock(&codec->widget_lock); | ||
162 | device_del(&codec->dev); | 167 | device_del(&codec->dev); |
163 | snd_hdac_bus_remove_device(codec->bus, codec); | 168 | snd_hdac_bus_remove_device(codec->bus, codec); |
164 | } | 169 | } |
@@ -404,7 +409,9 @@ int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs) | |||
404 | } | 409 | } |
405 | 410 | ||
406 | if (sysfs) { | 411 | if (sysfs) { |
412 | mutex_lock(&codec->widget_lock); | ||
407 | err = hda_widget_sysfs_reinit(codec, start_nid, nums); | 413 | err = hda_widget_sysfs_reinit(codec, start_nid, nums); |
414 | mutex_unlock(&codec->widget_lock); | ||
408 | if (err < 0) | 415 | if (err < 0) |
409 | return err; | 416 | return err; |
410 | } | 417 | } |
diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c index fb2aa344981e..909d5ef1179c 100644 --- a/sound/hda/hdac_sysfs.c +++ b/sound/hda/hdac_sysfs.c | |||
@@ -395,6 +395,7 @@ static int widget_tree_create(struct hdac_device *codec) | |||
395 | return 0; | 395 | return 0; |
396 | } | 396 | } |
397 | 397 | ||
398 | /* call with codec->widget_lock held */ | ||
398 | int hda_widget_sysfs_init(struct hdac_device *codec) | 399 | int hda_widget_sysfs_init(struct hdac_device *codec) |
399 | { | 400 | { |
400 | int err; | 401 | int err; |
@@ -411,11 +412,13 @@ int hda_widget_sysfs_init(struct hdac_device *codec) | |||
411 | return 0; | 412 | return 0; |
412 | } | 413 | } |
413 | 414 | ||
415 | /* call with codec->widget_lock held */ | ||
414 | void hda_widget_sysfs_exit(struct hdac_device *codec) | 416 | void hda_widget_sysfs_exit(struct hdac_device *codec) |
415 | { | 417 | { |
416 | widget_tree_free(codec); | 418 | widget_tree_free(codec); |
417 | } | 419 | } |
418 | 420 | ||
421 | /* call with codec->widget_lock held */ | ||
419 | int hda_widget_sysfs_reinit(struct hdac_device *codec, | 422 | int hda_widget_sysfs_reinit(struct hdac_device *codec, |
420 | hda_nid_t start_nid, int num_nodes) | 423 | hda_nid_t start_nid, int num_nodes) |
421 | { | 424 | { |