ia64/linux-2.6.18-xen.hg

view drivers/acpi/namespace/nsalloc.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /*******************************************************************************
2 *
3 * Module Name: nsalloc - Namespace allocation and deletion utilities
4 *
5 ******************************************************************************/
7 /*
8 * Copyright (C) 2000 - 2006, R. Byron Moore
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 */
44 #include <acpi/acpi.h>
45 #include <acpi/acnamesp.h>
47 #define _COMPONENT ACPI_NAMESPACE
48 ACPI_MODULE_NAME("nsalloc")
50 /*******************************************************************************
51 *
52 * FUNCTION: acpi_ns_create_node
53 *
54 * PARAMETERS: Name - Name of the new node (4 char ACPI name)
55 *
56 * RETURN: New namespace node (Null on failure)
57 *
58 * DESCRIPTION: Create a namespace node
59 *
60 ******************************************************************************/
61 struct acpi_namespace_node *acpi_ns_create_node(u32 name)
62 {
63 struct acpi_namespace_node *node;
65 ACPI_FUNCTION_TRACE(ns_create_node);
67 node = acpi_os_acquire_object(acpi_gbl_namespace_cache);
68 if (!node) {
69 return_PTR(NULL);
70 }
72 ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
74 node->name.integer = name;
75 ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
76 return_PTR(node);
77 }
79 /*******************************************************************************
80 *
81 * FUNCTION: acpi_ns_delete_node
82 *
83 * PARAMETERS: Node - Node to be deleted
84 *
85 * RETURN: None
86 *
87 * DESCRIPTION: Delete a namespace node
88 *
89 ******************************************************************************/
91 void acpi_ns_delete_node(struct acpi_namespace_node *node)
92 {
93 struct acpi_namespace_node *parent_node;
94 struct acpi_namespace_node *prev_node;
95 struct acpi_namespace_node *next_node;
97 ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node);
99 parent_node = acpi_ns_get_parent_node(node);
101 prev_node = NULL;
102 next_node = parent_node->child;
104 /* Find the node that is the previous peer in the parent's child list */
106 while (next_node != node) {
107 prev_node = next_node;
108 next_node = prev_node->peer;
109 }
111 if (prev_node) {
113 /* Node is not first child, unlink it */
115 prev_node->peer = next_node->peer;
116 if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
117 prev_node->flags |= ANOBJ_END_OF_PEER_LIST;
118 }
119 } else {
120 /* Node is first child (has no previous peer) */
122 if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
124 /* No peers at all */
126 parent_node->child = NULL;
127 } else { /* Link peer list to parent */
129 parent_node->child = next_node->peer;
130 }
131 }
133 ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
135 /*
136 * Detach an object if there is one, then delete the node
137 */
138 acpi_ns_detach_object(node);
139 (void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
140 return_VOID;
141 }
143 /*******************************************************************************
144 *
145 * FUNCTION: acpi_ns_install_node
146 *
147 * PARAMETERS: walk_state - Current state of the walk
148 * parent_node - The parent of the new Node
149 * Node - The new Node to install
150 * Type - ACPI object type of the new Node
151 *
152 * RETURN: None
153 *
154 * DESCRIPTION: Initialize a new namespace node and install it amongst
155 * its peers.
156 *
157 * Note: Current namespace lookup is linear search. This appears
158 * to be sufficient as namespace searches consume only a small
159 * fraction of the execution time of the ACPI subsystem.
160 *
161 ******************************************************************************/
163 void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namespace_node *parent_node, /* Parent */
164 struct acpi_namespace_node *node, /* New Child */
165 acpi_object_type type)
166 {
167 acpi_owner_id owner_id = 0;
168 struct acpi_namespace_node *child_node;
170 ACPI_FUNCTION_TRACE(ns_install_node);
172 /*
173 * Get the owner ID from the Walk state
174 * The owner ID is used to track table deletion and
175 * deletion of objects created by methods
176 */
177 if (walk_state) {
178 owner_id = walk_state->owner_id;
179 }
181 /* Link the new entry into the parent and existing children */
183 child_node = parent_node->child;
184 if (!child_node) {
185 parent_node->child = node;
186 node->flags |= ANOBJ_END_OF_PEER_LIST;
187 node->peer = parent_node;
188 } else {
189 while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) {
190 child_node = child_node->peer;
191 }
193 child_node->peer = node;
195 /* Clear end-of-list flag */
197 child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
198 node->flags |= ANOBJ_END_OF_PEER_LIST;
199 node->peer = parent_node;
200 }
202 /* Init the new entry */
204 node->owner_id = owner_id;
205 node->type = (u8) type;
207 ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
208 "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n",
209 acpi_ut_get_node_name(node),
210 acpi_ut_get_type_name(node->type), node, owner_id,
211 acpi_ut_get_node_name(parent_node),
212 acpi_ut_get_type_name(parent_node->type),
213 parent_node));
215 return_VOID;
216 }
218 /*******************************************************************************
219 *
220 * FUNCTION: acpi_ns_delete_children
221 *
222 * PARAMETERS: parent_node - Delete this objects children
223 *
224 * RETURN: None.
225 *
226 * DESCRIPTION: Delete all children of the parent object. In other words,
227 * deletes a "scope".
228 *
229 ******************************************************************************/
231 void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
232 {
233 struct acpi_namespace_node *child_node;
234 struct acpi_namespace_node *next_node;
235 u8 flags;
237 ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node);
239 if (!parent_node) {
240 return_VOID;
241 }
243 /* If no children, all done! */
245 child_node = parent_node->child;
246 if (!child_node) {
247 return_VOID;
248 }
250 /*
251 * Deallocate all children at this level
252 */
253 do {
255 /* Get the things we need */
257 next_node = child_node->peer;
258 flags = child_node->flags;
260 /* Grandchildren should have all been deleted already */
262 if (child_node->child) {
263 ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p",
264 parent_node, child_node));
265 }
267 /* Now we can free this child object */
269 ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
271 ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
272 "Object %p, Remaining %X\n", child_node,
273 acpi_gbl_current_node_count));
275 /*
276 * Detach an object if there is one, then free the child node
277 */
278 acpi_ns_detach_object(child_node);
280 /* Now we can delete the node */
282 (void)acpi_os_release_object(acpi_gbl_namespace_cache,
283 child_node);
285 /* And move on to the next child in the list */
287 child_node = next_node;
289 } while (!(flags & ANOBJ_END_OF_PEER_LIST));
291 /* Clear the parent's child pointer */
293 parent_node->child = NULL;
295 return_VOID;
296 }
298 /*******************************************************************************
299 *
300 * FUNCTION: acpi_ns_delete_namespace_subtree
301 *
302 * PARAMETERS: parent_node - Root of the subtree to be deleted
303 *
304 * RETURN: None.
305 *
306 * DESCRIPTION: Delete a subtree of the namespace. This includes all objects
307 * stored within the subtree.
308 *
309 ******************************************************************************/
311 void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
312 {
313 struct acpi_namespace_node *child_node = NULL;
314 u32 level = 1;
316 ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree);
318 if (!parent_node) {
319 return_VOID;
320 }
322 /*
323 * Traverse the tree of objects until we bubble back up
324 * to where we started.
325 */
326 while (level > 0) {
328 /* Get the next node in this scope (NULL if none) */
330 child_node =
331 acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
332 child_node);
333 if (child_node) {
335 /* Found a child node - detach any attached object */
337 acpi_ns_detach_object(child_node);
339 /* Check if this node has any children */
341 if (acpi_ns_get_next_node
342 (ACPI_TYPE_ANY, child_node, NULL)) {
343 /*
344 * There is at least one child of this node,
345 * visit the node
346 */
347 level++;
348 parent_node = child_node;
349 child_node = NULL;
350 }
351 } else {
352 /*
353 * No more children of this parent node.
354 * Move up to the grandparent.
355 */
356 level--;
358 /*
359 * Now delete all of the children of this parent
360 * all at the same time.
361 */
362 acpi_ns_delete_children(parent_node);
364 /* New "last child" is this parent node */
366 child_node = parent_node;
368 /* Move up the tree to the grandparent */
370 parent_node = acpi_ns_get_parent_node(parent_node);
371 }
372 }
374 return_VOID;
375 }
377 /*******************************************************************************
378 *
379 * FUNCTION: acpi_ns_delete_namespace_by_owner
380 *
381 * PARAMETERS: owner_id - All nodes with this owner will be deleted
382 *
383 * RETURN: Status
384 *
385 * DESCRIPTION: Delete entries within the namespace that are owned by a
386 * specific ID. Used to delete entire ACPI tables. All
387 * reference counts are updated.
388 *
389 * MUTEX: Locks namespace during deletion walk.
390 *
391 ******************************************************************************/
393 void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
394 {
395 struct acpi_namespace_node *child_node;
396 struct acpi_namespace_node *deletion_node;
397 struct acpi_namespace_node *parent_node;
398 u32 level;
399 acpi_status status;
401 ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id);
403 if (owner_id == 0) {
404 return_VOID;
405 }
407 /* Lock namespace for possible update */
409 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
410 if (ACPI_FAILURE(status)) {
411 return_VOID;
412 }
414 deletion_node = NULL;
415 parent_node = acpi_gbl_root_node;
416 child_node = NULL;
417 level = 1;
419 /*
420 * Traverse the tree of nodes until we bubble back up
421 * to where we started.
422 */
423 while (level > 0) {
424 /*
425 * Get the next child of this parent node. When child_node is NULL,
426 * the first child of the parent is returned
427 */
428 child_node =
429 acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
430 child_node);
432 if (deletion_node) {
433 acpi_ns_delete_children(deletion_node);
434 acpi_ns_delete_node(deletion_node);
435 deletion_node = NULL;
436 }
438 if (child_node) {
439 if (child_node->owner_id == owner_id) {
441 /* Found a matching child node - detach any attached object */
443 acpi_ns_detach_object(child_node);
444 }
446 /* Check if this node has any children */
448 if (acpi_ns_get_next_node
449 (ACPI_TYPE_ANY, child_node, NULL)) {
450 /*
451 * There is at least one child of this node,
452 * visit the node
453 */
454 level++;
455 parent_node = child_node;
456 child_node = NULL;
457 } else if (child_node->owner_id == owner_id) {
458 deletion_node = child_node;
459 }
460 } else {
461 /*
462 * No more children of this parent node.
463 * Move up to the grandparent.
464 */
465 level--;
466 if (level != 0) {
467 if (parent_node->owner_id == owner_id) {
468 deletion_node = parent_node;
469 }
470 }
472 /* New "last child" is this parent node */
474 child_node = parent_node;
476 /* Move up the tree to the grandparent */
478 parent_node = acpi_ns_get_parent_node(parent_node);
479 }
480 }
482 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
483 return_VOID;
484 }