nsalloc.c 13.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/*******************************************************************************
 *
 * Module Name: nsalloc - Namespace allocation and deletion utilities
 *
 ******************************************************************************/

/*
8
 * Copyright (C) 2000 - 2010, Intel Corp.
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
L
Len Brown 已提交
45 46
#include "accommon.h"
#include "acnamesp.h"
L
Linus Torvalds 已提交
47 48

#define _COMPONENT          ACPI_NAMESPACE
L
Len Brown 已提交
49
ACPI_MODULE_NAME("nsalloc")
L
Linus Torvalds 已提交
50 51 52 53 54

/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_create_node
 *
R
Robert Moore 已提交
55
 * PARAMETERS:  Name            - Name of the new node (4 char ACPI name)
L
Linus Torvalds 已提交
56
 *
R
Robert Moore 已提交
57
 * RETURN:      New namespace node (Null on failure)
L
Linus Torvalds 已提交
58 59 60 61
 *
 * DESCRIPTION: Create a namespace node
 *
 ******************************************************************************/
L
Len Brown 已提交
62
struct acpi_namespace_node *acpi_ns_create_node(u32 name)
L
Linus Torvalds 已提交
63
{
L
Len Brown 已提交
64
	struct acpi_namespace_node *node;
65 66 67
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
	u32 temp;
#endif
L
Linus Torvalds 已提交
68

B
Bob Moore 已提交
69
	ACPI_FUNCTION_TRACE(ns_create_node);
L
Linus Torvalds 已提交
70

B
Bob Moore 已提交
71
	node = acpi_os_acquire_object(acpi_gbl_namespace_cache);
L
Linus Torvalds 已提交
72
	if (!node) {
L
Len Brown 已提交
73
		return_PTR(NULL);
L
Linus Torvalds 已提交
74 75
	}

L
Len Brown 已提交
76
	ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
L
Linus Torvalds 已提交
77

78
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
79
	temp = acpi_gbl_ns_node_list->total_allocated -
80 81 82 83 84 85
	    acpi_gbl_ns_node_list->total_freed;
	if (temp > acpi_gbl_ns_node_list->max_occupied) {
		acpi_gbl_ns_node_list->max_occupied = temp;
	}
#endif

L
Len Brown 已提交
86 87 88
	node->name.integer = name;
	ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
	return_PTR(node);
L
Linus Torvalds 已提交
89 90 91 92 93 94 95 96 97 98
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_delete_node
 *
 * PARAMETERS:  Node            - Node to be deleted
 *
 * RETURN:      None
 *
99 100 101 102
 * DESCRIPTION: Delete a namespace node. All node deletions must come through
 *              here. Detaches any attached objects, including any attached
 *              data. If a handler is associated with attached data, it is
 *              invoked before the node is deleted.
L
Linus Torvalds 已提交
103 104 105
 *
 ******************************************************************************/

L
Len Brown 已提交
106
void acpi_ns_delete_node(struct acpi_namespace_node *node)
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
{
	union acpi_operand_object *obj_desc;

	ACPI_FUNCTION_NAME(ns_delete_node);

	/* Detach an object if there is one */

	acpi_ns_detach_object(node);

	/*
	 * Delete an attached data object if present (an object that was created
	 * and attached via acpi_attach_data). Note: After any normal object is
	 * detached above, the only possible remaining object is a data object.
	 */
	obj_desc = node->object;
	if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) {

		/* Invoke the attached data deletion handler if present */

		if (obj_desc->data.handler) {
			obj_desc->data.handler(node, obj_desc->data.pointer);
		}

		acpi_ut_remove_reference(obj_desc);
	}

	/* Now we can delete the node */

	(void)acpi_os_release_object(acpi_gbl_namespace_cache, node);

	ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n",
			  node, acpi_gbl_current_node_count));
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_remove_node
 *
 * PARAMETERS:  Node            - Node to be removed/deleted
 *
 * RETURN:      None
 *
 * DESCRIPTION: Remove (unlink) and delete a namespace node
 *
 ******************************************************************************/

