aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.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/osl.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/osl.c')
-rw-r--r--drivers/acpi/osl.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 235a1386888a..750e0df15604 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -682,6 +682,22 @@ static void acpi_os_execute_deferred(struct work_struct *work)
682 return; 682 return;
683} 683}
684 684
685static void acpi_os_execute_hp_deferred(struct work_struct *work)
686{
687 struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
688 if (!dpc) {
689 printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
690 return;
691 }
692
693 acpi_os_wait_events_complete(NULL);
694
695 dpc->function(dpc->context);
696 kfree(dpc);
697
698 return;
699}
700
685/******************************************************************************* 701/*******************************************************************************
686 * 702 *
687 * FUNCTION: acpi_os_execute 703 * FUNCTION: acpi_os_execute
@@ -697,12 +713,13 @@ static void acpi_os_execute_deferred(struct work_struct *work)
697 * 713 *
698 ******************************************************************************/ 714 ******************************************************************************/
699 715
700acpi_status acpi_os_execute(acpi_execute_type type, 716static acpi_status __acpi_os_execute(acpi_execute_type type,
701 acpi_osd_exec_callback function, void *context) 717 acpi_osd_exec_callback function, void *context, int hp)
702{ 718{
703 acpi_status status = AE_OK; 719 acpi_status status = AE_OK;
704 struct acpi_os_dpc *dpc; 720 struct acpi_os_dpc *dpc;
705 struct workqueue_struct *queue; 721 struct workqueue_struct *queue;
722 int ret;
706 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 723 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
707 "Scheduling function [%p(%p)] for deferred execution.\n", 724 "Scheduling function [%p(%p)] for deferred execution.\n",
708 function, context)); 725 function, context));
@@ -726,9 +743,17 @@ acpi_status acpi_os_execute(acpi_execute_type type,
726 dpc->function = function; 743 dpc->function = function;
727 dpc->context = context; 744 dpc->context = context;
728 745
729 INIT_WORK(&dpc->work, acpi_os_execute_deferred); 746 if (!hp) {
730 queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq; 747 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
731 if (!queue_work(queue, &dpc->work)) { 748 queue = (type == OSL_NOTIFY_HANDLER) ?
749 kacpi_notify_wq : kacpid_wq;
750 ret = queue_work(queue, &dpc->work);
751 } else {
752 INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
753 ret = schedule_work(&dpc->work);
754 }
755
756 if (!ret) {
732 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 757 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
733 "Call to queue_work() failed.\n")); 758 "Call to queue_work() failed.\n"));
734 status = AE_ERROR; 759 status = AE_ERROR;
@@ -737,8 +762,19 @@ acpi_status acpi_os_execute(acpi_execute_type type,
737 return_ACPI_STATUS(status); 762 return_ACPI_STATUS(status);
738} 763}
739 764
765acpi_status acpi_os_execute(acpi_execute_type type,
766 acpi_osd_exec_callback function, void *context)
767{
768 return __acpi_os_execute(type, function, context, 0);
769}
740EXPORT_SYMBOL(acpi_os_execute); 770EXPORT_SYMBOL(acpi_os_execute);
741 771
772acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
773 void *context)
774{
775 return __acpi_os_execute(0, function, context, 1);
776}
777
742void acpi_os_wait_events_complete(void *context) 778void acpi_os_wait_events_complete(void *context)
743{ 779{
744 flush_workqueue(kacpid_wq); 780 flush_workqueue(kacpid_wq);