diff options
author | Hans de Goede <hdegoede@redhat.com> | 2021-01-25 22:09:09 +0300 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2021-01-27 20:48:12 +0300 |
commit | 041142d7d25294c17d39552ae51c1d8d89434010 (patch) | |
tree | e834236ddb32e7f84ba2b64061493a761c63eff0 /drivers/acpi | |
parent | 84f9017c37c479c4f70456a645d24d2296ad2208 (diff) | |
download | linux-041142d7d25294c17d39552ae51c1d8d89434010.tar.xz |
ACPI: platform-profile: Fix possible deadlock in platform_profile_remove()
After a rmmod thinkpad_acpi, lockdep pointed out this possible deadlock:
Our _show and _store sysfs attr functions get called with the kn->active
lock held for the sysfs attr and then take the profile_lock.
sysfs_remove_group() also takes the kn->active lock for the sysfs attr,
so if we call it with the profile_lock held, then we get an ABBA deadlock.
platform_profile_remove() must only be called by drivers which have
first *successfully* called platform_profile_register(). Anything else
is a driver bug. So the check for cur_profile being set before calling
sysfs_remove_group() is not necessary and it can be dropped.
It is safe to call sysfs_remove_group() without holding the profile_lock
since the attr-group group cannot be re-added until after we clear
cur_profile.
Change platform_profile_remove() to only hold the profile_lock while
clearing the cur_profile, fixing the deadlock.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/platform_profile.c | 8 |
1 files changed, 2 insertions, 6 deletions
diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c index 80e9df427eb8..4a59c5993bde 100644 --- a/drivers/acpi/platform_profile.c +++ b/drivers/acpi/platform_profile.c @@ -164,13 +164,9 @@ EXPORT_SYMBOL_GPL(platform_profile_register); int platform_profile_remove(void) { - mutex_lock(&profile_lock); - if (!cur_profile) { - mutex_unlock(&profile_lock); - return -ENODEV; - } - sysfs_remove_group(acpi_kobj, &platform_profile_group); + + mutex_lock(&profile_lock); cur_profile = NULL; mutex_unlock(&profile_lock); return 0; |