void acpi_ns_remove_node(struct acpi_namespace_node *node)
L
Linus Torvalds 已提交
155
{
L
Len Brown 已提交
156 157 158
	struct acpi_namespace_node *parent_node;
	struct acpi_namespace_node *prev_node;
	struct acpi_namespace_node *next_node;
L
Linus Torvalds 已提交
159

160
	ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node);
L
Linus Torvalds 已提交
161

162
	parent_node = node->parent;
L
Linus Torvalds 已提交
163 164 165 166 167 168 169 170

	prev_node = NULL;
	next_node = parent_node->child;

	/* Find the node that is the previous peer in the parent's child list */

	while (next_node != node) {
		prev_node = next_node;
171
		next_node = next_node->peer;
L
Linus Torvalds 已提交
172 173 174
	}

	if (prev_node) {
B
Bob Moore 已提交
175

L
Linus Torvalds 已提交
176 177
		/* Node is not first child, unlink it */

178
		prev_node->peer = node->peer;
L
Len Brown 已提交
179
	} else {
180 181 182 183 184
		/*
		 * Node is first child (has no previous peer).
		 * Link peer list to parent
		 */
		parent_node->child = node->peer;
L
Linus Torvalds 已提交
185 186
	}

187
	/* Delete the node and any attached objects */
188

189
	acpi_ns_delete_node(node);
L
Linus Torvalds 已提交
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
	return_VOID;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_install_node
 *
 * PARAMETERS:  walk_state      - Current state of the walk
 *              parent_node     - The parent of the new Node
 *              Node            - The new Node to install
 *              Type            - ACPI object type of the new Node
 *
 * RETURN:      None
 *
 * DESCRIPTION: Initialize a new namespace node and install it amongst
 *              its peers.
 *
207 208 209
 *              Note: Current namespace lookup is linear search. This appears
 *              to be sufficient as namespace searches consume only a small
 *              fraction of the execution time of the ACPI subsystem.
L
Linus Torvalds 已提交
210 211 212
 *
 ******************************************************************************/

L
Len Brown 已提交
213 214 215
void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namespace_node *parent_node,	/* Parent */
			  struct acpi_namespace_node *node,	/* New Child */
			  acpi_object_type type)
L
Linus Torvalds 已提交
216
{
L
Len Brown 已提交
217 218
	acpi_owner_id owner_id = 0;
	struct acpi_namespace_node *child_node;
L
Linus Torvalds 已提交
219

B
Bob Moore 已提交
220
	ACPI_FUNCTION_TRACE(ns_install_node);
L
Linus Torvalds 已提交
221 222

	if (walk_state) {
223 224 225 226
		/*
		 * Get the owner ID from the Walk state. The owner ID is used to
		 * track table deletion and deletion of objects created by methods.
		 */
L
Linus Torvalds 已提交
227
		owner_id = walk_state->owner_id;
228 229 230 231 232 233 234 235 236 237 238 239

		if ((walk_state->method_desc) &&
		    (parent_node != walk_state->method_node)) {
			/*
			 * A method is creating a new node that is not a child of the
			 * method (it is non-local). Mark the executing method as having
			 * modified the namespace. This is used for cleanup when the
			 * method exits.
			 */
			walk_state->method_desc->method.flags |=
			    AOPOBJ_MODIFIED_NAMESPACE;
		}
L
Linus Torvalds 已提交
240 241 242 243
	}

	/* Link the new entry into the parent and existing children */

244 245
	node->peer = NULL;
	node->parent = parent_node;
L
Linus Torvalds 已提交
246
	child_node = parent_node->child;
247

L
Linus Torvalds 已提交
248 249
	if (!child_node) {
		parent_node->child = node;
L
Len Brown 已提交
250
	} else {
251 252 253
		/* Add node to the end of the peer list */

		while (child_node->peer) {
L
Linus Torvalds 已提交
254 255 256 257 258 259 260 261 262 263 264
			child_node = child_node->peer;
		}

		child_node->peer = node;
	}

	/* Init the new entry */

	node->owner_id = owner_id;
	node->type = (u8) type;

L
Len Brown 已提交
265 266 267 268 269 270 271
	ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
			  "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n",
			  acpi_ut_get_node_name(node),
			  acpi_ut_get_type_name(node->type), node, owner_id,
			  acpi_ut_get_node_name(parent_node),
			  acpi_ut_get_type_name(parent_node->type),
			  parent_node));
