Commit c0d127b5 authored by Alexey Starikovskiy's avatar Alexey Starikovskiy Committed by Len Brown

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=5534Signed-off-by: default avatarAlexey Starikovskiy <alexey.y.starikovskiy@linux.intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 724339d7
...@@ -231,10 +231,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, ...@@ -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 * Obtain the method mutex if necessary. Do not acquire mutex for a
* recursive call. * recursive call.
*/ */
if (!walk_state || if (acpi_os_get_thread_id() !=
!obj_desc->method.mutex->mutex.owner_thread || obj_desc->method.mutex->mutex.owner_thread_id) {
(walk_state->thread !=
obj_desc->method.mutex->mutex.owner_thread)) {
/* /*
* Acquire the method mutex. This releases the interpreter if we * Acquire the method mutex. This releases the interpreter if we
* block (and reacquires it before it returns) * block (and reacquires it before it returns)
...@@ -248,14 +246,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, ...@@ -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 */ /* 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) { if (walk_state) {
obj_desc->method.mutex->mutex. obj_desc->method.mutex->mutex.
original_sync_level = original_sync_level =
walk_state->thread->current_sync_level; walk_state->thread->current_sync_level;
obj_desc->method.mutex->mutex.owner_thread =
walk_state->thread;
walk_state->thread->current_sync_level = walk_state->thread->current_sync_level =
obj_desc->method.sync_level; obj_desc->method.sync_level;
} else { } else {
...@@ -569,7 +567,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, ...@@ -569,7 +567,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
acpi_os_release_mutex(method_desc->method.mutex->mutex. acpi_os_release_mutex(method_desc->method.mutex->mutex.
os_mutex); os_mutex);
method_desc->method.mutex->mutex.owner_thread = NULL; method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
} }
} }
......
...@@ -134,7 +134,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[8] = { ...@@ -134,7 +134,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[8] = {
static struct acpi_exdump_info acpi_ex_dump_mutex[5] = { static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL}, {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_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), {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
"Acquire Depth"}, "Acquire Depth"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"} {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
......
...@@ -66,10 +66,9 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc, ...@@ -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) { if (!thread) {
return; return;
} }
...@@ -174,16 +173,13 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, ...@@ -174,16 +173,13 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Support for multiple acquires by the owning thread */ /* Support for multiple acquires by the owning thread */
if (obj_desc->mutex.owner_thread) { if (obj_desc->mutex.owner_thread_id == acpi_os_get_thread_id()) {
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
* The mutex is already owned by this thread, just increment the */
* acquisition depth obj_desc->mutex.acquisition_depth++;
*/ return_ACPI_STATUS(AE_OK);
obj_desc->mutex.acquisition_depth++;
return_ACPI_STATUS(AE_OK);
}
} }
/* Acquire the mutex, wait if necessary. Special case for Global Lock */ /* 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, ...@@ -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 */ /* 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.acquisition_depth = 1;
obj_desc->mutex.original_sync_level = obj_desc->mutex.original_sync_level =
walk_state->thread->current_sync_level; walk_state->thread->current_sync_level;
...@@ -246,7 +242,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, ...@@ -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 */ /* 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, ACPI_ERROR((AE_INFO,
"Cannot release Mutex [%4.4s], not acquired", "Cannot release Mutex [%4.4s], not acquired",
acpi_ut_get_node_name(obj_desc->mutex.node))); acpi_ut_get_node_name(obj_desc->mutex.node)));
...@@ -266,14 +262,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, ...@@ -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. * The Mutex is owned, but this thread must be the owner.
* Special case for Global Lock, any thread can release * 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) walk_state->thread->thread_id)
&& (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) { && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
(unsigned long)walk_state->thread->thread_id, (unsigned long)walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node), 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); return_ACPI_STATUS(AE_AML_NOT_OWNER);
} }
...@@ -300,7 +296,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, ...@@ -300,7 +296,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
/* Unlink the mutex from the owner's list */ /* 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 */ /* Release the mutex, special case for Global Lock */
...@@ -312,7 +308,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, ...@@ -312,7 +308,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
/* Update the mutex and restore sync_level */ /* 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 = walk_state->thread->current_sync_level =
obj_desc->mutex.original_sync_level; obj_desc->mutex.original_sync_level;
...@@ -367,7 +363,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) ...@@ -367,7 +363,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
/* Mark mutex unowned */ /* 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) */ /* Update Thread sync_level (Last mutex is the important one) */
......
...@@ -170,7 +170,6 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ...@@ -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_os_delete_mutex(object->mutex.os_mutex);
acpi_gbl_global_lock_mutex = NULL; acpi_gbl_global_lock_mutex = NULL;
} else { } else {
acpi_ex_unlink_mutex(object);
acpi_os_delete_mutex(object->mutex.os_mutex); acpi_os_delete_mutex(object->mutex.os_mutex);
} }
break; break;
......
...@@ -253,7 +253,8 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, ...@@ -253,7 +253,8 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread); void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread);
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);
/* /*
* exprep - ACPI AML execution - prep utilities * exprep - ACPI AML execution - prep utilities
......
...@@ -155,7 +155,7 @@ struct acpi_object_event { ...@@ -155,7 +155,7 @@ struct acpi_object_event {
struct acpi_object_mutex { struct acpi_object_mutex {
ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */ ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */
u16 acquisition_depth; /* Allow multiple Acquires, same thread */ u16 acquisition_depth; /* Allow multiple Acquires, same thread */
struct acpi_thread_state *owner_thread; /* Current owner of the mutex */ acpi_thread_id owner_thread_id; /* Current owner of the mutex */
acpi_mutex os_mutex; /* Actual OS synchronization object */ acpi_mutex os_mutex; /* Actual OS synchronization object */
union acpi_operand_object *prev; /* Link for list of acquired mutexes */ union acpi_operand_object *prev; /* Link for list of acquired mutexes */
union acpi_operand_object *next; /* Link for list of acquired mutexes */ union acpi_operand_object *next; /* Link for list of acquired mutexes */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment