1 /******************************************************************************* 2 * 3 * Module Name: nsalloc - Namespace allocation and deletion utilities 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, 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 #include "acnamesp.h" 47 48 #define _COMPONENT ACPI_NAMESPACE 49 ACPI_MODULE_NAME("nsalloc") 50 51 /******************************************************************************* 52 * 53 * FUNCTION: acpi_ns_create_node 54 * 55 * PARAMETERS: name - Name of the new node (4 char ACPI name) 56 * 57 * RETURN: New namespace node (Null on failure) 58 * 59 * DESCRIPTION: Create a namespace node 60 * 61 ******************************************************************************/ 62 struct acpi_namespace_node *acpi_ns_create_node(u32 name) 63 { 64 struct acpi_namespace_node *node; 65 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 66 u32 temp; 67 #endif 68 69 ACPI_FUNCTION_TRACE(ns_create_node); 70 71 node = acpi_os_acquire_object(acpi_gbl_namespace_cache); 72 if (!node) { 73 return_PTR(NULL); 74 } 75 76 ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++); 77 78 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 79 temp = acpi_gbl_ns_node_list->total_allocated - 80 acpi_gbl_ns_node_list->total_freed; 81 if (temp > acpi_gbl_ns_node_list->max_occupied) { 82 acpi_gbl_ns_node_list->max_occupied = temp; 83 } 84 #endif 85 86 node->name.integer = name; 87 ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED); 88 return_PTR(node); 89 } 90 91 /******************************************************************************* 92 * 93 * FUNCTION: acpi_ns_delete_node 94 * 95 * PARAMETERS: node - Node to be deleted 96 * 97 * RETURN: None 98 * 99 * DESCRIPTION: Delete a namespace node. All node deletions must come through 100 * here. Detaches any attached objects, including any attached 101 * data. If a handler is associated with attached data, it is 102 * invoked before the node is deleted. 103 * 104 ******************************************************************************/ 105 106 void acpi_ns_delete_node(struct acpi_namespace_node *node) 107 { 108 union acpi_operand_object *obj_desc; 109 union acpi_operand_object *next_desc; 110 111 ACPI_FUNCTION_NAME(ns_delete_node); 112 113 /* Detach an object if there is one */ 114 115 acpi_ns_detach_object(node); 116 117 /* 118 * Delete an attached data object list if present (objects that were 119 * attached via acpi_attach_data). Note: After any normal object is 120 * detached above, the only possible remaining object(s) are data 121 * objects, in a linked list. 122 */ 123 obj_desc = node->object; 124 while (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { 125 126 /* Invoke the attached data deletion handler if present */ 127 128 if (obj_desc->data.handler) { 129 obj_desc->data.handler(node, obj_desc->data.pointer); 130 } 131 132 next_desc = obj_desc->common.next_object; 133 acpi_ut_remove_reference(obj_desc); 134 obj_desc = next_desc; 135 } 136 137 /* Special case for the statically allocated root node */ 138 139 if (node == acpi_gbl_root_node) { 140 return; 141 } 142 143 /* Now we can delete the node */ 144 145 (void)acpi_os_release_object(acpi_gbl_namespace_cache, node); 146 147 ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); 148 ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n", 149 node, acpi_gbl_current_node_count)); 150 } 151 152 /******************************************************************************* 153 * 154 * FUNCTION: acpi_ns_remove_node 155 * 156 * PARAMETERS: node - Node to be removed/deleted 157 * 158 * RETURN: None 159 * 160 * DESCRIPTION: Remove (unlink) and delete a namespace node 161 * 162 ******************************************************************************/ 163 164 void acpi_ns_remove_node(struct acpi_namespace_node *node) 165 { 166 struct acpi_namespace_node *parent_node; 167 struct acpi_namespace_node *prev_node; 168 struct acpi_namespace_node *next_node; 169 170 ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node); 171 172 parent_node = node->parent; 173 174 prev_node = NULL; 175 next_node = parent_node->child; 176 177 /* Find the node that is the previous peer in the parent's child list */ 178 179 while (next_node != node) { 180 prev_node = next_node; 181 next_node = next_node->peer; 182 } 183 184 if (prev_node) { 185 186 /* Node is not first child, unlink it */ 187 188 prev_node->peer = node->peer; 189 } else { 190 /* 191 * Node is first child (has no previous peer). 192 * Link peer list to parent 193 */ 194 parent_node->child = node->peer; 195 } 196 197 /* Delete the node and any attached objects */ 198 199 acpi_ns_delete_node(node); 200 return_VOID; 201 } 202 203 /******************************************************************************* 204 * 205 * FUNCTION: acpi_ns_install_node 206 * 207 * PARAMETERS: walk_state - Current state of the walk 208 * parent_node - The parent of the new Node 209 * node - The new Node to install 210 * type - ACPI object type of the new Node 211 * 212 * RETURN: None 213 * 214 * DESCRIPTION: Initialize a new namespace node and install it amongst 215 * its peers. 216 * 217 * Note: Current namespace lookup is linear search. This appears 218 * to be sufficient as namespace searches consume only a small 219 * fraction of the execution time of the ACPI subsystem. 220 * 221 ******************************************************************************/ 222 223 void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namespace_node *parent_node, /* Parent */ 224 struct acpi_namespace_node *node, /* New Child */ 225 acpi_object_type type) 226 { 227 acpi_owner_id owner_id = 0; 228 struct acpi_namespace_node *child_node; 229 230 ACPI_FUNCTION_TRACE(ns_install_node); 231 232 if (walk_state) { 233 /* 234 * Get the owner ID from the Walk state. The owner ID is used to 235 * track table deletion and deletion of objects created by methods. 236 */ 237 owner_id = walk_state->owner_id; 238 239 if ((walk_state->method_desc) && 240 (parent_node != walk_state->method_node)) { 241 /* 242 * A method is creating a new node that is not a child of the 243 * method (it is non-local). Mark the executing method as having 244 * modified the namespace. This is used for cleanup when the 245 * method exits. 246 */ 247 walk_state->method_desc->method.info_flags |= 248 ACPI_METHOD_MODIFIED_NAMESPACE; 249 } 250 } 251 252 /* Link the new entry into the parent and existing children */ 253 254 node->peer = NULL; 255 node->parent = parent_node; 256 child_node = parent_node->child; 257 258 if (!child_node) { 259 parent_node->child = node; 260 } else { 261 /* Add node to the end of the peer list */ 262 263 while (child_node->peer) { 264 child_node = child_node->peer; 265 } 266 267 child_node->peer = node; 268 } 269 270 /* Init the new entry */ 271 272 node->owner_id = owner_id; 273 node->type = (u8) type; 274 275 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 276 "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", 277 acpi_ut_get_node_name(node), 278 acpi_ut_get_type_name(node->type), node, owner_id, 279 acpi_ut_get_node_name(parent_node), 280 acpi_ut_get_type_name(parent_node->type), 281 parent_node)); 282 283 return_VOID; 284 } 285 286 /******************************************************************************* 287 * 288 * FUNCTION: acpi_ns_delete_children 289 * 290 * PARAMETERS: parent_node - Delete this objects children 291 * 292 * RETURN: None. 293 * 294 * DESCRIPTION: Delete all children of the parent object. In other words, 295 * deletes a "scope". 296 * 297 ******************************************************************************/ 298 299 void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) 300 { 301 struct acpi_namespace_node *next_node; 302 struct acpi_namespace_node *node_to_delete; 303 304 ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node); 305 306 if (!parent_node) { 307 return_VOID; 308 } 309 310 /* Deallocate all children at this level */ 311 312 next_node = parent_node->child; 313 while (next_node) { 314 315 /* Grandchildren should have all been deleted already */ 316 317 if (next_node->child) { 318 ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p", 319 parent_node, next_node)); 320 } 321 322 /* 323 * Delete this child node and move on to the next child in the list. 324 * No need to unlink the node since we are deleting the entire branch. 325 */ 326 node_to_delete = next_node; 327 next_node = next_node->peer; 328 acpi_ns_delete_node(node_to_delete); 329 }; 330 331 /* Clear the parent's child pointer */ 332 333 parent_node->child = NULL; 334 return_VOID; 335 } 336 337 /******************************************************************************* 338 * 339 * FUNCTION: acpi_ns_delete_namespace_subtree 340 * 341 * PARAMETERS: parent_node - Root of the subtree to be deleted 342 * 343 * RETURN: None. 344 * 345 * DESCRIPTION: Delete a subtree of the namespace. This includes all objects 346 * stored within the subtree. 347 * 348 ******************************************************************************/ 349 350 void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) 351 { 352 struct acpi_namespace_node *child_node = NULL; 353 u32 level = 1; 354 acpi_status status; 355 356 ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); 357 358 if (!parent_node) { 359 return_VOID; 360 } 361 362 /* Lock namespace for possible update */ 363 364 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 365 if (ACPI_FAILURE(status)) { 366 return_VOID; 367 } 368 369 /* 370 * Traverse the tree of objects until we bubble back up 371 * to where we started. 372 */ 373 while (level > 0) { 374 375 /* Get the next node in this scope (NULL if none) */ 376 377 child_node = acpi_ns_get_next_node(parent_node, child_node); 378 if (child_node) { 379 380 /* Found a child node - detach any attached object */ 381 382 acpi_ns_detach_object(child_node); 383 384 /* Check if this node has any children */ 385 386 if (child_node->child) { 387 /* 388 * There is at least one child of this node, 389 * visit the node 390 */ 391 level++; 392 parent_node = child_node; 393 child_node = NULL; 394 } 395 } else { 396 /* 397 * No more children of this parent node. 398 * Move up to the grandparent. 399 */ 400 level--; 401 402 /* 403 * Now delete all of the children of this parent 404 * all at the same time. 405 */ 406 acpi_ns_delete_children(parent_node); 407 408 /* New "last child" is this parent node */ 409 410 child_node = parent_node; 411 412 /* Move up the tree to the grandparent */ 413 414 parent_node = parent_node->parent; 415 } 416 } 417 418 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 419 return_VOID; 420 } 421 422 /******************************************************************************* 423 * 424 * FUNCTION: acpi_ns_delete_namespace_by_owner 425 * 426 * PARAMETERS: owner_id - All nodes with this owner will be deleted 427 * 428 * RETURN: Status 429 * 430 * DESCRIPTION: Delete entries within the namespace that are owned by a 431 * specific ID. Used to delete entire ACPI tables. All 432 * reference counts are updated. 433 * 434 * MUTEX: Locks namespace during deletion walk. 435 * 436 ******************************************************************************/ 437 438 void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) 439 { 440 struct acpi_namespace_node *child_node; 441 struct acpi_namespace_node *deletion_node; 442 struct acpi_namespace_node *parent_node; 443 u32 level; 444 acpi_status status; 445 446 ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id); 447 448 if (owner_id == 0) { 449 return_VOID; 450 } 451 452 /* Lock namespace for possible update */ 453 454 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 455 if (ACPI_FAILURE(status)) { 456 return_VOID; 457 } 458 459 deletion_node = NULL; 460 parent_node = acpi_gbl_root_node; 461 child_node = NULL; 462 level = 1; 463 464 /* 465 * Traverse the tree of nodes until we bubble back up 466 * to where we started. 467 */ 468 while (level > 0) { 469 /* 470 * Get the next child of this parent node. When child_node is NULL, 471 * the first child of the parent is returned 472 */ 473 child_node = acpi_ns_get_next_node(parent_node, child_node); 474 475 if (deletion_node) { 476 acpi_ns_delete_children(deletion_node); 477 acpi_ns_remove_node(deletion_node); 478 deletion_node = NULL; 479 } 480 481 if (child_node) { 482 if (child_node->owner_id == owner_id) { 483 484 /* Found a matching child node - detach any attached object */ 485 486 acpi_ns_detach_object(child_node); 487 } 488 489 /* Check if this node has any children */ 490 491 if (child_node->child) { 492 /* 493 * There is at least one child of this node, 494 * visit the node 495 */ 496 level++; 497 parent_node = child_node; 498 child_node = NULL; 499 } else if (child_node->owner_id == owner_id) { 500 deletion_node = child_node; 501 } 502 } else { 503 /* 504 * No more children of this parent node. 505 * Move up to the grandparent. 506 */ 507 level--; 508 if (level != 0) { 509 if (parent_node->owner_id == owner_id) { 510 deletion_node = parent_node; 511 } 512 } 513 514 /* New "last child" is this parent node */ 515 516 child_node = parent_node; 517 518 /* Move up the tree to the grandparent */ 519 520 parent_node = parent_node->parent; 521 } 522 } 523 524 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 525 return_VOID; 526 } 527