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>
This commit is contained in:
parent
724339d76d
commit
c0d127b569
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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) */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_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
|
||||
|
|
|
@ -155,7 +155,7 @@ struct acpi_object_event {
|
|||
struct acpi_object_mutex {
|
||||
ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */
|
||||
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 */
|
||||
union acpi_operand_object *prev; /* Link for list of acquired mutexes */
|
||||
union acpi_operand_object *next; /* Link for list of acquired mutexes */
|
||||
|
|
Loading…
Reference in New Issue