]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ALSA: core: Fix unintuitive behavior of snd_power_ref_and_wait()
authorTakashi Iwai <tiwai@suse.de>
Sun, 14 Jun 2026 09:05:05 +0000 (11:05 +0200)
committerTakashi Iwai <tiwai@suse.de>
Sun, 14 Jun 2026 15:31:54 +0000 (17:31 +0200)
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@iscas.ac.cn>
Closes: https://lore.kernel.org/20260612022121.14329-1-vulab@iscas.ac.cn
Link: https://patch.msgid.link/20260614090507.772540-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/init.c

index ed5af4e0ec1051685afff195864a9cb9c1fa7c75..56dde5bd73c4ef632ec44a7a17f588a6dd38d602 100644 (file)
@@ -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);