aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
authorDaniel Kiper <dkiper@net-space.pl>2011-03-08 16:48:24 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-03-14 11:34:21 -0400
commit95d2ac4a0c904942a4fecf815781ebd4171e7a30 (patch)
tree3460ad49cea47eb51dfee5fde9b9743f20f6dd52 /drivers/xen
parent95170b2e23d4e98843b4833d27fae7bf0910e19c (diff)
xen/balloon: Protect against CPU exhaust by event/x process
Protect against CPU exhaust by event/x process during errors by adding some delays in scheduling next event and retry count limit. Signed-off-by: Daniel Kiper <dkiper@net-space.pl> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/balloon.c107
1 files changed, 90 insertions, 17 deletions
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 9206ff7514e7..6cd2530f2330 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -66,6 +66,22 @@
66 66
67#define BALLOON_CLASS_NAME "xen_memory" 67#define BALLOON_CLASS_NAME "xen_memory"
68 68
69/*
70 * balloon_process() state:
71 *
72 * BP_DONE: done or nothing to do,
73 * BP_EAGAIN: error, go to sleep,
74 * BP_ECANCELED: error, balloon operation canceled.
75 */
76
77enum bp_state {
78 BP_DONE,
79 BP_EAGAIN,
80 BP_ECANCELED
81};
82
83#define RETRY_UNLIMITED 0
84
69struct balloon_stats { 85struct balloon_stats {
70 /* We aim for 'current allocation' == 'target allocation'. */ 86 /* We aim for 'current allocation' == 'target allocation'. */
71 unsigned long current_pages; 87 unsigned long current_pages;
@@ -73,6 +89,10 @@ struct balloon_stats {
73 /* Number of pages in high- and low-memory balloons. */ 89 /* Number of pages in high- and low-memory balloons. */
74 unsigned long balloon_low; 90 unsigned long balloon_low;
75 unsigned long balloon_high; 91 unsigned long balloon_high;
92 unsigned long schedule_delay;
93 unsigned long max_schedule_delay;
94 unsigned long retry_count;
95 unsigned long max_retry_count;
76}; 96};
77 97
78static DEFINE_MUTEX(balloon_mutex); 98static DEFINE_MUTEX(balloon_mutex);
@@ -171,6 +191,36 @@ static struct page *balloon_next_page(struct page *page)
171 return list_entry(next, struct page, lru); 191 return list_entry(next, struct page, lru);
172} 192}
173 193
194static enum bp_state update_schedule(enum bp_state state)
195{
196 if (state == BP_DONE) {
197 balloon_stats.schedule_delay = 1;
198 balloon_stats.retry_count = 1;
199 return BP_DONE;
200 }
201
202 pr_info("xen_balloon: Retry count: %lu/%lu\n", balloon_stats.retry_count,
203 balloon_stats.max_retry_count);
204
205 ++balloon_stats.retry_count;
206
207 if (balloon_stats.max_retry_count != RETRY_UNLIMITED &&
208 balloon_stats.retry_count > balloon_stats.max_retry_count) {
209 pr_info("xen_balloon: Retry count limit exceeded\n"
210 "xen_balloon: Balloon operation canceled\n");
211 balloon_stats.schedule_delay = 1;
212 balloon_stats.retry_count = 1;
213 return BP_ECANCELED;
214 }
215
216 balloon_stats.schedule_delay <<= 1;
217
218 if (balloon_stats.schedule_delay > balloon_stats.max_schedule_delay)
219 balloon_stats.schedule_delay = balloon_stats.max_schedule_delay;
220
221 return BP_EAGAIN;
222}
223
174static unsigned long current_target(void) 224static unsigned long current_target(void)
175{ 225{
176 unsigned long target = balloon_stats.target_pages; 226 unsigned long target = balloon_stats.target_pages;
@@ -183,11 +233,11 @@ static unsigned long current_target(void)
183 return target; 233 return target;
184} 234}
185 235
186static int increase_reservation(unsigned long nr_pages) 236static enum bp_state increase_reservation(unsigned long nr_pages)
187{ 237{
238 int rc;
188 unsigned long pfn, i; 239 unsigned long pfn, i;
189 struct page *page; 240 struct page *page;
190 long rc;
191 struct xen_memory_reservation reservation = { 241 struct xen_memory_reservation reservation = {
192 .address_bits = 0, 242 .address_bits = 0,
193 .extent_order = 0, 243 .extent_order = 0,
@@ -199,7 +249,10 @@ static int increase_reservation(unsigned long nr_pages)
199 249
200 page = balloon_first_page(); 250 page = balloon_first_page();
201 for (i = 0; i < nr_pages; i++) { 251 for (i = 0; i < nr_pages; i++) {
202 BUG_ON(page == NULL); 252 if (!page) {
253 nr_pages = i;
254 break;
255 }
203 frame_list[i] = page_to_pfn(page); 256 frame_list[i] = page_to_pfn(page);
204 page = balloon_next_page(page); 257 page = balloon_next_page(page);
205 } 258 }
@@ -207,8 +260,10 @@ static int increase_reservation(unsigned long nr_pages)
207 set_xen_guest_handle(reservation.extent_start, frame_list); 260 set_xen_guest_handle(reservation.extent_start, frame_list);
208 reservation.nr_extents = nr_pages; 261 reservation.nr_extents = nr_pages;
209 rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); 262 rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
210 if (rc < 0) 263 if (rc <= 0) {
211 goto out; 264 pr_info("xen_balloon: %s: Cannot allocate memory\n", __func__);
265 return BP_EAGAIN;
266 }
212 267
213 for (i = 0; i < rc; i++) { 268 for (i = 0; i < rc; i++) {
214 page = balloon_retrieve(); 269 page = balloon_retrieve();
@@ -238,15 +293,14 @@ static int increase_reservation(unsigned long nr_pages)
238 293
239 balloon_stats.current_pages += rc; 294 balloon_stats.current_pages += rc;
240 295
241 out: 296 return BP_DONE;
242 return rc < 0 ? rc : rc != nr_pages;
243} 297}
244 298
245static int decrease_reservation(unsigned long nr_pages) 299static enum bp_state decrease_reservation(unsigned long nr_pages)
246{ 300{
301 enum bp_state state = BP_DONE;
247 unsigned long pfn, i; 302 unsigned long pfn, i;
248 struct page *page; 303 struct page *page;
249 int need_sleep = 0;
250 int ret; 304 int ret;
251 struct xen_memory_reservation reservation = { 305 struct xen_memory_reservation reservation = {
252 .address_bits = 0, 306 .address_bits = 0,
@@ -259,8 +313,9 @@ static int decrease_reservation(unsigned long nr_pages)
259 313
260 for (i = 0; i < nr_pages; i++) { 314 for (i = 0; i < nr_pages; i++) {
261 if ((page = alloc_page(GFP_BALLOON)) == NULL) { 315 if ((page = alloc_page(GFP_BALLOON)) == NULL) {
316 pr_info("xen_balloon: %s: Cannot allocate memory\n", __func__);
262 nr_pages = i; 317 nr_pages = i;
263 need_sleep = 1; 318 state = BP_EAGAIN;
264 break; 319 break;
265 } 320 }
266 321
@@ -296,7 +351,7 @@ static int decrease_reservation(unsigned long nr_pages)
296 351
297 balloon_stats.current_pages -= nr_pages; 352 balloon_stats.current_pages -= nr_pages;
298 353
299 return need_sleep; 354 return state;
300} 355}
301 356
302/* 357/*
@@ -307,27 +362,31 @@ static int decrease_reservation(unsigned long nr_pages)
307 */ 362 */
308static void balloon_process(struct work_struct *work) 363static void balloon_process(struct work_struct *work)
309{ 364{
310 int need_sleep = 0; 365 enum bp_state state = BP_DONE;
311 long credit; 366 long credit;
312 367
313 mutex_lock(&balloon_mutex); 368 mutex_lock(&balloon_mutex);
314 369
315 do { 370 do {
316 credit = current_target() - balloon_stats.current_pages; 371 credit = current_target() - balloon_stats.current_pages;
372
317 if (credit > 0) 373 if (credit > 0)
318 need_sleep = (increase_reservation(credit) != 0); 374 state = increase_reservation(credit);
375
319 if (credit < 0) 376 if (credit < 0)
320 need_sleep = (decrease_reservation(-credit) != 0); 377 state = decrease_reservation(-credit);
378
379 state = update_schedule(state);
321 380
322#ifndef CONFIG_PREEMPT 381#ifndef CONFIG_PREEMPT
323 if (need_resched()) 382 if (need_resched())
324 schedule(); 383 schedule();
325#endif 384#endif
326 } while ((credit != 0) && !need_sleep); 385 } while (credit && state == BP_DONE);
327 386
328 /* Schedule more work if there is some still to be done. */ 387 /* Schedule more work if there is some still to be done. */
329 if (current_target() != balloon_stats.current_pages) 388 if (state == BP_EAGAIN)
330 schedule_delayed_work(&balloon_worker, HZ); 389 schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ);
331 390
332 mutex_unlock(&balloon_mutex); 391 mutex_unlock(&balloon_mutex);
333} 392}
@@ -394,6 +453,11 @@ static int __init balloon_init(void)
394 balloon_stats.balloon_low = 0; 453 balloon_stats.balloon_low = 0;
395 balloon_stats.balloon_high = 0; 454 balloon_stats.balloon_high = 0;
396 455
456 balloon_stats.schedule_delay = 1;
457 balloon_stats.max_schedule_delay = 32;
458 balloon_stats.retry_count = 1;
459 balloon_stats.max_retry_count = 16;
460
397 register_balloon(&balloon_sysdev); 461 register_balloon(&balloon_sysdev);
398 462
399 /* 463 /*
@@ -447,6 +511,11 @@ BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
447BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); 511BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
448BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); 512BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
449 513
514static SYSDEV_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay);
515static SYSDEV_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay);
516static SYSDEV_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count);
517static SYSDEV_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count);
518
450static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr, 519static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
451 char *buf) 520 char *buf)
452{ 521{
@@ -508,6 +577,10 @@ static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR,
508static struct sysdev_attribute *balloon_attrs[] = { 577static struct sysdev_attribute *balloon_attrs[] = {
509 &attr_target_kb, 578 &attr_target_kb,
510 &attr_target, 579 &attr_target,
580 &attr_schedule_delay.attr,
581 &attr_max_schedule_delay.attr,
582 &attr_retry_count.attr,
583 &attr_max_retry_count.attr
511}; 584};
512 585
513static struct attribute *balloon_info_attrs[] = { 586static struct attribute *balloon_info_attrs[] = {