Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPICA: Fix for some local named nodes not marked temporary and to disallow duplicates

Fixed a problem with the CreateField, CreateXXXField (Bit, Byte,
Word, Dword, Qword), Field, BankField, and IndexField operators
when invoked from inside an executing control method. In this case,
these operators created namespace nodes that were incorrectly
left marked as permanent nodes instead of temporary nodes. This
could cause a problem if there is race condition between an
exiting control method and a running namespace walk. (Reported
by Linn Crosetto). Fixed a problem where the CreateField and
CreateXXXField operators would incorrectly allow duplicate names
(the name of the field) with no exception generated.

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

Bob Moore and committed by
Len Brown
cca97b81 66e2c0bc

+79 -48
+73 -48
drivers/acpi/dispatcher/dsfield.c
··· 89 89 90 90 ACPI_FUNCTION_TRACE(ds_create_buffer_field); 91 91 92 - /* Get the name_string argument */ 93 - 92 + /* 93 + * Get the name_string argument (name of the new buffer_field) 94 + */ 94 95 if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { 96 + 97 + /* For create_field, name is the 4th argument */ 98 + 95 99 arg = acpi_ps_get_arg(op, 3); 96 100 } else { 97 - /* Create Bit/Byte/Word/Dword field */ 101 + /* For all other create_xXXField operators, name is the 3rd argument */ 98 102 99 103 arg = acpi_ps_get_arg(op, 2); 100 104 } ··· 111 107 node = walk_state->deferred_node; 112 108 status = AE_OK; 113 109 } else { 114 - /* 115 - * During the load phase, we want to enter the name of the field into 116 - * the namespace. During the execute phase (when we evaluate the size 117 - * operand), we want to lookup the name 118 - */ 119 - if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) { 120 - flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; 121 - } else { 122 - flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | 123 - ACPI_NS_ERROR_IF_FOUND; 110 + /* Execute flag should always be set when this function is entered */ 111 + 112 + if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { 113 + return_ACPI_STATUS(AE_AML_INTERNAL); 124 114 } 125 115 126 - /* 127 - * Enter the name_string into the namespace 128 - */ 116 + /* Creating new namespace node, should not already exist */ 117 + 118 + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | 119 + ACPI_NS_ERROR_IF_FOUND; 120 + 121 + /* Mark node temporary if we are executing a method */ 122 + 123 + if (walk_state->method_node) { 124 + flags |= ACPI_NS_TEMPORARY; 125 + } 126 + 127 + /* Enter the name_string into the namespace */ 128 + 129 129 status = 130 130 acpi_ns_lookup(walk_state->scope_info, 131 131 arg->common.value.string, ACPI_TYPE_ANY, 132 132 ACPI_IMODE_LOAD_PASS1, flags, walk_state, 133 - &(node)); 133 + &node); 134 134 if (ACPI_FAILURE(status)) { 135 135 ACPI_ERROR_NAMESPACE(arg->common.value.string, status); 136 136 return_ACPI_STATUS(status); ··· 144 136 /* 145 137 * We could put the returned object (Node) on the object stack for later, 146 138 * but for now, we will put it in the "op" object that the parser uses, 147 - * so we can get it again at the end of this scope 139 + * so we can get it again at the end of this scope. 148 140 */ 149 141 op->common.node = node; 150 142 151 143 /* 152 144 * If there is no object attached to the node, this node was just created 153 - * and we need to create the field object. Otherwise, this was a lookup 145 + * and we need to create the field object. Otherwise, this was a lookup 154 146 * of an existing node and we don't want to create the field object again. 155 147 */ 156 148 obj_desc = acpi_ns_get_attached_object(node); ··· 172 164 } 173 165 174 166 /* 175 - * Remember location in AML stream of the field unit 176 - * opcode and operands -- since the buffer and index 177 - * operands must be evaluated. 167 + * Remember location in AML stream of the field unit opcode and operands -- 168 + * since the buffer and index operands must be evaluated. 178 169 */ 179 170 second_desc = obj_desc->common.next_object; 180 171 second_desc->extra.aml_start = op->named.data; ··· 268 261 269 262 case AML_INT_NAMEDFIELD_OP: 270 263 271 - /* Lookup the name */ 264 + /* Lookup the name, it should already exist */ 272 265 273 266 status = acpi_ns_lookup(walk_state->scope_info, 274 267 (char *)&arg->named.name, ··· 279 272 if (ACPI_FAILURE(status)) { 280 273 ACPI_ERROR_NAMESPACE((char *)&arg->named.name, 281 274 status); 282 - if (status != AE_ALREADY_EXISTS) { 283 - return_ACPI_STATUS(status); 284 - } 285 - 286 - /* Already exists, ignore error */ 275 + return_ACPI_STATUS(status); 287 276 } else { 288 277 arg->common.node = info->field_node; 289 278 info->field_bit_length = arg->common.value.size; 290 279 291 280 /* 292 - * If there is no object attached to the node, this node was just created 293 - * and we need to create the field object. Otherwise, this was a lookup 294 - * of an existing node and we don't want to create the field object again. 281 + * If there is no object attached to the node, this node was 282 + * just created and we need to create the field object. 283 + * Otherwise, this was a lookup of an existing node and we 284 + * don't want to create the field object again. 295 285 */ 296 286 if (!acpi_ns_get_attached_object 297 287 (info->field_node)) { ··· 413 409 414 410 ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op); 415 411 416 - /* 417 - * During the load phase, we want to enter the name of the field into 418 - * the namespace. During the execute phase (when we evaluate the bank_value 419 - * operand), we want to lookup the name. 420 - */ 421 - if (walk_state->deferred_node) { 422 - flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; 423 - } else { 424 - flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | 425 - ACPI_NS_ERROR_IF_FOUND; 412 + /* Execute flag should always be set when this function is entered */ 413 + 414 + if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { 415 + if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) { 416 + 417 + /* bank_field Op is deferred, just return OK */ 418 + 419 + return_ACPI_STATUS(AE_OK); 420 + } 421 + 422 + return_ACPI_STATUS(AE_AML_INTERNAL); 426 423 } 427 424 425 + /* 426 + * Get the field_list argument for this opcode. This is the start of the 427 + * list of field elements. 428 + */ 428 429 switch (walk_state->opcode) { 429 430 case AML_FIELD_OP: 430 431 arg = acpi_ps_get_arg(op, 2); ··· 450 441 return_ACPI_STATUS(AE_BAD_PARAMETER); 451 442 } 452 443 444 + if (!arg) { 445 + return_ACPI_STATUS(AE_AML_NO_OPERAND); 446 + } 447 + 448 + /* Creating new namespace node(s), should not already exist */ 449 + 450 + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | 451 + ACPI_NS_ERROR_IF_FOUND; 452 + 453 + /* Mark node(s) temporary if we are executing a method */ 454 + 455 + if (walk_state->method_node) { 456 + flags |= ACPI_NS_TEMPORARY; 457 + } 458 + 453 459 /* 454 460 * Walk the list of entries in the field_list 455 461 */ 456 462 while (arg) { 457 - 458 - /* Ignore OFFSET and ACCESSAS terms here */ 459 - 463 + /* 464 + * Ignore OFFSET and ACCESSAS terms here; we are only interested in the 465 + * field names in order to enter them into the namespace. 466 + */ 460 467 if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { 461 468 status = acpi_ns_lookup(walk_state->scope_info, 462 - (char *)&arg->named.name, 463 - type, ACPI_IMODE_LOAD_PASS1, 464 - flags, walk_state, &node); 469 + (char *)&arg->named.name, type, 470 + ACPI_IMODE_LOAD_PASS1, flags, 471 + walk_state, &node); 465 472 if (ACPI_FAILURE(status)) { 466 473 ACPI_ERROR_NAMESPACE((char *)&arg->named.name, 467 474 status); ··· 493 468 arg->common.node = node; 494 469 } 495 470 496 - /* Move to next field in the list */ 471 + /* Get the next field element in the list */ 497 472 498 473 arg = arg->common.next; 499 474 }
+6
drivers/acpi/dispatcher/dswload.c
··· 776 776 acpi_ns_lookup(walk_state->scope_info, buffer_ptr, 777 777 object_type, ACPI_IMODE_LOAD_PASS2, flags, 778 778 walk_state, &node); 779 + 780 + if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) { 781 + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 782 + "***New Node [%4.4s] %p is temporary\n", 783 + acpi_ut_get_node_name(node), node)); 784 + } 779 785 break; 780 786 } 781 787