ia64/linux-2.6.18-xen.hg

view drivers/acpi/fan.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_fan.c - ACPI Fan Driver ($Revision: 29 $)
3 *
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/types.h>
30 #include <linux/proc_fs.h>
31 #include <linux/seq_file.h>
32 #include <asm/uaccess.h>
34 #include <acpi/acpi_bus.h>
35 #include <acpi/acpi_drivers.h>
37 #define ACPI_FAN_COMPONENT 0x00200000
38 #define ACPI_FAN_CLASS "fan"
39 #define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver"
40 #define ACPI_FAN_FILE_STATE "state"
42 #define _COMPONENT ACPI_FAN_COMPONENT
43 ACPI_MODULE_NAME("acpi_fan")
45 MODULE_AUTHOR("Paul Diefenbaugh");
46 MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME);
47 MODULE_LICENSE("GPL");
49 static int acpi_fan_add(struct acpi_device *device);
50 static int acpi_fan_remove(struct acpi_device *device, int type);
51 static int acpi_fan_suspend(struct acpi_device *device, int state);
52 static int acpi_fan_resume(struct acpi_device *device, int state);
54 static struct acpi_driver acpi_fan_driver = {
55 .name = ACPI_FAN_DRIVER_NAME,
56 .class = ACPI_FAN_CLASS,
57 .ids = "PNP0C0B",
58 .ops = {
59 .add = acpi_fan_add,
60 .remove = acpi_fan_remove,
61 .suspend = acpi_fan_suspend,
62 .resume = acpi_fan_resume,
63 },
64 };
66 struct acpi_fan {
67 struct acpi_device * device;
68 };
70 /* --------------------------------------------------------------------------
71 FS Interface (/proc)
72 -------------------------------------------------------------------------- */
74 static struct proc_dir_entry *acpi_fan_dir;
76 static int acpi_fan_read_state(struct seq_file *seq, void *offset)
77 {
78 struct acpi_fan *fan = seq->private;
79 int state = 0;
82 if (fan) {
83 if (acpi_bus_get_power(fan->device->handle, &state))
84 seq_printf(seq, "status: ERROR\n");
85 else
86 seq_printf(seq, "status: %s\n",
87 !state ? "on" : "off");
88 }
89 return 0;
90 }
92 static int acpi_fan_state_open_fs(struct inode *inode, struct file *file)
93 {
94 return single_open(file, acpi_fan_read_state, PDE(inode)->data);
95 }
97 static ssize_t
98 acpi_fan_write_state(struct file *file, const char __user * buffer,
99 size_t count, loff_t * ppos)
100 {
101 int result = 0;
102 struct seq_file *m = (struct seq_file *)file->private_data;
103 struct acpi_fan *fan = (struct acpi_fan *)m->private;
104 char state_string[12] = { '\0' };
107 if (!fan || (count > sizeof(state_string) - 1))
108 return -EINVAL;
110 if (copy_from_user(state_string, buffer, count))
111 return -EFAULT;
113 state_string[count] = '\0';
115 result = acpi_bus_set_power(fan->device->handle,
116 simple_strtoul(state_string, NULL, 0));
117 if (result)
118 return result;
120 return count;
121 }
123 static const struct file_operations acpi_fan_state_ops = {
124 .open = acpi_fan_state_open_fs,
125 .read = seq_read,
126 .write = acpi_fan_write_state,
127 .llseek = seq_lseek,
128 .release = single_release,
129 .owner = THIS_MODULE,
130 };
132 static int acpi_fan_add_fs(struct acpi_device *device)
133 {
134 struct proc_dir_entry *entry = NULL;
137 if (!device)
138 return -EINVAL;
140 if (!acpi_device_dir(device)) {
141 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
142 acpi_fan_dir);
143 if (!acpi_device_dir(device))
144 return -ENODEV;
145 acpi_device_dir(device)->owner = THIS_MODULE;
146 }
148 /* 'status' [R/W] */
149 entry = create_proc_entry(ACPI_FAN_FILE_STATE,
150 S_IFREG | S_IRUGO | S_IWUSR,
151 acpi_device_dir(device));
152 if (!entry)
153 return -ENODEV;
154 else {
155 entry->proc_fops = &acpi_fan_state_ops;
156 entry->data = acpi_driver_data(device);
157 entry->owner = THIS_MODULE;
158 }
160 return 0;
161 }
163 static int acpi_fan_remove_fs(struct acpi_device *device)
164 {
166 if (acpi_device_dir(device)) {
167 remove_proc_entry(ACPI_FAN_FILE_STATE, acpi_device_dir(device));
168 remove_proc_entry(acpi_device_bid(device), acpi_fan_dir);
169 acpi_device_dir(device) = NULL;
170 }
172 return 0;
173 }
175 /* --------------------------------------------------------------------------
176 Driver Interface
177 -------------------------------------------------------------------------- */
179 static int acpi_fan_add(struct acpi_device *device)
180 {
181 int result = 0;
182 struct acpi_fan *fan = NULL;
183 int state = 0;
186 if (!device)
187 return -EINVAL;
189 fan = kmalloc(sizeof(struct acpi_fan), GFP_KERNEL);
190 if (!fan)
191 return -ENOMEM;
192 memset(fan, 0, sizeof(struct acpi_fan));
194 fan->device = device;
195 strcpy(acpi_device_name(device), "Fan");
196 strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
197 acpi_driver_data(device) = fan;
199 result = acpi_bus_get_power(device->handle, &state);
200 if (result) {
201 printk(KERN_ERR PREFIX "Reading power state\n");
202 goto end;
203 }
205 device->flags.force_power_state = 1;
206 acpi_bus_set_power(device->handle, state);
207 device->flags.force_power_state = 0;
209 result = acpi_fan_add_fs(device);
210 if (result)
211 goto end;
213 printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
214 acpi_device_name(device), acpi_device_bid(device),
215 !device->power.state ? "on" : "off");
217 end:
218 if (result)
219 kfree(fan);
221 return result;
222 }
224 static int acpi_fan_remove(struct acpi_device *device, int type)
225 {
226 struct acpi_fan *fan = NULL;
229 if (!device || !acpi_driver_data(device))
230 return -EINVAL;
232 fan = (struct acpi_fan *)acpi_driver_data(device);
234 acpi_fan_remove_fs(device);
236 kfree(fan);
238 return 0;
239 }
241 static int acpi_fan_suspend(struct acpi_device *device, int state)
242 {
243 if (!device)
244 return -EINVAL;
246 acpi_bus_set_power(device->handle, ACPI_STATE_D0);
248 return AE_OK;
249 }
251 static int acpi_fan_resume(struct acpi_device *device, int state)
252 {
253 int result = 0;
254 int power_state = 0;
256 if (!device)
257 return -EINVAL;
259 result = acpi_bus_get_power(device->handle, &power_state);
260 if (result) {
261 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
262 "Error reading fan power state\n"));
263 return result;
264 }
266 device->flags.force_power_state = 1;
267 acpi_bus_set_power(device->handle, power_state);
268 device->flags.force_power_state = 0;
270 return result;
271 }
273 static int __init acpi_fan_init(void)
274 {
275 int result = 0;
278 acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
279 if (!acpi_fan_dir)
280 return -ENODEV;
281 acpi_fan_dir->owner = THIS_MODULE;
283 result = acpi_bus_register_driver(&acpi_fan_driver);
284 if (result < 0) {
285 remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
286 return -ENODEV;
287 }
289 return 0;
290 }
292 static void __exit acpi_fan_exit(void)
293 {
295 acpi_bus_unregister_driver(&acpi_fan_driver);
297 remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
299 return;
300 }
302 module_init(acpi_fan_init);
303 module_exit(acpi_fan_exit);