If for any reason multiple profile handlers don't agree on the profile set for the system then the value shown in sysfs can be wrong. Explicitly check that they match. Tested-by: Matthew Schwartz <matthew.schwartz@xxxxxxxxx> Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx> --- drivers/acpi/platform_profile.c | 61 ++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c index db2ebd0393cf7..d22c4eb5f0c36 100644 --- a/drivers/acpi/platform_profile.c +++ b/drivers/acpi/platform_profile.c @@ -51,6 +51,45 @@ static unsigned long platform_profile_get_choices(void) return seen; } +/* expected to be called under mutex */ +static int platform_profile_get_active(enum platform_profile_option *profile) +{ + struct platform_profile_handler *handler; + enum platform_profile_option active = PLATFORM_PROFILE_LAST; + enum platform_profile_option active2 = PLATFORM_PROFILE_LAST; + int err; + + list_for_each_entry(handler, &platform_profile_handler_list, list) { + if (active == PLATFORM_PROFILE_LAST) + err = handler->profile_get(handler, &active); + else + err = handler->profile_get(handler, &active2); + if (err) { + pr_err("Failed to get profile for handler %s\n", handler->name); + return err; + } + + if (WARN_ON(active == PLATFORM_PROFILE_LAST)) + return -EINVAL; + if (active2 == PLATFORM_PROFILE_LAST) + continue; + + if (active != active2) { + pr_warn("Profile handlers don't agree on current profile\n"); + return -EINVAL; + } + active = active2; + } + + /* Check that profile is valid index */ + if (WARN_ON((active < 0) || (active >= ARRAY_SIZE(profile_names)))) + return -EIO; + + *profile = active; + + return 0; +} + static ssize_t platform_profile_choices_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -80,24 +119,14 @@ static ssize_t platform_profile_show(struct device *dev, enum platform_profile_option profile = PLATFORM_PROFILE_BALANCED; int err; - err = mutex_lock_interruptible(&profile_lock); - if (err) - return err; - - if (!cur_profile) { - mutex_unlock(&profile_lock); - return -ENODEV; + scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { + if (!platform_profile_is_registered()) + return -ENODEV; + err = platform_profile_get_active(&profile); + if (err) + return err; } - err = cur_profile->profile_get(cur_profile, &profile); - mutex_unlock(&profile_lock); - if (err) - return err; - - /* Check that profile is valid index */ - if (WARN_ON((profile < 0) || (profile >= ARRAY_SIZE(profile_names)))) - return -EIO; - return sysfs_emit(buf, "%s\n", profile_names[profile]); } -- 2.43.0