ia64/linux-2.6.18-xen.hg

view arch/alpha/kernel/srmcons.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 * linux/arch/alpha/kernel/srmcons.c
3 *
4 * Callback based driver for SRM Console console device.
5 * (TTY driver and console driver)
6 */
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/console.h>
11 #include <linux/delay.h>
12 #include <linux/mm.h>
13 #include <linux/slab.h>
14 #include <linux/spinlock.h>
15 #include <linux/timer.h>
16 #include <linux/tty.h>
17 #include <linux/tty_driver.h>
18 #include <linux/tty_flip.h>
20 #include <asm/console.h>
21 #include <asm/uaccess.h>
24 static DEFINE_SPINLOCK(srmcons_callback_lock);
25 static int srm_is_registered_console = 0;
27 /*
28 * The TTY driver
29 */
30 #define MAX_SRM_CONSOLE_DEVICES 1 /* only support 1 console device */
32 struct srmcons_private {
33 struct tty_struct *tty;
34 struct timer_list timer;
35 spinlock_t lock;
36 };
38 typedef union _srmcons_result {
39 struct {
40 unsigned long c :61;
41 unsigned long status :3;
42 } bits;
43 long as_long;
44 } srmcons_result;
46 /* called with callback_lock held */
47 static int
48 srmcons_do_receive_chars(struct tty_struct *tty)
49 {
50 srmcons_result result;
51 int count = 0, loops = 0;
53 do {
54 result.as_long = callback_getc(0);
55 if (result.bits.status < 2) {
56 tty_insert_flip_char(tty, (char)result.bits.c, 0);
57 count++;
58 }
59 } while((result.bits.status & 1) && (++loops < 10));
61 if (count)
62 tty_schedule_flip(tty);
64 return count;
65 }
67 static void
68 srmcons_receive_chars(unsigned long data)
69 {
70 struct srmcons_private *srmconsp = (struct srmcons_private *)data;
71 unsigned long flags;
72 int incr = 10;
74 local_irq_save(flags);
75 if (spin_trylock(&srmcons_callback_lock)) {
76 if (!srmcons_do_receive_chars(srmconsp->tty))
77 incr = 100;
78 spin_unlock(&srmcons_callback_lock);
79 }
81 spin_lock(&srmconsp->lock);
82 if (srmconsp->tty) {
83 srmconsp->timer.expires = jiffies + incr;
84 add_timer(&srmconsp->timer);
85 }
86 spin_unlock(&srmconsp->lock);
88 local_irq_restore(flags);
89 }
91 /* called with callback_lock held */
92 static int
93 srmcons_do_write(struct tty_struct *tty, const char *buf, int count)
94 {
95 static char str_cr[1] = "\r";
96 long c, remaining = count;
97 srmcons_result result;
98 char *cur;
99 int need_cr;
101 for (cur = (char *)buf; remaining > 0; ) {
102 need_cr = 0;
103 /*
104 * Break it up into reasonable size chunks to allow a chance
105 * for input to get in
106 */
107 for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++)
108 if (cur[c] == '\n')
109 need_cr = 1;
111 while (c > 0) {
112 result.as_long = callback_puts(0, cur, c);
113 c -= result.bits.c;
114 remaining -= result.bits.c;
115 cur += result.bits.c;
117 /*
118 * Check for pending input iff a tty was provided
119 */
120 if (tty)
121 srmcons_do_receive_chars(tty);
122 }
124 while (need_cr) {
125 result.as_long = callback_puts(0, str_cr, 1);
126 if (result.bits.c > 0)
127 need_cr = 0;
128 }
129 }
130 return count;
131 }
133 static int
134 srmcons_write(struct tty_struct *tty,
135 const unsigned char *buf, int count)
136 {
137 unsigned long flags;
139 spin_lock_irqsave(&srmcons_callback_lock, flags);
140 srmcons_do_write(tty, (const char *) buf, count);
141 spin_unlock_irqrestore(&srmcons_callback_lock, flags);
143 return count;
144 }
146 static int
147 srmcons_write_room(struct tty_struct *tty)
148 {
149 return 512;
150 }
152 static int
153 srmcons_chars_in_buffer(struct tty_struct *tty)
154 {
155 return 0;
156 }
158 static int
159 srmcons_get_private_struct(struct srmcons_private **ps)
160 {
161 static struct srmcons_private *srmconsp = NULL;
162 static DEFINE_SPINLOCK(srmconsp_lock);
163 unsigned long flags;
164 int retval = 0;
166 if (srmconsp == NULL) {
167 spin_lock_irqsave(&srmconsp_lock, flags);
169 srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
170 if (srmconsp == NULL)
171 retval = -ENOMEM;
172 else {
173 srmconsp->tty = NULL;
174 spin_lock_init(&srmconsp->lock);
175 init_timer(&srmconsp->timer);
176 }
178 spin_unlock_irqrestore(&srmconsp_lock, flags);
179 }
181 *ps = srmconsp;
182 return retval;
183 }
185 static int
186 srmcons_open(struct tty_struct *tty, struct file *filp)
187 {
188 struct srmcons_private *srmconsp;
189 unsigned long flags;
190 int retval;
192 retval = srmcons_get_private_struct(&srmconsp);
193 if (retval)
194 return retval;
196 spin_lock_irqsave(&srmconsp->lock, flags);
198 if (!srmconsp->tty) {
199 tty->driver_data = srmconsp;
201 srmconsp->tty = tty;
202 srmconsp->timer.function = srmcons_receive_chars;
203 srmconsp->timer.data = (unsigned long)srmconsp;
204 srmconsp->timer.expires = jiffies + 10;
205 add_timer(&srmconsp->timer);
206 }
208 spin_unlock_irqrestore(&srmconsp->lock, flags);
210 return 0;
211 }
213 static void
214 srmcons_close(struct tty_struct *tty, struct file *filp)
215 {
216 struct srmcons_private *srmconsp = tty->driver_data;
217 unsigned long flags;
219 spin_lock_irqsave(&srmconsp->lock, flags);
221 if (tty->count == 1) {
222 srmconsp->tty = NULL;
223 del_timer(&srmconsp->timer);
224 }
226 spin_unlock_irqrestore(&srmconsp->lock, flags);
227 }
230 static struct tty_driver *srmcons_driver;
232 static struct tty_operations srmcons_ops = {
233 .open = srmcons_open,
234 .close = srmcons_close,
235 .write = srmcons_write,
236 .write_room = srmcons_write_room,
237 .chars_in_buffer= srmcons_chars_in_buffer,
238 };
240 static int __init
241 srmcons_init(void)
242 {
243 if (srm_is_registered_console) {
244 struct tty_driver *driver;
245 int err;
247 driver = alloc_tty_driver(MAX_SRM_CONSOLE_DEVICES);
248 if (!driver)
249 return -ENOMEM;
250 driver->driver_name = "srm";
251 driver->name = "srm";
252 driver->major = 0; /* dynamic */
253 driver->minor_start = 0;
254 driver->type = TTY_DRIVER_TYPE_SYSTEM;
255 driver->subtype = SYSTEM_TYPE_SYSCONS;
256 driver->init_termios = tty_std_termios;
257 tty_set_operations(driver, &srmcons_ops);
258 err = tty_register_driver(driver);
259 if (err) {
260 put_tty_driver(driver);
261 return err;
262 }
263 srmcons_driver = driver;
264 }
266 return -ENODEV;
267 }
269 module_init(srmcons_init);
272 /*
273 * The console driver
274 */
275 static void
276 srm_console_write(struct console *co, const char *s, unsigned count)
277 {
278 unsigned long flags;
280 spin_lock_irqsave(&srmcons_callback_lock, flags);
281 srmcons_do_write(NULL, s, count);
282 spin_unlock_irqrestore(&srmcons_callback_lock, flags);
283 }
285 static struct tty_driver *
286 srm_console_device(struct console *co, int *index)
287 {
288 *index = co->index;
289 return srmcons_driver;
290 }
292 static int __init
293 srm_console_setup(struct console *co, char *options)
294 {
295 return 0;
296 }
298 static struct console srmcons = {
299 .name = "srm",
300 .write = srm_console_write,
301 .device = srm_console_device,
302 .setup = srm_console_setup,
303 .flags = CON_PRINTBUFFER,
304 .index = -1,
305 };
307 void __init
308 register_srm_console(void)
309 {
310 if (!srm_is_registered_console) {
311 callback_open_console();
312 register_console(&srmcons);
313 srm_is_registered_console = 1;
314 }
315 }
317 void __init
318 unregister_srm_console(void)
319 {
320 if (srm_is_registered_console) {
321 callback_close_console();
322 unregister_console(&srmcons);
323 srm_is_registered_console = 0;
324 }
325 }