summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorAlexey Starikovskiy <alexey.y.starikovskiy@linux.intel.com>2007-02-15 22:12:23 +0100
committerLen Brown <len.brown@intel.com>2007-02-15 22:13:16 +0100
commitc0d127b56937c3e72c2b1819161d2f6718eee877 (patch)
tree40ac0fd3a628685ce25d11d1b00360344279ec5b /drivers/acpi
parentMerge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa (diff)
downloadlinux-c0d127b56937c3e72c2b1819161d2f6718eee877.tar.xz
linux-c0d127b56937c3e72c2b1819161d2f6718eee877.zip
ACPICA: fix AML mutex re-entrancy
ACPI AML supports "serialized" methods which are protected by an implicit mutex. The mutex is re-entrant for that AML thread to allow recursion. However, Linux implements notify() by creating a new AML thread. So for systems where notify() re-enters a serialized method, deadlock results. The fix is to use the Linux thread_id as the key to allowing re-entrancy, not the AML thread pointer. http://bugzilla.kernel.org/show_bug.cgi?id=5534 Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@linux.intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c12
-rw-r--r--drivers/acpi/executer/exdump.c2
-rw-r--r--drivers/acpi/executer/exmutex.c36
-rw-r--r--drivers/acpi/utilities/utdelete.c1
4 files changed, 22 insertions, 29 deletions
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 1cbe61905824..1683e5c5b94c 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -231,10 +231,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
* Obtain the method mutex if necessary. Do not acquire mutex for a
* recursive call.
*/
- if (!walk_state ||
- !obj_desc->method.mutex->mutex.owner_thread ||
- (walk_state->thread !=
- obj_desc->method.mutex->mutex.owner_thread)) {
+ if (acpi_os_get_thread_id() !=
+ obj_desc->method.mutex->mutex.owner_thread_id) {
/*
* Acquire the method mutex. This releases the interpreter if we
* block (and reacquires it before it returns)
@@ -248,14 +246,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
}
/* Update the mutex and walk info and save the original sync_level */
+ obj_desc->method.mutex->mutex.owner_thread_id =
+ acpi_os_get_thread_id();
if (walk_state) {
obj_desc->method.mutex->mutex.
original_sync_level =
walk_state->thread->current_sync_level;
- obj_desc->method.mutex->mutex.owner_thread =
- walk_state->thread;
walk_state->thread->current_sync_level =
obj_desc->method.sync_level;
} else {
@@ -569,7 +567,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
acpi_os_release_mutex(method_desc->method.mutex->mutex.
os_mutex);
- method_desc->method.mutex->mutex.owner_thread = NULL;
+ method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
}
}
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 68d283fd60e7..1a73c14df2c5 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -134,7 +134,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[8] = {
static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread_id), "Owner Thread"},
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
"Acquire Depth"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 5101bad5baf8..4eb883bda6ae 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -66,10 +66,9 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
*
******************************************************************************/
-void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
+void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc,
+ struct acpi_thread_state *thread)
{
- struct acpi_thread_state *thread = obj_desc->mutex.owner_thread;
-
if (!thread) {
return;
}
@@ -174,16 +173,13 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Support for multiple acquires by the owning thread */
- if (obj_desc->mutex.owner_thread) {
- if (obj_desc->mutex.owner_thread->thread_id ==
- walk_state->thread->thread_id) {
- /*
- * The mutex is already owned by this thread, just increment the
- * acquisition depth
- */
- obj_desc->mutex.acquisition_depth++;
- return_ACPI_STATUS(AE_OK);
- }
+ if (obj_desc->mutex.owner_thread_id == acpi_os_get_thread_id()) {
+ /*
+ * The mutex is already owned by this thread, just increment the
+ * acquisition depth
+ */
+ obj_desc->mutex.acquisition_depth++;
+ return_ACPI_STATUS(AE_OK);
}
/* Acquire the mutex, wait if necessary. Special case for Global Lock */
@@ -206,7 +202,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Have the mutex: update mutex and walk info and save the sync_level */
- obj_desc->mutex.owner_thread = walk_state->thread;
+ obj_desc->mutex.owner_thread_id = acpi_os_get_thread_id();
obj_desc->mutex.acquisition_depth = 1;
obj_desc->mutex.original_sync_level =
walk_state->thread->current_sync_level;
@@ -246,7 +242,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
/* The mutex must have been previously acquired in order to release it */
- if (!obj_desc->mutex.owner_thread) {
+ if (!obj_desc->mutex.owner_thread_id) {
ACPI_ERROR((AE_INFO,
"Cannot release Mutex [%4.4s], not acquired",
acpi_ut_get_node_name(obj_desc->mutex.node)));
@@ -266,14 +262,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
* The Mutex is owned, but this thread must be the owner.
* Special case for Global Lock, any thread can release
*/
- if ((obj_desc->mutex.owner_thread->thread_id !=
+ if ((obj_desc->mutex.owner_thread_id !=
walk_state->thread->thread_id)
&& (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO,
"Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
(unsigned long)walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node),
- (unsigned long)obj_desc->mutex.owner_thread->thread_id));
+ (unsigned long)obj_desc->mutex.owner_thread_id));
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
@@ -300,7 +296,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
/* Unlink the mutex from the owner's list */
- acpi_ex_unlink_mutex(obj_desc);
+ acpi_ex_unlink_mutex(obj_desc, walk_state->thread);
/* Release the mutex, special case for Global Lock */
@@ -312,7 +308,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
/* Update the mutex and restore sync_level */
- obj_desc->mutex.owner_thread = NULL;
+ obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
walk_state->thread->current_sync_level =
obj_desc->mutex.original_sync_level;
@@ -367,7 +363,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
/* Mark mutex unowned */
- obj_desc->mutex.owner_thread = NULL;
+ obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
/* Update Thread sync_level (Last mutex is the important one) */
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index f777cebdc46d..673a0caa4073 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -170,7 +170,6 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
acpi_os_delete_mutex(object->mutex.os_mutex);
acpi_gbl_global_lock_mutex = NULL;
} else {
- acpi_ex_unlink_mutex(object);
acpi_os_delete_mutex(object->mutex.os_mutex);
}
break;