From ae6f61870490c10a0b0436e5afffa00c9dacffef Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 30 Jun 2011 11:32:40 +0800 Subject: ACPI / Battery: Add the power unit macro This patch is cosmetic only, and makes no functional change. Signed-off-by: Lan Tianyu Signed-off-by: Len Brown --- drivers/acpi/battery.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index fcc13ac0aa1..611434f413d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -55,6 +55,9 @@ #define ACPI_BATTERY_NOTIFY_INFO 0x81 #define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 +/* Battery power unit: 0 means mW, 1 means mA */ +#define ACPI_BATTERY_POWER_UNIT_MA 1 + #define _COMPONENT ACPI_BATTERY_COMPONENT ACPI_MODULE_NAME("battery"); @@ -301,7 +304,8 @@ static enum power_supply_property energy_battery_props[] = { #ifdef CONFIG_ACPI_PROCFS_POWER inline char *acpi_battery_units(struct acpi_battery *battery) { - return (battery->power_unit)?"mA":"mW"; + return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ? + "mA" : "mW"; } #endif @@ -544,7 +548,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) { int result; - if (battery->power_unit) { + if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) { battery->bat.properties = charge_battery_props; battery->bat.num_properties = ARRAY_SIZE(charge_battery_props); @@ -575,7 +579,8 @@ static void sysfs_remove_battery(struct acpi_battery *battery) static void acpi_battery_quirks(struct acpi_battery *battery) { - if (dmi_name_in_vendors("Acer") && battery->power_unit) { + if (dmi_name_in_vendors("Acer") && + battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) { set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags); } } -- cgit v1.2.3-70-g09d2 From 55003b2105a4578736f3e868fbaa889bb1ff3ce0 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 30 Jun 2011 11:33:12 +0800 Subject: ACPI / Battery: Change 16-bit signed negative battery current into correct value This patch is for some machines which report the battery current as a 16-bit signed negative when it is charging. This is caused by DSDT bug. The commit bc76f90b8a5cf4aceedf210d08d5e8292f820cec has resolved the problem for Acer laptops. But some other machines also have such problem. https://bugzilla.kernel.org/show_bug.cgi?id=33722 Since it is improper that the current is above 32A on laptops whether on AC or on battery, this patch is to check the current and take its absolute value as current and producing a message when it is negative in s16. Remove Acer quirk, as this workaround handles Acer too. Signed-off-by: Lan Tianyu Signed-off-by: Len Brown --- drivers/acpi/battery.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 611434f413d..ff1ff70da38 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -94,11 +94,6 @@ MODULE_DEVICE_TABLE(acpi, battery_device_ids); enum { ACPI_BATTERY_ALARM_PRESENT, ACPI_BATTERY_XINFO_PRESENT, - /* For buggy DSDTs that report negative 16-bit values for either - * charging or discharging current and/or report 0 as 65536 - * due to bad math. - */ - ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, }; @@ -465,9 +460,17 @@ static int acpi_battery_get_state(struct acpi_battery *battery) battery->update_time = jiffies; kfree(buffer.pointer); - if (test_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags) && - battery->rate_now != -1) + /* For buggy DSDTs that report negative 16-bit values for either + * charging or discharging current and/or report 0 as 65536 + * due to bad math. + */ + if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA && + battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN && + (s16)(battery->rate_now) < 0) { battery->rate_now = abs((s16)battery->rate_now); + printk_once(KERN_WARNING FW_BUG "battery: (dis)charge rate" + " invalid.\n"); + } if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) && battery->capacity_now >= 0 && battery->capacity_now <= 100) @@ -577,14 +580,6 @@ static void sysfs_remove_battery(struct acpi_battery *battery) battery->bat.dev = NULL; } -static void acpi_battery_quirks(struct acpi_battery *battery) -{ - if (dmi_name_in_vendors("Acer") && - battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) { - set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags); - } -} - /* * According to the ACPI spec, some kinds of primary batteries can * report percentage battery remaining capacity directly to OS. @@ -628,7 +623,6 @@ static int acpi_battery_update(struct acpi_battery *battery) result = acpi_battery_get_info(battery); if (result) return result; - acpi_battery_quirks(battery); acpi_battery_init_alarm(battery); } if (!battery->bat.dev) -- cgit v1.2.3-70-g09d2 From 7b78622d0f9df9f274a319eea1494240119d3734 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 30 Jun 2011 11:33:27 +0800 Subject: ACPI / Battery: Rename acpi_battery_quirks2 with acpi_battery_quirks This patch is cosmetic only, and makes no functional change. Since the acpi_battery_quirks has been deleted, rename acpi_battery_quirks2 with acpi_battery_quirks to clean the code. Signed-off-by: Lan Tianyu Signed-off-by: Len Brown --- drivers/acpi/battery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index ff1ff70da38..ba7926fce4f 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -592,7 +592,7 @@ static void sysfs_remove_battery(struct acpi_battery *battery) * * Handle this correctly so that they won't break userspace. */ -static void acpi_battery_quirks2(struct acpi_battery *battery) +static void acpi_battery_quirks(struct acpi_battery *battery) { if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) return ; @@ -628,7 +628,7 @@ static int acpi_battery_update(struct acpi_battery *battery) if (!battery->bat.dev) sysfs_add_battery(battery); result = acpi_battery_get_state(battery); - acpi_battery_quirks2(battery); + acpi_battery_quirks(battery); return result; } -- cgit v1.2.3-70-g09d2 From d5a5911b3278bad6515a9958f7318f74d534ef64 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 30 Jun 2011 11:33:40 +0800 Subject: ACPI / Battery: Add the hibernation process in the battery_notify() The Commit 25be58215 has added a PM notifier to refresh the sys in order to deal with the unit change of the Battery Present Rate. But it just consided the suspend situation. The problem also will happen during the hibernation according the bug 28192. https://bugzilla.kernel.org/show_bug.cgi?id=28192 This patch adds the hibernation process and fix the bug. Signed-off-by: Lan Tianyu Signed-off-by: Len Brown --- drivers/acpi/battery.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index ba7926fce4f..2fe7cfd9568 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -947,6 +947,7 @@ static int battery_notify(struct notifier_block *nb, struct acpi_battery *battery = container_of(nb, struct acpi_battery, pm_nb); switch (mode) { + case PM_POST_HIBERNATION: case PM_POST_SUSPEND: sysfs_remove_battery(battery); sysfs_add_battery(battery); -- cgit v1.2.3-70-g09d2 From 6e17fb6aa1a67afa1827ae317c3594040f055730 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 30 Jun 2011 11:33:58 +0800 Subject: ACPI / Battery: Add the check before refresh sysfs in the battery_notify() In the commit 25be5821, add the refresh sysfs when system resumes from suspending. But it didn't check that the battery exists. This will cause battery sysfs files added when the battery doesn't exist. This patch add the check before refreshing. https://bugzilla.kernel.org/show_bug.cgi?id=35642 Signed-off-by: Lan Tianyu Signed-off-by: Len Brown --- drivers/acpi/battery.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 2fe7cfd9568..4ba339d0ea1 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -949,8 +949,10 @@ static int battery_notify(struct notifier_block *nb, switch (mode) { case PM_POST_HIBERNATION: case PM_POST_SUSPEND: - sysfs_remove_battery(battery); - sysfs_add_battery(battery); + if (battery->bat.dev) { + sysfs_remove_battery(battery); + sysfs_add_battery(battery); + } break; } -- cgit v1.2.3-70-g09d2 From 9c921c22a7f33397a6774d7fa076db9b6a0fd669 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Thu, 30 Jun 2011 11:34:12 +0800 Subject: ACPI / Battery: Resolve the race condition in the sysfs_remove_battery() Use battery->lock in sysfs_remove_battery() to make checking, removing, and clearing bat.dev atomic. This is necessary because sysfs_remove_battery() may be invoked concurrently from different paths. https://bugzilla.kernel.org/show_bug.cgi?id=35642 Signed-off-by: Lan Tianyu Signed-off-by: Len Brown --- drivers/acpi/battery.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 4ba339d0ea1..40bf01d42cc 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -573,11 +573,16 @@ static int sysfs_add_battery(struct acpi_battery *battery) static void sysfs_remove_battery(struct acpi_battery *battery) { - if (!battery->bat.dev) + mutex_lock(&battery->lock); + if (!battery->bat.dev) { + mutex_unlock(&battery->lock); return; + } + device_remove_file(battery->bat.dev, &alarm_attr); power_supply_unregister(&battery->bat); battery->bat.dev = NULL; + mutex_unlock(&battery->lock); } /* -- cgit v1.2.3-70-g09d2 From 9c8b04be443b33939f374a811c82abeebe0a61d1 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Sat, 25 Jun 2011 21:07:52 +0400 Subject: ACPI: constify ops structs Structs battery_file, acpi_dock_ops, file_operations, thermal_cooling_device_ops, thermal_zone_device_ops, kernel_param_ops are not changed in runtime. It is safe to make them const. register_hotplug_dock_device() was altered to take const "ops" argument to respect acpi_dock_ops' const notion. Signed-off-by: Vasiliy Kulikov Acked-by: Jeff Garzik Signed-off-by: Len Brown --- drivers/acpi/battery.c | 2 +- drivers/acpi/dock.c | 4 ++-- drivers/acpi/ec_sys.c | 2 +- drivers/acpi/fan.c | 2 +- drivers/acpi/processor_thermal.c | 2 +- drivers/acpi/sysfs.c | 4 ++-- drivers/acpi/thermal.c | 2 +- drivers/acpi/video.c | 2 +- drivers/ata/libata-acpi.c | 4 ++-- drivers/pci/hotplug/acpiphp_glue.c | 2 +- include/acpi/acpi_drivers.h | 2 +- include/acpi/processor.h | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index fcc13ac0aa1..746b47507e9 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -863,7 +863,7 @@ DECLARE_FILE_FUNCTIONS(alarm); }, \ } -static struct battery_file { +static const struct battery_file { struct file_operations ops; mode_t mode; const char *name; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 1864ad3cf89..19a61136d84 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -77,7 +77,7 @@ struct dock_dependent_device { struct list_head list; struct list_head hotplug_list; acpi_handle handle; - struct acpi_dock_ops *ops; + const struct acpi_dock_ops *ops; void *context; }; @@ -589,7 +589,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); * the dock driver after _DCK is executed. */ int -register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, +register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, void *context) { struct dock_dependent_device *dd; diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 05b44201a61..22f918bacd3 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -92,7 +92,7 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf, return count; } -static struct file_operations acpi_ec_io_ops = { +static const struct file_operations acpi_ec_io_ops = { .owner = THIS_MODULE, .open = acpi_ec_open_io, .read = acpi_ec_read_io, diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 467479f07c1..0f0356ca1a9 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -110,7 +110,7 @@ fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) return result; } -static struct thermal_cooling_device_ops fan_cooling_ops = { +static const struct thermal_cooling_device_ops fan_cooling_ops = { .get_max_state = fan_get_max_state, .get_cur_state = fan_get_cur_state, .set_cur_state = fan_set_cur_state, diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 79cb6533289..870550d6a4b 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -244,7 +244,7 @@ processor_set_cur_state(struct thermal_cooling_device *cdev, return result; } -struct thermal_cooling_device_ops processor_cooling_ops = { +const struct thermal_cooling_device_ops processor_cooling_ops = { .get_max_state = processor_get_max_state, .get_cur_state = processor_get_cur_state, .set_cur_state = processor_set_cur_state, diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 77255f250db..c538d0ef10f 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -149,12 +149,12 @@ static int param_get_debug_level(char *buffer, const struct kernel_param *kp) return result; } -static struct kernel_param_ops param_ops_debug_layer = { +static const struct kernel_param_ops param_ops_debug_layer = { .set = param_set_uint, .get = param_get_debug_layer, }; -static struct kernel_param_ops param_ops_debug_level = { +static const struct kernel_param_ops param_ops_debug_level = { .set = param_set_uint, .get = param_get_debug_level, }; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 2607e17b520..48fbc647b17 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -812,7 +812,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, thermal_zone_unbind_cooling_device); } -static struct thermal_zone_device_ops acpi_thermal_zone_ops = { +static const struct thermal_zone_device_ops acpi_thermal_zone_ops = { .bind = acpi_thermal_bind_cooling_device, .unbind = acpi_thermal_unbind_cooling_device, .get_temp = thermal_get_temp, diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index db39e9e607d..c6f9ef8d9cc 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -308,7 +308,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st return acpi_video_device_lcd_set_level(video, level); } -static struct thermal_cooling_device_ops video_cooling_ops = { +static const struct thermal_cooling_device_ops video_cooling_ops = { .get_max_state = video_get_max_state, .get_cur_state = video_get_cur_state, .set_cur_state = video_set_cur_state, diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index a791b8ce629..993d40620f9 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -218,12 +218,12 @@ static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) ata_acpi_uevent(dev->link->ap, dev, event); } -static struct acpi_dock_ops ata_acpi_dev_dock_ops = { +static const struct acpi_dock_ops ata_acpi_dev_dock_ops = { .handler = ata_acpi_dev_notify_dock, .uevent = ata_acpi_dev_uevent, }; -static struct acpi_dock_ops ata_acpi_ap_dock_ops = { +static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { .handler = ata_acpi_ap_notify_dock, .uevent = ata_acpi_ap_uevent, }; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a70fa89f76f..220285760b6 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -110,7 +110,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, } -static struct acpi_dock_ops acpiphp_dock_ops = { +static const struct acpi_dock_ops acpiphp_dock_ops = { .handler = handle_hotplug_event_func, }; diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 3090471b2a5..e49c36d38d7 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -128,7 +128,7 @@ extern int is_dock_device(acpi_handle handle); extern int register_dock_notifier(struct notifier_block *nb); extern void unregister_dock_notifier(struct notifier_block *nb); extern int register_hotplug_dock_device(acpi_handle handle, - struct acpi_dock_ops *ops, + const struct acpi_dock_ops *ops, void *context); extern void unregister_hotplug_dock_device(acpi_handle handle); #else diff --git a/include/acpi/processor.h b/include/acpi/processor.h index ba4928cae47..67055f18033 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -337,7 +337,7 @@ extern struct cpuidle_driver acpi_idle_driver; /* in processor_thermal.c */ int acpi_processor_get_limit_info(struct acpi_processor *pr); -extern struct thermal_cooling_device_ops processor_cooling_ops; +extern const struct thermal_cooling_device_ops processor_cooling_ops; #ifdef CONFIG_CPU_FREQ void acpi_thermal_cpufreq_init(void); void acpi_thermal_cpufreq_exit(void); -- cgit v1.2.3-70-g09d2 From e80bba4b5108c6479379740201b0a5d9da5ffbac Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 12 Jul 2011 09:03:28 +0100 Subject: ACPI / Battery: avoid acpi_battery_add() use-after-free When acpi_battery_add_fs() fails the error handling code does not clean up completely. Moreover, it does not return resulting in a use-after-free. Signed-off-by: Stefan Hajnoczi Signed-off-by: Len Brown --- drivers/acpi/battery.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 40bf01d42cc..c771768f57c 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -986,21 +986,27 @@ static int acpi_battery_add(struct acpi_device *device) #ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); #endif - if (!result) { - printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", - ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), - device->status.battery_present ? "present" : "absent"); - } else { + if (result) { #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif - kfree(battery); + goto fail; } + printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", + ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), + device->status.battery_present ? "present" : "absent"); + battery->pm_nb.notifier_call = battery_notify; register_pm_notifier(&battery->pm_nb); return result; + +fail: + sysfs_remove_battery(battery); + mutex_destroy(&battery->lock); + kfree(battery); + return result; } static int acpi_battery_remove(struct acpi_device *device, int type) -- cgit v1.2.3-70-g09d2 From eb03cb02b74df6dd0b653d5f6d976f16a434dfaf Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 12 Jul 2011 09:03:29 +0100 Subject: ACPI / Battery: propagate sysfs error in acpi_battery_add() Make sure the error return from sysfs_add_battery() is checked and propagated out from acpi_battery_add(). Signed-off-by: Stefan Hajnoczi Signed-off-by: Len Brown --- drivers/acpi/battery.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index c771768f57c..ffce2f06dd8 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -630,8 +630,11 @@ static int acpi_battery_update(struct acpi_battery *battery) return result; acpi_battery_init_alarm(battery); } - if (!battery->bat.dev) - sysfs_add_battery(battery); + if (!battery->bat.dev) { + result = sysfs_add_battery(battery); + if (result) + return result; + } result = acpi_battery_get_state(battery); acpi_battery_quirks(battery); return result; @@ -982,7 +985,9 @@ static int acpi_battery_add(struct acpi_device *device) if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, "_BIX", &handle))) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); - acpi_battery_update(battery); + result = acpi_battery_update(battery); + if (result) + goto fail; #ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); #endif -- cgit v1.2.3-70-g09d2 From 69d94ec6d83d84044252d9ba03f6a8970816e350 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Sat, 6 Aug 2011 01:34:08 +0300 Subject: Battery: sysfs_remove_battery(): possible circular locking Commit 9c921c22a7f33397a6774d7fa076db9b6a0fd669 Author: Lan Tianyu ACPI / Battery: Resolve the race condition in the sysfs_remove_battery() fixed BUG https://bugzilla.kernel.org/show_bug.cgi?id=35642 , but as a side effect made lockdep unhappy with sysfs_remove_battery(): [14818.477168] [14818.477170] ======================================================= [14818.477200] [ INFO: possible circular locking dependency detected ] [14818.477221] 3.1.0-dbg-07865-g1280ea8-dirty #668 [14818.477236] ------------------------------------------------------- [14818.477257] s2ram/1599 is trying to acquire lock: [14818.477276] (s_active#8){++++.+}, at: [] sysfs_addrm_finish+0x31/0x5a [14818.477323] [14818.477325] but task is already holding lock: [14818.477350] (&battery->lock){+.+.+.}, at: [] sysfs_remove_battery+0x10/0x4b [battery] [14818.477395] [14818.477397] which lock already depends on the new lock. [14818.477399] [..] [14818.479121] stack backtrace: [14818.479148] Pid: 1599, comm: s2ram Not tainted 3.1.0-dbg-07865-g1280ea8-dirty #668 [14818.479175] Call Trace: [14818.479198] [] print_circular_bug+0x293/0x2a4 [14818.479228] [] __lock_acquire+0xfe4/0x164b [14818.479260] [] ? sysfs_addrm_finish+0x31/0x5a [14818.479288] [] lock_acquire+0x138/0x1ac [14818.479316] [] ? sysfs_addrm_finish+0x31/0x5a [14818.479345] [] sysfs_deactivate+0x9b/0xec [14818.479373] [] ? sysfs_addrm_finish+0x31/0x5a [14818.479405] [] sysfs_addrm_finish+0x31/0x5a [14818.479433] [] sysfs_hash_and_remove+0x54/0x77 [14818.479461] [] sysfs_remove_file+0x12/0x14 [14818.479488] [] device_remove_file+0x12/0x14 [14818.479516] [] device_del+0x119/0x17c [14818.479542] [] device_unregister+0xe/0x1a [14818.479570] [] power_supply_unregister+0x23/0x27 [14818.479601] [] sysfs_remove_battery+0x34/0x4b [battery] [14818.479632] [] battery_notify+0x2c/0x3a [battery] [14818.479662] [] notifier_call_chain+0x74/0xa1 [14818.479692] [] __blocking_notifier_call_chain+0x6c/0x89 [14818.479722] [] blocking_notifier_call_chain+0xf/0x11 [14818.479751] [] pm_notifier_call_chain+0x15/0x27 [14818.479770] [] enter_state+0xa7/0xd5 [14818.479782] [] state_store+0xaa/0xc0 [14818.479795] [] ? pm_async_store+0x45/0x45 [14818.479807] [] kobj_attr_store+0x17/0x19 [14818.479820] [] sysfs_write_file+0x103/0x13f [14818.479834] [] vfs_write+0xad/0x13d [14818.479847] [] sys_write+0x45/0x6c [14818.479860] [] system_call_fastpath+0x16/0x1b This patch introduces separate lock to struct acpi_battery to grab in sysfs_remove_battery() instead of battery->lock. So fix by Lan Tianyu is still there, we just grab independent lock. Signed-off-by: Sergey Senozhatsky Tested-by: Lan Tianyu Signed-off-by: Len Brown --- drivers/acpi/battery.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/acpi/battery.c') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index ffce2f06dd8..8953b708709 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -99,6 +99,7 @@ enum { struct acpi_battery { struct mutex lock; + struct mutex sysfs_lock; struct power_supply bat; struct acpi_device *device; struct notifier_block pm_nb; @@ -573,16 +574,16 @@ static int sysfs_add_battery(struct acpi_battery *battery) static void sysfs_remove_battery(struct acpi_battery *battery) { - mutex_lock(&battery->lock); + mutex_lock(&battery->sysfs_lock); if (!battery->bat.dev) { - mutex_unlock(&battery->lock); + mutex_unlock(&battery->sysfs_lock); return; } device_remove_file(battery->bat.dev, &alarm_attr); power_supply_unregister(&battery->bat); battery->bat.dev = NULL; - mutex_unlock(&battery->lock); + mutex_unlock(&battery->sysfs_lock); } /* @@ -982,6 +983,7 @@ static int acpi_battery_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); device->driver_data = battery; mutex_init(&battery->lock); + mutex_init(&battery->sysfs_lock); if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, "_BIX", &handle))) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); @@ -1010,6 +1012,7 @@ static int acpi_battery_add(struct acpi_device *device) fail: sysfs_remove_battery(battery); mutex_destroy(&battery->lock); + mutex_destroy(&battery->sysfs_lock); kfree(battery); return result; } @@ -1027,6 +1030,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type) #endif sysfs_remove_battery(battery); mutex_destroy(&battery->lock); + mutex_destroy(&battery->sysfs_lock); kfree(battery); return 0; } -- cgit v1.2.3-70-g09d2