#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsalloc")
+/* Local prototypes */
+static void acpi_ns_remove_reference(struct acpi_namespace_node *node);
+
/*******************************************************************************
*
* FUNCTION: acpi_ns_create_node
* DESCRIPTION: Create a namespace node
*
******************************************************************************/
+
struct acpi_namespace_node *acpi_ns_create_node(u32 name)
{
struct acpi_namespace_node *node;
- ACPI_FUNCTION_TRACE(ns_create_node);
+ ACPI_FUNCTION_TRACE("ns_create_node");
- node = acpi_os_acquire_object(acpi_gbl_namespace_cache);
+ node = ACPI_MEM_CALLOCATE(sizeof(struct acpi_namespace_node));
if (!node) {
return_PTR(NULL);
}
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
node->name.integer = name;
+ node->reference_count = 1;
ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
+
return_PTR(node);
}
struct acpi_namespace_node *prev_node;
struct acpi_namespace_node *next_node;
- ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node);
+ ACPI_FUNCTION_TRACE_PTR("ns_delete_node", node);
parent_node = acpi_ns_get_parent_node(node);
}
if (prev_node) {
-
/* Node is not first child, unlink it */
prev_node->peer = next_node->peer;
/* Node is first child (has no previous peer) */
if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
-
/* No peers at all */
parent_node->child = NULL;
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
/*
- * Detach an object if there is one, then delete the node
+ * Detach an object if there is one then delete the node
*/
acpi_ns_detach_object(node);
- (void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
+ ACPI_MEM_FREE(node);
return_VOID;
}
acpi_owner_id owner_id = 0;
struct acpi_namespace_node *child_node;
- ACPI_FUNCTION_TRACE(ns_install_node);
+ ACPI_FUNCTION_TRACE("ns_install_node");
/*
* Get the owner ID from the Walk state
acpi_ut_get_type_name(parent_node->type),
parent_node));
+ /*
+ * Increment the reference count(s) of all parents up to
+ * the root!
+ */
+ while ((node = acpi_ns_get_parent_node(node)) != NULL) {
+ node->reference_count++;
+ }
+
return_VOID;
}
{
struct acpi_namespace_node *child_node;
struct acpi_namespace_node *next_node;
+ struct acpi_namespace_node *node;
u8 flags;
- ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node);
+ ACPI_FUNCTION_TRACE_PTR("ns_delete_children", parent_node);
if (!parent_node) {
return_VOID;
* Deallocate all children at this level
*/
do {
-
/* Get the things we need */
next_node = child_node->peer;
*/
acpi_ns_detach_object(child_node);
+ /*
+ * Decrement the reference count(s) of all parents up to
+ * the root! (counts were incremented when the node was created)
+ */
+ node = child_node;
+ while ((node = acpi_ns_get_parent_node(node)) != NULL) {
+ node->reference_count--;
+ }
+
+ /* There should be only one reference remaining on this node */
+
+ if (child_node->reference_count != 1) {
+ ACPI_WARNING((AE_INFO,
+ "Existing references (%d) on node being deleted (%p)",
+ child_node->reference_count, child_node));
+ }
+
/* Now we can delete the node */
- (void)acpi_os_release_object(acpi_gbl_namespace_cache,
- child_node);
+ ACPI_MEM_FREE(child_node);
/* And move on to the next child in the list */
struct acpi_namespace_node *child_node = NULL;
u32 level = 1;
- ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree);
+ ACPI_FUNCTION_TRACE("ns_delete_namespace_subtree");
if (!parent_node) {
return_VOID;
* to where we started.
*/
while (level > 0) {
-
/* Get the next node in this scope (NULL if none) */
- child_node =
- acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
- child_node);
+ child_node = acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
+ child_node);
if (child_node) {
-
/* Found a child node - detach any attached object */
acpi_ns_detach_object(child_node);
return_VOID;
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_remove_reference
+ *
+ * PARAMETERS: Node - Named node whose reference count is to be
+ * decremented
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Remove a Node reference. Decrements the reference count
+ * of all parent Nodes up to the root. Any node along
+ * the way that reaches zero references is freed.
+ *
+ ******************************************************************************/
+
+static void acpi_ns_remove_reference(struct acpi_namespace_node *node)
+{
+ struct acpi_namespace_node *parent_node;
+ struct acpi_namespace_node *this_node;
+
+ ACPI_FUNCTION_ENTRY();
+
+ /*
+ * Decrement the reference count(s) of this node and all
+ * nodes up to the root, Delete anything with zero remaining references.
+ */
+ this_node = node;
+ while (this_node) {
+ /* Prepare to move up to parent */
+
+ parent_node = acpi_ns_get_parent_node(this_node);
+
+ /* Decrement the reference count on this node */
+
+ this_node->reference_count--;
+
+ /* Delete the node if no more references */
+
+ if (!this_node->reference_count) {
+ /* Delete all children and delete the node */
+
+ acpi_ns_delete_children(this_node);
+ acpi_ns_delete_node(this_node);
+ }
+
+ this_node = parent_node;
+ }
+}
+
/*******************************************************************************
*
* FUNCTION: acpi_ns_delete_namespace_by_owner
* specific ID. Used to delete entire ACPI tables. All
* reference counts are updated.
*
- * MUTEX: Locks namespace during deletion walk.
- *
******************************************************************************/
void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
{
struct acpi_namespace_node *child_node;
struct acpi_namespace_node *deletion_node;
- struct acpi_namespace_node *parent_node;
u32 level;
- acpi_status status;
+ struct acpi_namespace_node *parent_node;
- ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id);
+ ACPI_FUNCTION_TRACE_U32("ns_delete_namespace_by_owner", owner_id);
if (owner_id == 0) {
return_VOID;
}
- /* Lock namespace for possible update */
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return_VOID;
- }
-
- deletion_node = NULL;
parent_node = acpi_gbl_root_node;
child_node = NULL;
+ deletion_node = NULL;
level = 1;
/*
child_node);
if (deletion_node) {
- acpi_ns_delete_children(deletion_node);
- acpi_ns_delete_node(deletion_node);
+ acpi_ns_remove_reference(deletion_node);
deletion_node = NULL;
}
if (child_node) {
if (child_node->owner_id == owner_id) {
-
/* Found a matching child node - detach any attached object */
acpi_ns_detach_object(child_node);
}
}
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_VOID;
}