aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/xen/balloon.c90
-rw-r--r--include/xen/balloon.h1
2 files changed, 81 insertions, 10 deletions
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 7ec933d505d2..25fd1bd949d8 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -55,6 +55,7 @@
55#include <linux/memory_hotplug.h> 55#include <linux/memory_hotplug.h>
56#include <linux/percpu-defs.h> 56#include <linux/percpu-defs.h>
57#include <linux/slab.h> 57#include <linux/slab.h>
58#include <linux/sysctl.h>
58 59
59#include <asm/page.h> 60#include <asm/page.h>
60#include <asm/pgalloc.h> 61#include <asm/pgalloc.h>
@@ -71,6 +72,46 @@
71#include <xen/features.h> 72#include <xen/features.h>
72#include <xen/page.h> 73#include <xen/page.h>
73 74
75static int xen_hotplug_unpopulated;
76
77#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
78
79static int zero;
80static int one = 1;
81
82static struct ctl_table balloon_table[] = {
83 {
84 .procname = "hotplug_unpopulated",
85 .data = &xen_hotplug_unpopulated,
86 .maxlen = sizeof(int),
87 .mode = 0644,
88 .proc_handler = proc_dointvec_minmax,
89 .extra1 = &zero,
90 .extra2 = &one,
91 },
92 { }
93};
94
95static struct ctl_table balloon_root[] = {
96 {
97 .procname = "balloon",
98 .mode = 0555,
99 .child = balloon_table,
100 },
101 { }
102};
103
104static struct ctl_table xen_root[] = {
105 {
106 .procname = "xen",
107 .mode = 0555,
108 .child = balloon_root,
109 },
110 { }
111};
112
113#endif
114
74/* 115/*
75 * balloon_process() state: 116 * balloon_process() state:
76 * 117 *
@@ -99,6 +140,7 @@ static xen_pfn_t frame_list[PAGE_SIZE / sizeof(unsigned long)];
99 140
100/* List of ballooned pages, threaded through the mem_map array. */ 141/* List of ballooned pages, threaded through the mem_map array. */
101static LIST_HEAD(ballooned_pages); 142static LIST_HEAD(ballooned_pages);
143static DECLARE_WAIT_QUEUE_HEAD(balloon_wq);
102 144
103/* Main work function, always executed in process context. */ 145/* Main work function, always executed in process context. */
104static void balloon_process(struct work_struct *work); 146static void balloon_process(struct work_struct *work);
@@ -127,6 +169,7 @@ static void __balloon_append(struct page *page)
127 list_add(&page->lru, &ballooned_pages); 169 list_add(&page->lru, &ballooned_pages);
128 balloon_stats.balloon_low++; 170 balloon_stats.balloon_low++;
129 } 171 }
172 wake_up(&balloon_wq);
130} 173}
131 174
132static void balloon_append(struct page *page) 175static void balloon_append(struct page *page)
@@ -242,7 +285,8 @@ static enum bp_state reserve_additional_memory(void)
242 int nid, rc; 285 int nid, rc;
243 unsigned long balloon_hotplug; 286 unsigned long balloon_hotplug;
244 287
245 credit = balloon_stats.target_pages - balloon_stats.total_pages; 288 credit = balloon_stats.target_pages + balloon_stats.target_unpopulated
289 - balloon_stats.total_pages;
246 290
247 /* 291 /*
248 * Already hotplugged enough pages? Wait for them to be 292 * Already hotplugged enough pages? Wait for them to be
@@ -323,7 +367,7 @@ static struct notifier_block xen_memory_nb = {
323static enum bp_state reserve_additional_memory(void) 367static enum bp_state reserve_additional_memory(void)
324{ 368{
325 balloon_stats.target_pages = balloon_stats.current_pages; 369 balloon_stats.target_pages = balloon_stats.current_pages;
326 return BP_DONE; 370 return BP_ECANCELED;
327} 371}
328#endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */ 372#endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */
329 373
@@ -516,6 +560,28 @@ void balloon_set_new_target(unsigned long target)
516} 560}
517EXPORT_SYMBOL_GPL(balloon_set_new_target); 561EXPORT_SYMBOL_GPL(balloon_set_new_target);
518 562
563static int add_ballooned_pages(int nr_pages)
564{
565 enum bp_state st;
566
567 if (xen_hotplug_unpopulated) {
568 st = reserve_additional_memory();
569 if (st != BP_ECANCELED) {
570 mutex_unlock(&balloon_mutex);
571 wait_event(balloon_wq,
572 !list_empty(&ballooned_pages));
573 mutex_lock(&balloon_mutex);
574 return 0;
575 }
576 }
577
578 st = decrease_reservation(nr_pages, GFP_USER);
579 if (st != BP_DONE)
580 return -ENOMEM;
581
582 return 0;
583}
584
519/** 585/**
520 * alloc_xenballooned_pages - get pages that have been ballooned out 586 * alloc_xenballooned_pages - get pages that have been ballooned out
521 * @nr_pages: Number of pages to get 587 * @nr_pages: Number of pages to get
@@ -526,27 +592,28 @@ int alloc_xenballooned_pages(int nr_pages, struct page **pages)
526{ 592{
527 int pgno = 0; 593 int pgno = 0;
528 struct page *page; 594 struct page *page;
595 int ret;
596
529 mutex_lock(&balloon_mutex); 597 mutex_lock(&balloon_mutex);
598
599 balloon_stats.target_unpopulated += nr_pages;
600
530 while (pgno < nr_pages) { 601 while (pgno < nr_pages) {
531 page = balloon_retrieve(true); 602 page = balloon_retrieve(true);
532 if (page) { 603 if (page) {
533 pages[pgno++] = page; 604 pages[pgno++] = page;
534 } else { 605 } else {
535 enum bp_state st; 606 ret = add_ballooned_pages(nr_pages - pgno);
536 st = decrease_reservation(nr_pages - pgno, GFP_USER); 607 if (ret < 0)
537 if (st != BP_DONE)
538 goto out_undo; 608 goto out_undo;
539 } 609 }
540 } 610 }
541 mutex_unlock(&balloon_mutex); 611 mutex_unlock(&balloon_mutex);
542 return 0; 612 return 0;
543 out_undo: 613 out_undo:
544 while (pgno)
545 balloon_append(pages[--pgno]);
546 /* Free the memory back to the kernel soon */
547 schedule_delayed_work(&balloon_worker, 0);
548 mutex_unlock(&balloon_mutex); 614 mutex_unlock(&balloon_mutex);
549 return -ENOMEM; 615 free_xenballooned_pages(pgno, pages);
616 return ret;
550} 617}
551EXPORT_SYMBOL(alloc_xenballooned_pages); 618EXPORT_SYMBOL(alloc_xenballooned_pages);
552 619
@@ -566,6 +633,8 @@ void free_xenballooned_pages(int nr_pages, struct page **pages)
566 balloon_append(pages[i]); 633 balloon_append(pages[i]);
567 } 634 }
568 635
636 balloon_stats.target_unpopulated -= nr_pages;
637
569 /* The balloon may be too large now. Shrink it if needed. */ 638 /* The balloon may be too large now. Shrink it if needed. */
570 if (current_credit()) 639 if (current_credit())
571 schedule_delayed_work(&balloon_worker, 0); 640 schedule_delayed_work(&balloon_worker, 0);
@@ -623,6 +692,7 @@ static int __init balloon_init(void)
623#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG 692#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
624 set_online_page_callback(&xen_online_page); 693 set_online_page_callback(&xen_online_page);
625 register_memory_notifier(&xen_memory_nb); 694 register_memory_notifier(&xen_memory_nb);
695 register_sysctl_table(xen_root);
626#endif 696#endif
627 697
628 /* 698 /*
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
index 83efdeb243bf..d1767dfb0d95 100644
--- a/include/xen/balloon.h
+++ b/include/xen/balloon.h
@@ -8,6 +8,7 @@ struct balloon_stats {
8 /* We aim for 'current allocation' == 'target allocation'. */ 8 /* We aim for 'current allocation' == 'target allocation'. */
9 unsigned long current_pages; 9 unsigned long current_pages;
10 unsigned long target_pages; 10 unsigned long target_pages;
11 unsigned long target_unpopulated;
11 /* Number of pages in high- and low-memory balloons. */ 12 /* Number of pages in high- and low-memory balloons. */
12 unsigned long balloon_low; 13 unsigned long balloon_low;
13 unsigned long balloon_high; 14 unsigned long balloon_high;