[PATCH v3 1/5] ALSA: hda: Serialize codec probe and remove on the same bus
From: Cen Zhang
Date: Fri Oct 30 2026 - 04:05:56 EST
The probe and remove of different codecs on one HD-audio bus can run at
the same time, for example when two codecs are bound and unbound through
sysfs. A codec probe on a registered card calls snd_card_register(),
which walks card->devices in snd_device_register_all(), while the remove
of another codec frees its PCMs and deletes them from the same list.
The list has no lock of its own.
Add a mutex to struct hdac_bus and hold it in hda_codec_driver_probe()
and hda_codec_driver_remove(). The ASoC ext_ops paths are unchanged.
Fixes: bcd96557bd0a ("ALSA: hda - Build PCMs and controls at codec driver probe")
Suggested-by: Takashi Iwai <tiwai@xxxxxxx>
Signed-off-by: Cen Zhang <zzzccc427@xxxxxxxxx>
---
include/sound/hdaudio.h | 1 +
sound/hda/common/bind.c | 7 +++++++
sound/hda/core/bus.c | 1 +
3 files changed, 9 insertions(+)
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 04fd4794bcee..066d2fef3986 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -367,6 +367,7 @@ struct hdac_bus {
spinlock_t reg_lock;
struct mutex cmd_mutex;
struct mutex lock;
+ struct mutex codec_bind_lock; /* codec driver probe and remove */
/* DRM component interface */
struct drm_audio_component *audio_component;
diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c
index 957feace0f58..abbb3b64ec09 100644
--- a/sound/hda/common/bind.c
+++ b/sound/hda/common/bind.c
@@ -104,6 +104,12 @@ static int hda_codec_driver_probe(struct device *dev)
if (WARN_ON(!codec->preset))
return -EINVAL;
+ /*
+ * snd_card_register() below walks the device list of the card, which
+ * the removal of another codec changes when it frees its PCMs.
+ */
+ guard(mutex)(&codec->bus->core.codec_bind_lock);
+
err = snd_hda_codec_set_name(codec, codec->preset->name);
if (err < 0)
goto error;
@@ -171,6 +177,7 @@ static int hda_codec_driver_remove(struct device *dev)
return codec->bus->core.ext_ops->hdev_detach(&codec->core);
}
+ guard(mutex)(&codec->bus->core.codec_bind_lock);
snd_hda_codec_disconnect_pcms(codec);
snd_hda_jack_tbl_disconnect(codec);
snd_refcount_sync(&codec->pcm_ref);
diff --git a/sound/hda/core/bus.c b/sound/hda/core/bus.c
index 02462bd035e7..304110c9a6a7 100644
--- a/sound/hda/core/bus.c
+++ b/sound/hda/core/bus.c
@@ -44,6 +44,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
spin_lock_init(&bus->reg_lock);
mutex_init(&bus->cmd_mutex);
mutex_init(&bus->lock);
+ mutex_init(&bus->codec_bind_lock);
INIT_LIST_HEAD(&bus->hlink_list);
init_waitqueue_head(&bus->rirb_wq);
bus->irq = -1;
--
2.43.0