diff options
author | Bob Moore <robert.moore@intel.com> | 2009-03-09 04:31:04 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-27 12:11:02 -0400 |
commit | 8a335a2331c72e60c6b3ef09b2dedd3ba00da1b1 (patch) | |
tree | f538a4f68499dab0d59e253bc55a5cf4aff66ec1 /drivers/acpi/acpica | |
parent | aab61b676a024d3527f6201e2b31285a96f7a1d2 (diff) |
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')
-rw-r--r-- | drivers/acpi/acpica/Makefile | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/acglobal.h | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/aclocal.h | 8 | ||||
-rw-r--r-- | drivers/acpi/acpica/actables.h | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/acutils.h | 15 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsinit.c | 16 | ||||
-rw-r--r-- | drivers/acpi/acpica/exconfig.c | 13 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsxfeval.c | 33 | ||||
-rw-r--r-- | drivers/acpi/acpica/tbinstal.c | 45 | ||||
-rw-r--r-- | drivers/acpi/acpica/utlock.c | 175 | ||||
-rw-r--r-- | drivers/acpi/acpica/utmutex.c | 23 |
11 files changed, 303 insertions, 33 deletions
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 3f23298ee3fd..290be74b774d 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile | |||
@@ -41,4 +41,4 @@ obj-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o | |||
41 | 41 | ||
42 | obj-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ | 42 | obj-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ |
43 | utcopy.o utdelete.o utglobal.o utmath.o utobject.o \ | 43 | utcopy.o utdelete.o utglobal.o utmath.o utobject.o \ |
44 | utstate.o utmutex.o utobject.o utresrc.o | 44 | utstate.o utmutex.o utobject.o utresrc.o utlock.o |
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index f3e87ba43dbe..f431b997d2f8 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h | |||
@@ -165,6 +165,10 @@ ACPI_EXTERN u8 acpi_gbl_integer_bit_width; | |||
165 | ACPI_EXTERN u8 acpi_gbl_integer_byte_width; | 165 | ACPI_EXTERN u8 acpi_gbl_integer_byte_width; |
166 | ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; | 166 | ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; |
167 | 167 | ||
168 | /* Reader/Writer lock is used for namespace walk and dynamic table unload */ | ||
169 | |||
170 | ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock; | ||
171 | |||
168 | /***************************************************************************** | 172 | /***************************************************************************** |
169 | * | 173 | * |
170 | * Mutual exlusion within ACPICA subsystem | 174 | * Mutual exlusion within ACPICA subsystem |
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 6feebc8f789a..18a8d96eaa49 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h | |||
@@ -108,6 +108,14 @@ static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { | |||
108 | #endif | 108 | #endif |
109 | #endif | 109 | #endif |
110 | 110 | ||
111 | /* Lock structure for reader/writer interfaces */ | ||
112 | |||
113 | struct acpi_rw_lock { | ||
114 | acpi_mutex writer_mutex; | ||
115 | acpi_mutex reader_mutex; | ||
116 | u32 num_readers; | ||
117 | }; | ||
118 | |||
111 | /* | 119 | /* |
112 | * Predefined handles for spinlocks used within the subsystem. | 120 | * Predefined handles for spinlocks used within the subsystem. |
113 | * These spinlocks are created by acpi_ut_mutex_initialize | 121 | * These spinlocks are created by acpi_ut_mutex_initialize |
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index d8f8c5df4fbc..01c76b8ea7ba 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h | |||
@@ -79,7 +79,7 @@ void acpi_tb_delete_table(struct acpi_table_desc *table_desc); | |||
79 | 79 | ||
80 | void acpi_tb_terminate(void); | 80 | void acpi_tb_terminate(void); |
81 | 81 | ||
82 | void acpi_tb_delete_namespace_by_owner(u32 table_index); | 82 | acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index); |
83 | 83 | ||
84 | acpi_status acpi_tb_allocate_owner_id(u32 table_index); | 84 | acpi_status acpi_tb_allocate_owner_id(u32 table_index); |
85 | 85 | ||
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 80d8813484fe..897810ba0ccc 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h | |||
@@ -346,6 +346,21 @@ acpi_status | |||
346 | acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest); | 346 | acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest); |
347 | 347 | ||
348 | /* | 348 | /* |
349 | * utlock - reader/writer locks | ||
350 | */ | ||
351 | acpi_status acpi_ut_create_rw_lock(struct acpi_rw_lock *lock); | ||
352 | |||
353 | void acpi_ut_delete_rw_lock(struct acpi_rw_lock *lock); | ||
354 | |||
355 | acpi_status acpi_ut_acquire_read_lock(struct acpi_rw_lock *lock); | ||
356 | |||
357 | acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock); | ||
358 | |||
359 | acpi_status acpi_ut_acquire_write_lock(struct acpi_rw_lock *lock); | ||
360 | |||
361 | void acpi_ut_release_write_lock(struct acpi_rw_lock *lock); | ||
362 | |||
363 | /* | ||
349 | * utobject - internal object create/delete/cache routines | 364 | * utobject - internal object create/delete/cache routines |
350 | */ | 365 | */ |
351 | union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char | 366 | union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char |
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index eb144b13d8fa..3aae13f30c5e 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c | |||
@@ -180,11 +180,23 @@ acpi_ds_initialize_objects(u32 table_index, | |||
180 | 180 | ||
181 | /* Walk entire namespace from the supplied root */ | 181 | /* Walk entire namespace from the supplied root */ |
182 | 182 | ||
183 | status = acpi_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, | 183 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
184 | acpi_ds_init_one_object, &info, NULL); | 184 | if (ACPI_FAILURE(status)) { |
185 | return_ACPI_STATUS(status); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * We don't use acpi_walk_namespace since we do not want to acquire | ||
190 | * the namespace reader lock. | ||
191 | */ | ||
192 | status = | ||
193 | acpi_ns_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, | ||
194 | ACPI_NS_WALK_UNLOCK, acpi_ds_init_one_object, | ||
195 | &info, NULL); | ||
185 | if (ACPI_FAILURE(status)) { | 196 | if (ACPI_FAILURE(status)) { |
186 | ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); | 197 | ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); |
187 | } | 198 | } |
199 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | ||
188 | 200 | ||
189 | status = acpi_get_table_by_index(table_index, &table); | 201 | status = acpi_get_table_by_index(table_index, &table); |
190 | if (ACPI_FAILURE(status)) { | 202 | if (ACPI_FAILURE(status)) { |
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 70b39c7daeab..3deb20a126b2 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c | |||
@@ -520,13 +520,14 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) | |||
520 | } | 520 | } |
521 | } | 521 | } |
522 | 522 | ||
523 | /* | 523 | /* Delete the portion of the namespace owned by this table */ |
524 | * Delete the entire namespace under this table Node | 524 | |
525 | * (Offset contains the table_id) | 525 | status = acpi_tb_delete_namespace_by_owner(table_index); |
526 | */ | 526 | if (ACPI_FAILURE(status)) { |
527 | acpi_tb_delete_namespace_by_owner(table_index); | 527 | return_ACPI_STATUS(status); |
528 | (void)acpi_tb_release_owner_id(table_index); | 528 | } |
529 | 529 | ||
530 | (void)acpi_tb_release_owner_id(table_index); | ||
530 | acpi_tb_set_table_loaded_flag(table_index, FALSE); | 531 | acpi_tb_set_table_loaded_flag(table_index, FALSE); |
531 | 532 | ||
532 | /* Table unloaded, remove a reference to the ddb_handle object */ | 533 | /* Table unloaded, remove a reference to the ddb_handle object */ |
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 2583a66a60a7..045054037c2d 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c | |||
@@ -475,21 +475,40 @@ acpi_walk_namespace(acpi_object_type type, | |||
475 | } | 475 | } |
476 | 476 | ||
477 | /* | 477 | /* |
478 | * Lock the namespace around the walk. | 478 | * Need to acquire the namespace reader lock to prevent interference |
479 | * The namespace will be unlocked/locked around each call | 479 | * with any concurrent table unloads (which causes the deletion of |
480 | * to the user function - since this function | 480 | * namespace objects). We cannot allow the deletion of a namespace node |
481 | * must be allowed to make Acpi calls itself. | 481 | * while the user function is using it. The exception to this are the |
482 | * nodes created and deleted during control method execution -- these | ||
483 | * nodes are marked as temporary nodes and are ignored by the namespace | ||
484 | * walk. Thus, control methods can be executed while holding the | ||
485 | * namespace deletion lock (and the user function can execute control | ||
486 | * methods.) | ||
487 | */ | ||
488 | status = acpi_ut_acquire_read_lock(&acpi_gbl_namespace_rw_lock); | ||
489 | if (ACPI_FAILURE(status)) { | ||
490 | return status; | ||
491 | } | ||
492 | |||
493 | /* | ||
494 | * Lock the namespace around the walk. The namespace will be | ||
495 | * unlocked/locked around each call to the user function - since the user | ||
496 | * function must be allowed to make ACPICA calls itself (for example, it | ||
497 | * will typically execute control methods during device enumeration.) | ||
482 | */ | 498 | */ |
483 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | 499 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
484 | if (ACPI_FAILURE(status)) { | 500 | if (ACPI_FAILURE(status)) { |
485 | return_ACPI_STATUS(status); | 501 | goto unlock_and_exit; |
486 | } | 502 | } |
487 | 503 | ||
488 | status = acpi_ns_walk_namespace(type, start_object, max_depth, | 504 | status = acpi_ns_walk_namespace(type, start_object, max_depth, |
489 | ACPI_NS_WALK_UNLOCK, | 505 | ACPI_NS_WALK_UNLOCK, user_function, |
490 | user_function, context, return_value); | 506 | context, return_value); |
491 | 507 | ||
492 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 508 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
509 | |||
510 | unlock_and_exit: | ||
511 | (void)acpi_ut_release_read_lock(&acpi_gbl_namespace_rw_lock); | ||
493 | return_ACPI_STATUS(status); | 512 | return_ACPI_STATUS(status); |
494 | } | 513 | } |
495 | 514 | ||
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) | |||
434 | * | 434 | * |
435 | * PARAMETERS: table_index - Table index | 435 | * PARAMETERS: table_index - Table index |
436 | * | 436 | * |
437 | * RETURN: None | 437 | * RETURN: Status |
438 | * | 438 | * |
439 | * DESCRIPTION: Delete all namespace objects created when this table was loaded. | 439 | * DESCRIPTION: Delete all namespace objects created when this table was loaded. |
440 | * | 440 | * |
441 | ******************************************************************************/ | 441 | ******************************************************************************/ |
442 | 442 | ||
443 | void acpi_tb_delete_namespace_by_owner(u32 table_index) | 443 | acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) |
444 | { | 444 | { |
445 | acpi_owner_id owner_id; | 445 | acpi_owner_id owner_id; |
446 | acpi_status status; | ||
447 | |||
448 | ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); | ||
449 | |||
450 | status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); | ||
451 | if (ACPI_FAILURE(status)) { | ||
452 | return_ACPI_STATUS(status); | ||
453 | } | ||
454 | |||
455 | if (table_index >= acpi_gbl_root_table_list.count) { | ||
456 | |||
457 | /* The table index does not exist */ | ||
446 | 458 | ||
447 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); | ||
448 | if (table_index < acpi_gbl_root_table_list.count) { | ||
449 | owner_id = | ||
450 | acpi_gbl_root_table_list.tables[table_index].owner_id; | ||
451 | } else { | ||
452 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); | 459 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
453 | return; | 460 | return_ACPI_STATUS(AE_NOT_EXIST); |
454 | } | 461 | } |
455 | 462 | ||
463 | /* Get the owner ID for this table, used to delete namespace nodes */ | ||
464 | |||
465 | owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; | ||
456 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); | 466 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
467 | |||
468 | /* | ||
469 | * Need to acquire the namespace writer lock to prevent interference | ||
470 | * with any concurrent namespace walks. The interpreter must be | ||
471 | * released during the deletion since the acquisition of the deletion | ||
472 | * lock may block, and also since the execution of a namespace walk | ||
473 | * must be allowed to use the interpreter. | ||
474 | */ | ||
475 | acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); | ||
476 | status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); | ||
477 | |||
457 | acpi_ns_delete_namespace_by_owner(owner_id); | 478 | acpi_ns_delete_namespace_by_owner(owner_id); |
479 | if (ACPI_FAILURE(status)) { | ||
480 | return_ACPI_STATUS(status); | ||
481 | } | ||
482 | |||
483 | acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); | ||
484 | |||
485 | status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); | ||
486 | return_ACPI_STATUS(status); | ||
458 | } | 487 | } |
459 | 488 | ||
460 | /******************************************************************************* | 489 | /******************************************************************************* |
diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c new file mode 100644 index 000000000000..25e03120686d --- /dev/null +++ b/drivers/acpi/acpica/utlock.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: utlock - Reader/Writer lock interfaces | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2009, Intel Corp. | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * 1. Redistributions of source code must retain the above copyright | ||
15 | * notice, this list of conditions, and the following disclaimer, | ||
16 | * without modification. | ||
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
18 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
19 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
20 | * including a substantially similar Disclaimer requirement for further | ||
21 | * binary redistribution. | ||
22 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
23 | * of any contributors may be used to endorse or promote products derived | ||
24 | * from this software without specific prior written permission. | ||
25 | * | ||
26 | * Alternatively, this software may be distributed under the terms of the | ||
27 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
28 | * Software Foundation. | ||
29 | * | ||
30 | * NO WARRANTY | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGES. | ||
42 | */ | ||
43 | |||
44 | #include <acpi/acpi.h> | ||
45 | #include "accommon.h" | ||
46 | |||
47 | #define _COMPONENT ACPI_UTILITIES | ||
48 | ACPI_MODULE_NAME("utlock") | ||
49 | |||
50 | /******************************************************************************* | ||
51 | * | ||
52 | * FUNCTION: acpi_ut_create_rw_lock | ||
53 | * acpi_ut_delete_rw_lock | ||
54 | * | ||
55 | * PARAMETERS: Lock - Pointer to a valid RW lock | ||
56 | * | ||
57 | * RETURN: Status | ||
58 | * | ||
59 | * DESCRIPTION: Reader/writer lock creation and deletion interfaces. | ||
60 | * | ||
61 | ******************************************************************************/ | ||
62 | acpi_status acpi_ut_create_rw_lock(struct acpi_rw_lock *lock) | ||
63 | { | ||
64 | acpi_status status; | ||
65 | |||
66 | lock->num_readers = 0; | ||
67 | status = acpi_os_create_mutex(&lock->reader_mutex); | ||
68 | if (ACPI_FAILURE(status)) { | ||
69 | return status; | ||
70 | } | ||
71 | |||
72 | status = acpi_os_create_mutex(&lock->writer_mutex); | ||
73 | return status; | ||
74 | } | ||
75 | |||
76 | void acpi_ut_delete_rw_lock(struct acpi_rw_lock *lock) | ||
77 | { | ||
78 | |||
79 | acpi_os_delete_mutex(lock->reader_mutex); | ||
80 | acpi_os_delete_mutex(lock->writer_mutex); | ||
81 | |||
82 | lock->num_readers = 0; | ||
83 | lock->reader_mutex = NULL; | ||
84 | lock->writer_mutex = NULL; | ||
85 | } | ||
86 | |||
87 | /******************************************************************************* | ||
88 | * | ||
89 | * FUNCTION: acpi_ut_acquire_read_lock | ||
90 | * acpi_ut_release_read_lock | ||
91 | * | ||
92 | * PARAMETERS: Lock - Pointer to a valid RW lock | ||
93 | * | ||
94 | * RETURN: Status | ||
95 | * | ||
96 | * DESCRIPTION: Reader interfaces for reader/writer locks. On acquisition, | ||
97 | * only the first reader acquires the write mutex. On release, | ||
98 | * only the last reader releases the write mutex. Although this | ||
99 | * algorithm can in theory starve writers, this should not be a | ||
100 | * problem with ACPICA since the subsystem is infrequently used | ||
101 | * in comparison to (for example) an I/O system. | ||
102 | * | ||
103 | ******************************************************************************/ | ||
104 | |||
105 | acpi_status acpi_ut_acquire_read_lock(struct acpi_rw_lock *lock) | ||
106 | { | ||
107 | acpi_status status; | ||
108 | |||
109 | status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER); | ||
110 | if (ACPI_FAILURE(status)) { | ||
111 | return status; | ||
112 | } | ||
113 | |||
114 | /* Acquire the write lock only for the first reader */ | ||
115 | |||
116 | lock->num_readers++; | ||
117 | if (lock->num_readers == 1) { | ||
118 | status = | ||
119 | acpi_os_acquire_mutex(lock->writer_mutex, | ||
120 | ACPI_WAIT_FOREVER); | ||
121 | } | ||
122 | |||
123 | acpi_os_release_mutex(lock->reader_mutex); | ||
124 | return status; | ||
125 | } | ||
126 | |||
127 | acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock) | ||
128 | { | ||
129 | acpi_status status; | ||
130 | |||
131 | status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER); | ||
132 | if (ACPI_FAILURE(status)) { | ||
133 | return status; | ||
134 | } | ||
135 | |||
136 | /* Release the write lock only for the very last reader */ | ||
137 | |||
138 | lock->num_readers--; | ||
139 | if (lock->num_readers == 0) { | ||
140 | acpi_os_release_mutex(lock->writer_mutex); | ||
141 | } | ||
142 | |||
143 | acpi_os_release_mutex(lock->reader_mutex); | ||
144 | return status; | ||
145 | } | ||
146 | |||
147 | /******************************************************************************* | ||
148 | * | ||
149 | * FUNCTION: acpi_ut_acquire_write_lock | ||
150 | * acpi_ut_release_write_lock | ||
151 | * | ||
152 | * PARAMETERS: Lock - Pointer to a valid RW lock | ||
153 | * | ||
154 | * RETURN: Status | ||
155 | * | ||
156 | * DESCRIPTION: Writer interfaces for reader/writer locks. Simply acquire or | ||
157 | * release the writer mutex associated with the lock. Acquisition | ||
158 | * of the lock is fully exclusive and will block all readers and | ||
159 | * writers until it is released. | ||
160 | * | ||
161 | ******************************************************************************/ | ||
162 | |||
163 | acpi_status acpi_ut_acquire_write_lock(struct acpi_rw_lock *lock) | ||
164 | { | ||
165 | acpi_status status; | ||
166 | |||
167 | status = acpi_os_acquire_mutex(lock->writer_mutex, ACPI_WAIT_FOREVER); | ||
168 | return status; | ||
169 | } | ||
170 | |||
171 | void acpi_ut_release_write_lock(struct acpi_rw_lock *lock) | ||
172 | { | ||
173 | |||
174 | acpi_os_release_mutex(lock->writer_mutex); | ||
175 | } | ||
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 14eb52c4d647..26c93a748e64 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c | |||
@@ -60,7 +60,8 @@ static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id); | |||
60 | * | 60 | * |
61 | * RETURN: Status | 61 | * RETURN: Status |
62 | * | 62 | * |
63 | * DESCRIPTION: Create the system mutex objects. | 63 | * DESCRIPTION: Create the system mutex objects. This includes mutexes, |
64 | * spin locks, and reader/writer locks. | ||
64 | * | 65 | * |
65 | ******************************************************************************/ | 66 | ******************************************************************************/ |
66 | 67 | ||
@@ -71,9 +72,8 @@ acpi_status acpi_ut_mutex_initialize(void) | |||
71 | 72 | ||
72 | ACPI_FUNCTION_TRACE(ut_mutex_initialize); | 73 | ACPI_FUNCTION_TRACE(ut_mutex_initialize); |
73 | 74 | ||
74 | /* | 75 | /* Create each of the predefined mutex objects */ |
75 | * Create each of the predefined mutex objects | 76 | |
76 | */ | ||
77 | for (i = 0; i < ACPI_NUM_MUTEX; i++) { | 77 | for (i = 0; i < ACPI_NUM_MUTEX; i++) { |
78 | status = acpi_ut_create_mutex(i); | 78 | status = acpi_ut_create_mutex(i); |
79 | if (ACPI_FAILURE(status)) { | 79 | if (ACPI_FAILURE(status)) { |
@@ -86,6 +86,9 @@ acpi_status acpi_ut_mutex_initialize(void) | |||
86 | spin_lock_init(acpi_gbl_gpe_lock); | 86 | spin_lock_init(acpi_gbl_gpe_lock); |
87 | spin_lock_init(acpi_gbl_hardware_lock); | 87 | spin_lock_init(acpi_gbl_hardware_lock); |
88 | 88 | ||
89 | /* Create the reader/writer lock for namespace access */ | ||
90 | |||
91 | status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock); | ||
89 | return_ACPI_STATUS(status); | 92 | return_ACPI_STATUS(status); |
90 | } | 93 | } |
91 | 94 | ||
@@ -97,7 +100,8 @@ acpi_status acpi_ut_mutex_initialize(void) | |||
97 | * | 100 | * |
98 | * RETURN: None. | 101 | * RETURN: None. |
99 | * | 102 | * |
100 | * DESCRIPTION: Delete all of the system mutex objects. | 103 | * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes, |
104 | * spin locks, and reader/writer locks. | ||
101 | * | 105 | * |
102 | ******************************************************************************/ | 106 | ******************************************************************************/ |
103 | 107 | ||
@@ -107,9 +111,8 @@ void acpi_ut_mutex_terminate(void) | |||
107 | 111 | ||
108 | ACPI_FUNCTION_TRACE(ut_mutex_terminate); | 112 | ACPI_FUNCTION_TRACE(ut_mutex_terminate); |
109 | 113 | ||
110 | /* | 114 | /* Delete each predefined mutex object */ |
111 | * Delete each predefined mutex object | 115 | |
112 | */ | ||
113 | for (i = 0; i < ACPI_NUM_MUTEX; i++) { | 116 | for (i = 0; i < ACPI_NUM_MUTEX; i++) { |
114 | (void)acpi_ut_delete_mutex(i); | 117 | (void)acpi_ut_delete_mutex(i); |
115 | } | 118 | } |
@@ -118,6 +121,10 @@ void acpi_ut_mutex_terminate(void) | |||
118 | 121 | ||
119 | acpi_os_delete_lock(acpi_gbl_gpe_lock); | 122 | acpi_os_delete_lock(acpi_gbl_gpe_lock); |
120 | acpi_os_delete_lock(acpi_gbl_hardware_lock); | 123 | acpi_os_delete_lock(acpi_gbl_hardware_lock); |
124 | |||
125 | /* Delete the reader/writer lock */ | ||
126 | |||
127 | acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock); | ||
121 | return_VOID; | 128 | return_VOID; |
122 | } | 129 | } |
123 | 130 | ||