From 19cd847ab24fefe9e50101ec94479e0400a08650 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 28 Aug 2008 10:05:06 +0800 Subject: 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 Signed-off-by: Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/dock.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/acpi/dock.c') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 2563bc62987..4b395b1e61b 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) } } +struct dock_data { + acpi_handle handle; + unsigned long event; + struct dock_station *ds; +}; + +static void acpi_dock_deferred_cb(void *context) +{ + struct dock_data *data = (struct dock_data *)context; + + dock_notify(data->handle, data->event, data->ds); + kfree(data); +} + static int acpi_dock_notifier_call(struct notifier_block *this, unsigned long event, void *data) { @@ -759,7 +773,16 @@ static int acpi_dock_notifier_call(struct notifier_block *this, return 0; list_for_each_entry(dock_station, &dock_stations, sibiling) { if (dock_station->handle == handle) { - dock_notify(handle, event, dock_station); + struct dock_data *dock_data; + + dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL); + if (!dock_data) + return 0; + dock_data->handle = handle; + dock_data->event = event; + dock_data->ds = dock_station; + acpi_os_hotplug_execute(acpi_dock_deferred_cb, + dock_data); return 0 ; } } -- cgit v1.2.3