[PATCH] ALSA: core: Fix unintuitive behavior of snd_power_ref_and_wait()

From: Takashi Iwai

Date: Sun Jun 14 2026 - 05:05:30 EST


snd_power_ref_and_wait() takes the power refcount and doesn't leave it
no matter whether it returns an error or not. However, the majority
of callers don't expect but just returns without unreferencing in the
caller side upon errors.

For addressing the potential refcount unbalance, rather correct the
behavior of snd_power_ref_wait() to unreference upon returning an
error.

Note that the problem above is likely negligible; the function returns
an error only when the sound card is being shutdown, hence it doesn't
matter about the power refcount any longer at such a state.

Fixes: e94fdbd7b25d ("ALSA: control: Track in-flight control read/write/tlv accesses")
Reported-by: WenTao Liang <vulab@xxxxxxxxxxx>
Closes: https://lore.kernel.org/20260612022121.14329-1-vulab@xxxxxxxxxxx
Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
---
sound/core/init.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/sound/core/init.c b/sound/core/init.c
index ed5af4e0ec10..56dde5bd73c4 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -1139,7 +1139,7 @@ EXPORT_SYMBOL(snd_card_file_remove);
* typically around calling control ops.
*
* The caller needs to pull down the refcount via snd_power_unref() later
- * no matter whether the error is returned from this function or not.
+ * when this function returns 0.
*
* Return: Zero if successful, or a negative error code.
*/
@@ -1152,7 +1152,11 @@ int snd_power_ref_and_wait(struct snd_card *card)
card->shutdown ||
snd_power_get_state(card) == SNDRV_CTL_POWER_D0,
snd_power_unref(card), snd_power_ref(card));
- return card->shutdown ? -ENODEV : 0;
+ if (card->shutdown) {
+ snd_power_unref(card);
+ return -ENODEV;
+ }
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_power_ref_and_wait);

@@ -1169,7 +1173,8 @@ int snd_power_wait(struct snd_card *card)
int ret;

ret = snd_power_ref_and_wait(card);
- snd_power_unref(card);
+ if (!ret)
+ snd_power_unref(card);
return ret;
}
EXPORT_SYMBOL(snd_power_wait);
--
2.54.0