aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/dock.c
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2008-08-27 22:05:06 -0400
committerLen Brown <len.brown@intel.com>2008-09-23 23:12:38 -0400
commit19cd847ab24fefe9e50101ec94479e0400a08650 (patch)
tree9af663d1f43e59d6ce3f942d89b910dda5e1c542 /drivers/acpi/dock.c
parent6bd00a61ab63d4ceb635ae0316353c11c900b8d8 (diff)
ACPI: fix hotplug race
The hotplug notification handler and drivers' notification handler all run in one workqueue. Before hotplug removes an acpi device, the device driver's notification handler is already be recorded to run just after global notification handler. After hotplug notification handler runs, acpica will notice a NULL notification handler and crash. So now we run run hotplug in another workqueue and wait for all acpi notication handlers finish. This was found in battery hotplug, but actually all hotplug can be affected. Signed-off-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/dock.c')
-rw-r--r--drivers/acpi/dock.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 2563bc62987d..4b395b1e61b2 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -748,6 +748,20 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
748 } 748 }
749} 749}
750 750
751struct dock_data {
752 acpi_handle handle;
753 unsigned long event;
754 struct dock_station *ds;
755};
756
757static void acpi_dock_deferred_cb(void *context)
758{
759 struct dock_data *data = (struct dock_data *)context;
760
761 dock_notify(data->handle, data->event, data->ds);
762 kfree(data);
763}
764
751static int acpi_dock_notifier_call(struct notifier_block *this, 765static int acpi_dock_notifier_call(struct notifier_block *this,
752 unsigned long event, void *data) 766 unsigned long event, void *data)
753{ 767{
@@ -759,7 +773,16 @@ static int acpi_dock_notifier_call(struct notifier_block *this,
759 return 0; 773 return 0;
760 list_for_each_entry(dock_station, &dock_stations, sibiling) { 774 list_for_each_entry(dock_station, &dock_stations, sibiling) {
761 if (dock_station->handle == handle) { 775 if (dock_station->handle == handle) {
762 dock_notify(handle, event, dock_station); 776 struct dock_data *dock_data;
777
778 dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
779 if (!dock_data)
780 return 0;
781 dock_data->handle = handle;
782 dock_data->event = event;
783 dock_data->ds = dock_station;
784 acpi_os_hotplug_execute(acpi_dock_deferred_cb,
785 dock_data);
763 return 0 ; 786 return 0 ;
764 } 787 }
765 } 788 }