diff options
author | Takashi Iwai <tiwai@suse.de> | 2017-06-28 13:02:02 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-07-05 15:37:15 +0300 |
commit | 11327be3570e4640bf9c19e60b724f9fbb21eeb6 (patch) | |
tree | b32cc3a64d8a23a71d481ef31696826d56125ff7 /sound/pci | |
parent | db60a2ec9acc938c2427cbba367f20f1b0505267 (diff) | |
download | linux-11327be3570e4640bf9c19e60b724f9fbb21eeb6.tar.xz |
ALSA: hda - Fix endless loop of codec configure
commit d94815f917da770d42c377786dc428f542e38f71 upstream.
azx_codec_configure() loops over the codecs found on the given
controller via a linked list. The code used to work in the past, but
in the current version, this may lead to an endless loop when a codec
binding returns an error.
The culprit is that the snd_hda_codec_configure() unregisters the
device upon error, and this eventually deletes the given codec object
from the bus. Since the list is initialized via list_del_init(), the
next object points to the same device itself. This behavior change
was introduced at splitting the HD-audio code code, and forgotten to
adapt it here.
For fixing this bug, just use a *_safe() version of list iteration.
Fixes: d068ebc25e6e ("ALSA: hda - Move some codes up to hdac_bus struct")
Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/hda_codec.h | 2 | ||||
-rw-r--r-- | sound/pci/hda/hda_controller.c | 8 |
2 files changed, 8 insertions, 2 deletions
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 373fcad840ea..776dffa88aee 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -294,6 +294,8 @@ struct hda_codec { #define list_for_each_codec(c, bus) \ list_for_each_entry(c, &(bus)->core.codec_list, core.list) +#define list_for_each_codec_safe(c, n, bus) \ + list_for_each_entry_safe(c, n, &(bus)->core.codec_list, core.list) /* snd_hda_codec_read/write optional flags */ #define HDA_RW_NO_RESPONSE_FALLBACK (1 << 0) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 5baf8b56b6e7..9c6e10fb479f 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1128,8 +1128,12 @@ EXPORT_SYMBOL_GPL(azx_probe_codecs); /* configure each codec instance */ int azx_codec_configure(struct azx *chip) { - struct hda_codec *codec; - list_for_each_codec(codec, &chip->bus) { + struct hda_codec *codec, *next; + + /* use _safe version here since snd_hda_codec_configure() deregisters + * the device upon error and deletes itself from the bus list. + */ + list_for_each_codec_safe(codec, next, &chip->bus) { snd_hda_codec_configure(codec); } return 0; |