[PATCH 8/8] ASoC: soc-dapm: Remove widget from cache on removal

From: Amadeusz Sławiński

Date: Wed Oct 14 2026 - 16:07:37 EST


When a single DAPM widget is removed, it also needs to be removed from
the widget cache to prevent dapm_wcache_lookup() from using a dangling
pointer when checking if a widget is in cache. Since widgets may be
cached across different DAPM contexts on the card (e.g. card routes),
clear any matching cache entries across all DAPM contexts on the card.
Since dapm_free_widgets() calls snd_soc_dapm_free_widget() anyway, it
does not need to clear cache anymore.

Signed-off-by: Amadeusz Sławiński <amade@xxxxxxxxxx>
---
sound/soc/soc-dapm.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 74be5e209493..7455160b11fe 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2869,6 +2869,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path)
*/
void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
{
+ struct snd_soc_dapm_context *d;
struct snd_soc_dapm_path *p, *next_p;
enum snd_soc_dapm_direction dir;

@@ -2889,6 +2890,22 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)

dapm_debugfs_free_widget(w);

+ if (w->dapm) {
+ if (w->dapm->card) {
+ for_each_card_dapms(w->dapm->card, d) {
+ if (d->wcache_sink == w)
+ d->wcache_sink = NULL;
+ if (d->wcache_source == w)
+ d->wcache_source = NULL;
+ }
+ } else {
+ if (w->dapm->wcache_sink == w)
+ w->dapm->wcache_sink = NULL;
+ if (w->dapm->wcache_source == w)
+ w->dapm->wcache_source = NULL;
+ }
+ }
+
kfree(w->kcontrols);
kfree_const(w->name);
kfree_const(w->sname);
@@ -2906,9 +2923,6 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
continue;
snd_soc_dapm_free_widget(w);
}
-
- dapm->wcache_sink = NULL;
- dapm->wcache_source = NULL;
}

static struct snd_soc_dapm_widget *dapm_find_widget(
--
2.56.0