aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2015-06-16 16:27:54 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-06-19 01:11:14 +0200
commit2a8b18e9fb650ab5c637005a7506045c46ed2b0e (patch)
tree637a4660e3ba3e89e8c3bea3b709712c4bcb333e /drivers/acpi
parentACPI / video: Move dmi_check_system from module_init to acpi_video_register (diff)
downloadlinux-dev-2a8b18e9fb650ab5c637005a7506045c46ed2b0e.tar.xz
linux-dev-2a8b18e9fb650ab5c637005a7506045c46ed2b0e.zip
ACPI / video: Fix acpi_video _register vs _unregister_backlight race
It is possible for a native backlight driver to load while acpi_video_register is running, which may lead to acpi_video_unregister_backlight being called while acpi_video_register is running and the 2 racing against eachother. The register_count variable protects against this, but not in a thread safe manner, this commit adds locking to make this thread safe. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Darren Hart <dvhart@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/acpi_video.c43
1 files changed, 21 insertions, 22 deletions
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index efa0ab553aa3..5b877a127167 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -82,6 +82,7 @@ static int disable_backlight_sysfs_if = -1;
module_param(disable_backlight_sysfs_if, int, 0444);
static int register_count;
+static DEFINE_MUTEX(register_count_mutex);
static struct mutex video_list_lock;
static struct list_head video_bus_head;
static int acpi_video_bus_add(struct acpi_device *device);
@@ -1964,14 +1965,15 @@ static int __init intel_opregion_present(void)
int acpi_video_register(void)
{
- int ret;
+ int ret = 0;
+ mutex_lock(&register_count_mutex);
if (register_count) {
/*
* if the function of acpi_video_register is already called,
* don't register the acpi_vide_bus again and return no error.
*/
- return 0;
+ goto leave;
}
mutex_init(&video_list_lock);
@@ -1981,7 +1983,7 @@ int acpi_video_register(void)
ret = acpi_bus_register_driver(&acpi_video_bus);
if (ret)
- return ret;
+ goto leave;
/*
* When the acpi_video_bus is loaded successfully, increase
@@ -1989,24 +1991,20 @@ int acpi_video_register(void)
*/
register_count = 1;
- return 0;
+leave:
+ mutex_unlock(&register_count_mutex);
+ return ret;
}
EXPORT_SYMBOL(acpi_video_register);
void acpi_video_unregister(void)
{
- if (!register_count) {
- /*
- * If the acpi video bus is already unloaded, don't
- * unload it again and return directly.
- */
- return;
+ mutex_lock(&register_count_mutex);
+ if (register_count) {
+ acpi_bus_unregister_driver(&acpi_video_bus);
+ register_count = 0;
}
- acpi_bus_unregister_driver(&acpi_video_bus);
-
- register_count = 0;
-
- return;
+ mutex_unlock(&register_count_mutex);
}
EXPORT_SYMBOL(acpi_video_unregister);
@@ -2014,13 +2012,14 @@ void acpi_video_unregister_backlight(void)
{
struct acpi_video_bus *video;
- if (!register_count)
- return;
-
- mutex_lock(&video_list_lock);
- list_for_each_entry(video, &video_bus_head, entry)
- acpi_video_bus_unregister_backlight(video);
- mutex_unlock(&video_list_lock);
+ mutex_lock(&register_count_mutex);
+ if (register_count) {
+ mutex_lock(&video_list_lock);
+ list_for_each_entry(video, &video_bus_head, entry)
+ acpi_video_bus_unregister_backlight(video);
+ mutex_unlock(&video_list_lock);
+ }
+ mutex_unlock(&register_count_mutex);
}
EXPORT_SYMBOL(acpi_video_unregister_backlight);