ia64/linux-2.6.18-xen.hg

view drivers/acpi/container.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 * acpi_container.c - ACPI Generic Container Driver
3 * ($Revision: )
4 *
5 * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
6 * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
7 * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
8 * Copyright (C) 2004 Intel Corp.
9 * Copyright (C) 2004 FUJITSU LIMITED
10 *
11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or (at
16 * your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 *
27 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 */
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/init.h>
32 #include <linux/types.h>
33 #include <linux/acpi.h>
34 #include <acpi/acpi_bus.h>
35 #include <acpi/acpi_drivers.h>
36 #include <acpi/container.h>
38 #define ACPI_CONTAINER_DRIVER_NAME "ACPI container driver"
39 #define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
40 #define ACPI_CONTAINER_CLASS "container"
42 #define INSTALL_NOTIFY_HANDLER 1
43 #define UNINSTALL_NOTIFY_HANDLER 2
45 #define ACPI_CONTAINER_COMPONENT 0x01000000
46 #define _COMPONENT ACPI_CONTAINER_COMPONENT
47 ACPI_MODULE_NAME("acpi_container")
49 MODULE_AUTHOR("Anil S Keshavamurthy");
50 MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME);
51 MODULE_LICENSE("GPL");
53 #define ACPI_STA_PRESENT (0x00000001)
55 static int acpi_container_add(struct acpi_device *device);
56 static int acpi_container_remove(struct acpi_device *device, int type);
58 static struct acpi_driver acpi_container_driver = {
59 .name = ACPI_CONTAINER_DRIVER_NAME,
60 .class = ACPI_CONTAINER_CLASS,
61 .ids = "ACPI0004,PNP0A05,PNP0A06",
62 .ops = {
63 .add = acpi_container_add,
64 .remove = acpi_container_remove,
65 },
66 };
68 /*******************************************************************/
70 static int is_device_present(acpi_handle handle)
71 {
72 acpi_handle temp;
73 acpi_status status;
74 unsigned long sta;
77 status = acpi_get_handle(handle, "_STA", &temp);
78 if (ACPI_FAILURE(status))
79 return 1; /* _STA not found, assmue device present */
81 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
82 if (ACPI_FAILURE(status))
83 return 0; /* Firmware error */
85 return ((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
86 }
88 /*******************************************************************/
89 static int acpi_container_add(struct acpi_device *device)
90 {
91 struct acpi_container *container;
94 if (!device) {
95 printk(KERN_ERR PREFIX "device is NULL\n");
96 return -EINVAL;
97 }
99 container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
100 if (!container)
101 return -ENOMEM;
103 memset(container, 0, sizeof(struct acpi_container));
104 container->handle = device->handle;
105 strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
106 strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
107 acpi_driver_data(device) = container;
109 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
110 acpi_device_name(device), acpi_device_bid(device)));
112 return 0;
113 }
115 static int acpi_container_remove(struct acpi_device *device, int type)
116 {
117 acpi_status status = AE_OK;
118 struct acpi_container *pc = NULL;
120 pc = (struct acpi_container *)acpi_driver_data(device);
121 kfree(pc);
122 return status;
123 }
125 static int container_device_add(struct acpi_device **device, acpi_handle handle)
126 {
127 acpi_handle phandle;
128 struct acpi_device *pdev;
129 int result;
132 if (acpi_get_parent(handle, &phandle)) {
133 return -ENODEV;
134 }
136 if (acpi_bus_get_device(phandle, &pdev)) {
137 return -ENODEV;
138 }
140 if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
141 return -ENODEV;
142 }
144 result = acpi_bus_start(*device);
146 return result;
147 }
149 static void container_notify_cb(acpi_handle handle, u32 type, void *context)
150 {
151 struct acpi_device *device = NULL;
152 int result;
153 int present;
154 acpi_status status;
157 present = is_device_present(handle);
159 switch (type) {
160 case ACPI_NOTIFY_BUS_CHECK:
161 /* Fall through */
162 case ACPI_NOTIFY_DEVICE_CHECK:
163 printk("Container driver received %s event\n",
164 (type == ACPI_NOTIFY_BUS_CHECK) ?
165 "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
166 status = acpi_bus_get_device(handle, &device);
167 if (present) {
168 if (ACPI_FAILURE(status) || !device) {
169 result = container_device_add(&device, handle);
170 if (!result)
171 kobject_uevent(&device->kobj,
172 KOBJ_ONLINE);
173 else
174 printk("Failed to add container\n");
175 }
176 } else {
177 if (ACPI_SUCCESS(status)) {
178 /* device exist and this is a remove request */
179 kobject_uevent(&device->kobj, KOBJ_OFFLINE);
180 }
181 }
182 break;
183 case ACPI_NOTIFY_EJECT_REQUEST:
184 if (!acpi_bus_get_device(handle, &device) && device) {
185 kobject_uevent(&device->kobj, KOBJ_OFFLINE);
186 }
187 break;
188 default:
189 break;
190 }
191 return;
192 }
194 static acpi_status
195 container_walk_namespace_cb(acpi_handle handle,
196 u32 lvl, void *context, void **rv)
197 {
198 char *hid = NULL;
199 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
200 struct acpi_device_info *info;
201 acpi_status status;
202 int *action = context;
205 status = acpi_get_object_info(handle, &buffer);
206 if (ACPI_FAILURE(status) || !buffer.pointer) {
207 return AE_OK;
208 }
210 info = buffer.pointer;
211 if (info->valid & ACPI_VALID_HID)
212 hid = info->hardware_id.value;
214 if (hid == NULL) {
215 goto end;
216 }
218 if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") &&
219 strcmp(hid, "PNP0A06")) {
220 goto end;
221 }
223 switch (*action) {
224 case INSTALL_NOTIFY_HANDLER:
225 acpi_install_notify_handler(handle,
226 ACPI_SYSTEM_NOTIFY,
227 container_notify_cb, NULL);
228 break;
229 case UNINSTALL_NOTIFY_HANDLER:
230 acpi_remove_notify_handler(handle,
231 ACPI_SYSTEM_NOTIFY,
232 container_notify_cb);
233 break;
234 default:
235 break;
236 }
238 end:
239 kfree(buffer.pointer);
241 return AE_OK;
242 }
244 static int __init acpi_container_init(void)
245 {
246 int result = 0;
247 int action = INSTALL_NOTIFY_HANDLER;
249 result = acpi_bus_register_driver(&acpi_container_driver);
250 if (result < 0) {
251 return (result);
252 }
254 /* register notify handler to every container device */
255 acpi_walk_namespace(ACPI_TYPE_DEVICE,
256 ACPI_ROOT_OBJECT,
257 ACPI_UINT32_MAX,
258 container_walk_namespace_cb, &action, NULL);
260 return (0);
261 }
263 static void __exit acpi_container_exit(void)
264 {
265 int action = UNINSTALL_NOTIFY_HANDLER;
268 acpi_walk_namespace(ACPI_TYPE_DEVICE,
269 ACPI_ROOT_OBJECT,
270 ACPI_UINT32_MAX,
271 container_walk_namespace_cb, &action, NULL);
273 acpi_bus_unregister_driver(&acpi_container_driver);
275 return;
276 }
278 module_init(acpi_container_init);
279 module_exit(acpi_container_exit);