B
Bob Moore 已提交
272 273

	return_VOID;
L
Linus Torvalds 已提交
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_delete_children
 *
 * PARAMETERS:  parent_node     - Delete this objects children
 *
 * RETURN:      None.
 *
 * DESCRIPTION: Delete all children of the parent object. In other words,
 *              deletes a "scope".
 *
 ******************************************************************************/

L
Len Brown 已提交
289
void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
L
Linus Torvalds 已提交
290
{
L
Len Brown 已提交
291
	struct acpi_namespace_node *next_node;
292
	struct acpi_namespace_node *node_to_delete;
L
Linus Torvalds 已提交
293

B
Bob Moore 已提交
294
	ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node);
L
Linus Torvalds 已提交
295 296 297 298 299

	if (!parent_node) {
		return_VOID;
	}

300 301
	/* Deallocate all children at this level */

302 303
	next_node = parent_node->child;
	while (next_node) {
L
Linus Torvalds 已提交
304 305 306

		/* Grandchildren should have all been deleted already */

307
		if (next_node->child) {
B
Bob Moore 已提交
308
			ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p",
309
				    parent_node, next_node));
L
Linus Torvalds 已提交
310 311
		}

312 313 314 315
		/*
		 * Delete this child node and move on to the next child in the list.
		 * No need to unlink the node since we are deleting the entire branch.
		 */
316 317 318 319
		node_to_delete = next_node;
		next_node = next_node->peer;
		acpi_ns_delete_node(node_to_delete);
	};
L
Linus Torvalds 已提交
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

	/* Clear the parent's child pointer */

	parent_node->child = NULL;
	return_VOID;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_delete_namespace_subtree
 *
 * PARAMETERS:  parent_node     - Root of the subtree to be deleted
 *
 * RETURN:      None.
 *
 * DESCRIPTION: Delete a subtree of the namespace.  This includes all objects
 *              stored within the subtree.
 *
 ******************************************************************************/

L
Len Brown 已提交
340
void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
L
Linus Torvalds 已提交
341
{
L
Len Brown 已提交
342 343
	struct acpi_namespace_node *child_node = NULL;
	u32 level = 1;
L
Linus Torvalds 已提交
344

B
Bob Moore 已提交
345
	ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree);
L
Linus Torvalds 已提交
346 347 348 349 350 351 352 353 354 355

	if (!parent_node) {
		return_VOID;
	}

	/*
	 * Traverse the tree of objects until we bubble back up
	 * to where we started.
	 */
	while (level > 0) {
B
Bob Moore 已提交
356

L
Linus Torvalds 已提交
357 358
		/* Get the next node in this scope (NULL if none) */

359
		child_node = acpi_ns_get_next_node(parent_node, child_node);
L
Linus Torvalds 已提交
360
		if (child_node) {
B
Bob Moore 已提交
361

L
Linus Torvalds 已提交
362 363
			/* Found a child node - detach any attached object */

L
Len Brown 已提交
364
			acpi_ns_detach_object(child_node);
L
Linus Torvalds 已提交
365 366 367

			/* Check if this node has any children */

368
			if (child_node->child) {
L
Linus Torvalds 已提交
369 370 371 372 373 374 375 376
				/*
				 * There is at least one child of this node,
				 * visit the node
				 */
				level++;
				parent_node = child_node;
				child_node = NULL;
			}
L
Len Brown 已提交
377
		} else {
L
Linus Torvalds 已提交
378 379 380 381 382 383 384 385 386 387
			/*
			 * No more children of this parent node.
			 * Move up to the grandparent.
			 */
			level--;

			/*
			 * Now delete all of the children of this parent
			 * all at the same time.
			 */
L
Len Brown 已提交
388
			acpi_ns_delete_children(parent_node);
L
Linus Torvalds 已提交
389 390 391 392 393 394 395

			/* New "last child" is this parent node */

			child_node = parent_node;

			/* Move up the tree to the grandparent */

396
			parent_node = parent_node->parent;
L
Linus Torvalds 已提交
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
		}
	}

	return_VOID;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_delete_namespace_by_owner
 *
 * PARAMETERS:  owner_id    - All nodes with this owner will be deleted
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Delete entries within the namespace that are owned by a
 *              specific ID.  Used to delete entire ACPI tables.  All
 *              reference counts are updated.
 *
