diff options
author | Bob Moore <robert.moore@intel.com> | 2009-03-09 09:31:04 +0100 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-27 17:11:02 +0100 |
commit | 8a335a2331c72e60c6b3ef09b2dedd3ba00da1b1 (patch) | |
tree | f538a4f68499dab0d59e253bc55a5cf4aff66ec1 /drivers/acpi/acpica/tbinstal.c | |
parent | ACPICA: FADT: Fix extraneous length mismatch warning (diff) | |
download | linux-8a335a2331c72e60c6b3ef09b2dedd3ba00da1b1.tar.xz linux-8a335a2331c72e60c6b3ef09b2dedd3ba00da1b1.zip |
ACPICA: Fix AcpiWalkNamespace race condition with table unload
Added a reader/writer locking mechanism to allow multiple
concurrent namespace walks (readers), but a dynamic table unload
will have exclusive access to the namespace. This fixes a problem
where a table unload could delete the portion of the namespace that
is currently being examined by a walk. Adds a new file, utlock.c
that implements the reader/writer lock mechanism. ACPICA BZ 749.
http://www.acpica.org/bugzilla/show_bug.cgi?id=749
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/tbinstal.c')
-rw-r--r-- | drivers/acpi/acpica/tbinstal.c | 45 |
1 files changed, 37 insertions, 8 deletions
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index c37993003f2c..f865d5a096de 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -434,27 +434,56 @@ void acpi_tb_terminate(void) * * PARAMETERS: table_index - Table index * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Delete all namespace objects created when this table was loaded. * ******************************************************************************/ -void acpi_tb_delete_namespace_by_owner(u32 table_index) +acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) { acpi_owner_id owner_id; + acpi_status status; + + ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); + + status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + if (table_index >= acpi_gbl_root_table_list.count) { + + /* The table index does not exist */ - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.count) { - owner_id = - acpi_gbl_root_table_list.tables[table_index].owner_id; - } else { (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return; + return_ACPI_STATUS(AE_NOT_EXIST); } + /* Get the owner ID for this table, used to delete namespace nodes */ + + owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + + /* + * Need to acquire the namespace writer lock to prevent interference + * with any concurrent namespace walks. The interpreter must be + * released during the deletion since the acquisition of the deletion + * lock may block, and also since the execution of a namespace walk + * must be allowed to use the interpreter. + */ + acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); + status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); + acpi_ns_delete_namespace_by_owner(owner_id); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); + + status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); + return_ACPI_STATUS(status); } /******************************************************************************* |