ALSA: control: Fix power_ref lock order for compat code, too
authorTakashi Iwai <tiwai@suse.de>
Thu, 8 Aug 2024 16:31:27 +0000 (18:31 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 8 Aug 2024 16:31:54 +0000 (18:31 +0200)
In the previous change for swapping the power_ref and controls_rwsem
lock order, the code path for the compat layer was forgotten.
This patch covers the remaining code.

Fixes: fcc62b19104a ("ALSA: control: Take power_ref lock primarily")
Link: https://patch.msgid.link/20240808163128.20383-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/control_compat.c

index 934bb94..ff0031c 100644 (file)
@@ -79,6 +79,7 @@ struct snd_ctl_elem_info32 {
 static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
                                    struct snd_ctl_elem_info32 __user *data32)
 {
+       struct snd_card *card = ctl->card;
        struct snd_ctl_elem_info *data __free(kfree) = NULL;
        int err;
 
@@ -95,7 +96,11 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
        if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
                return -EFAULT;
 
+       err = snd_power_ref_and_wait(card);
+       if (err < 0)
+               return err;
        err = snd_ctl_elem_info(ctl, data);
+       snd_power_unref(card);
        if (err < 0)
                return err;
        /* restore info to 32bit */
@@ -175,10 +180,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
        if (info == NULL)
                return -ENOMEM;
        info->id = *id;
-       err = snd_power_ref_and_wait(card);
-       if (!err)
-               err = kctl->info(kctl, info);
-       snd_power_unref(card);
+       err = kctl->info(kctl, info);
        if (err >= 0) {
                err = info->type;
                *countp = info->count;
@@ -275,8 +277,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
        return 0;
 }
 
-static int ctl_elem_read_user(struct snd_card *card,
-                             void __user *userdata, void __user *valuep)
+static int __ctl_elem_read_user(struct snd_card *card,
+                               void __user *userdata, void __user *valuep)
 {
        struct snd_ctl_elem_value *data __free(kfree) = NULL;
        int err, type, count;
@@ -296,8 +298,21 @@ static int ctl_elem_read_user(struct snd_card *card,
        return copy_ctl_value_to_user(userdata, valuep, data, type, count);
 }
 
-static int ctl_elem_write_user(struct snd_ctl_file *file,
-                              void __user *userdata, void __user *valuep)
+static int ctl_elem_read_user(struct snd_card *card,
+                             void __user *userdata, void __user *valuep)
+{
+       int err;
+
+       err = snd_power_ref_and_wait(card);
+       if (err < 0)
+               return err;
+       err = __ctl_elem_read_user(card, userdata, valuep);
+       snd_power_unref(card);
+       return err;
+}
+
+static int __ctl_elem_write_user(struct snd_ctl_file *file,
+                                void __user *userdata, void __user *valuep)
 {
        struct snd_ctl_elem_value *data __free(kfree) = NULL;
        struct snd_card *card = file->card;
@@ -318,6 +333,20 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
        return copy_ctl_value_to_user(userdata, valuep, data, type, count);
 }
 
+static int ctl_elem_write_user(struct snd_ctl_file *file,
+                              void __user *userdata, void __user *valuep)
+{
+       struct snd_card *card = file->card;
+       int err;
+
+       err = snd_power_ref_and_wait(card);
+       if (err < 0)
+               return err;
+       err = __ctl_elem_write_user(file, userdata, valuep);
+       snd_power_unref(card);
+       return err;
+}
+
 static int snd_ctl_elem_read_user_compat(struct snd_card *card,
                                         struct snd_ctl_elem_value32 __user *data32)
 {