B
Bob Moore 已提交
415 416
 * MUTEX:       Locks namespace during deletion walk.
 *
L
Linus Torvalds 已提交
417 418
 ******************************************************************************/

L
Len Brown 已提交
419
void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
L
Linus Torvalds 已提交
420
{
L
Len Brown 已提交
421 422 423
	struct acpi_namespace_node *child_node;
	struct acpi_namespace_node *deletion_node;
	struct acpi_namespace_node *parent_node;
B
Bob Moore 已提交
424 425
	u32 level;
	acpi_status status;
L
Linus Torvalds 已提交
426

B
Bob Moore 已提交
427
	ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id);
L
Linus Torvalds 已提交
428

429 430 431 432
	if (owner_id == 0) {
		return_VOID;
	}

B
Bob Moore 已提交
433 434 435 436 437 438 439
	/* Lock namespace for possible update */

	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
	if (ACPI_FAILURE(status)) {
		return_VOID;
	}

B
Bob Moore 已提交
440
	deletion_node = NULL;
L
Len Brown 已提交
441 442 443
	parent_node = acpi_gbl_root_node;
	child_node = NULL;
	level = 1;
L
Linus Torvalds 已提交
444 445 446 447 448 449 450 451 452 453

	/*
	 * Traverse the tree of nodes until we bubble back up
	 * to where we started.
	 */
	while (level > 0) {
		/*
		 * Get the next child of this parent node. When child_node is NULL,
		 * the first child of the parent is returned
		 */
454
		child_node = acpi_ns_get_next_node(parent_node, child_node);
L
Linus Torvalds 已提交
455 456

		if (deletion_node) {
B
Bob Moore 已提交
457
			acpi_ns_delete_children(deletion_node);
458
			acpi_ns_remove_node(deletion_node);
L
Linus Torvalds 已提交
459 460 461 462 463
			deletion_node = NULL;
		}

		if (child_node) {
			if (child_node->owner_id == owner_id) {
B
Bob Moore 已提交
464

L
Linus Torvalds 已提交
465 466
				/* Found a matching child node - detach any attached object */

L
Len Brown 已提交
467
				acpi_ns_detach_object(child_node);
L
Linus Torvalds 已提交
468 469 470 471
			}

			/* Check if this node has any children */

472
			if (child_node->child) {
L
Linus Torvalds 已提交
473 474 475 476 477 478 479
				/*
				 * There is at least one child of this node,
				 * visit the node
				 */
				level++;
				parent_node = child_node;
				child_node = NULL;
L
Len Brown 已提交
480
			} else if (child_node->owner_id == owner_id) {
L
Linus Torvalds 已提交
481 482
				deletion_node = child_node;
			}
L
Len Brown 已提交
483
		} else {
L
Linus Torvalds 已提交
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
			/*
			 * No more children of this parent node.
			 * Move up to the grandparent.
			 */
			level--;
			if (level != 0) {
				if (parent_node->owner_id == owner_id) {
					deletion_node = parent_node;
				}
			}

			/* New "last child" is this parent node */

			child_node = parent_node;

			/* Move up the tree to the grandparent */

501
			parent_node = parent_node->parent;
L
Linus Torvalds 已提交
502 503 504
		}
	}

B
Bob Moore 已提交
505
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
L
Linus Torvalds 已提交
506 507
	return_VOID;
}