ia64/linux-2.6.18-xen.hg

view arch/sparc64/kernel/power.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 /* $Id: power.c,v 1.10 2001/12/11 01:57:16 davem Exp $
2 * power.c: Power management driver.
3 *
4 * Copyright (C) 1999 David S. Miller (davem@redhat.com)
5 */
7 #define __KERNEL_SYSCALLS__
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/sched.h>
13 #include <linux/signal.h>
14 #include <linux/delay.h>
15 #include <linux/interrupt.h>
16 #include <linux/pm.h>
18 #include <asm/system.h>
19 #include <asm/auxio.h>
20 #include <asm/prom.h>
21 #include <asm/of_device.h>
22 #include <asm/io.h>
24 #include <linux/unistd.h>
26 /*
27 * sysctl - toggle power-off restriction for serial console
28 * systems in machine_power_off()
29 */
30 int scons_pwroff = 1;
32 #ifdef CONFIG_PCI
33 #include <linux/pci.h>
34 static void __iomem *power_reg;
36 static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
37 static int button_pressed;
39 static irqreturn_t power_handler(int irq, void *dev_id, struct pt_regs *regs)
40 {
41 if (button_pressed == 0) {
42 button_pressed = 1;
43 wake_up(&powerd_wait);
44 }
46 /* FIXME: Check registers for status... */
47 return IRQ_HANDLED;
48 }
49 #endif /* CONFIG_PCI */
51 extern void machine_halt(void);
52 extern void machine_alt_power_off(void);
53 static void (*poweroff_method)(void) = machine_alt_power_off;
55 void machine_power_off(void)
56 {
57 if (!serial_console || scons_pwroff) {
58 #ifdef CONFIG_PCI
59 if (power_reg) {
60 /* Both register bits seem to have the
61 * same effect, so until I figure out
62 * what the difference is...
63 */
64 writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg);
65 } else
66 #endif /* CONFIG_PCI */
67 if (poweroff_method != NULL) {
68 poweroff_method();
69 /* not reached */
70 }
71 }
72 machine_halt();
73 }
75 void (*pm_power_off)(void) = machine_power_off;
76 EXPORT_SYMBOL(pm_power_off);
78 #ifdef CONFIG_PCI
79 static int powerd(void *__unused)
80 {
81 static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
82 char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
83 DECLARE_WAITQUEUE(wait, current);
85 daemonize("powerd");
87 add_wait_queue(&powerd_wait, &wait);
88 again:
89 for (;;) {
90 set_task_state(current, TASK_INTERRUPTIBLE);
91 if (button_pressed)
92 break;
93 flush_signals(current);
94 schedule();
95 }
96 __set_current_state(TASK_RUNNING);
97 remove_wait_queue(&powerd_wait, &wait);
99 /* Ok, down we go... */
100 button_pressed = 0;
101 if (execve("/sbin/shutdown", argv, envp) < 0) {
102 printk("powerd: shutdown execution failed\n");
103 add_wait_queue(&powerd_wait, &wait);
104 goto again;
105 }
106 return 0;
107 }
109 static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
110 {
111 if (irq == PCI_IRQ_NONE)
112 return 0;
113 if (!of_find_property(dp, "button", NULL))
114 return 0;
116 return 1;
117 }
119 static int __devinit power_probe(struct of_device *op, const struct of_device_id *match)
120 {
121 struct resource *res = &op->resource[0];
122 unsigned int irq= op->irqs[0];
124 power_reg = of_ioremap(res, 0, 0x4, "power");
126 printk("%s: Control reg at %lx ... ",
127 op->node->name, res->start);
129 poweroff_method = machine_halt; /* able to use the standard halt */
131 if (has_button_interrupt(irq, op->node)) {
132 if (kernel_thread(powerd, NULL, CLONE_FS) < 0) {
133 printk("Failed to start power daemon.\n");
134 return 0;
135 }
136 printk("powerd running.\n");
138 if (request_irq(irq,
139 power_handler, 0, "power", NULL) < 0)
140 printk("power: Error, cannot register IRQ handler.\n");
141 } else {
142 printk("not using powerd.\n");
143 }
145 return 0;
146 }
148 static struct of_device_id power_match[] = {
149 {
150 .name = "power",
151 },
152 {},
153 };
155 static struct of_platform_driver power_driver = {
156 .name = "power",
157 .match_table = power_match,
158 .probe = power_probe,
159 };
161 void __init power_init(void)
162 {
163 of_register_driver(&power_driver, &of_bus_type);
164 return;
165 }
166 #endif /* CONFIG_PCI */