diff options
-rw-r--r-- | drivers/xen/balloon.c | 90 | ||||
-rw-r--r-- | include/xen/balloon.h | 1 |
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 | ||
75 | static int xen_hotplug_unpopulated; | ||
76 | |||
77 | #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG | ||
78 | |||
79 | static int zero; | ||
80 | static int one = 1; | ||
81 | |||
82 | static 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 | |||
95 | static struct ctl_table balloon_root[] = { | ||
96 | { | ||
97 | .procname = "balloon", | ||
98 | .mode = 0555, | ||
99 | .child = balloon_table, | ||
100 | }, | ||
101 | { } | ||
102 | }; | ||
103 | |||
104 | static 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. */ |
101 | static LIST_HEAD(ballooned_pages); | 142 | static LIST_HEAD(ballooned_pages); |
143 | static 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. */ |
104 | static void balloon_process(struct work_struct *work); | 146 | static 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 | ||
132 | static void balloon_append(struct page *page) | 175 | static 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 = { | |||
323 | static enum bp_state reserve_additional_memory(void) | 367 | static 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 | } |
517 | EXPORT_SYMBOL_GPL(balloon_set_new_target); | 561 | EXPORT_SYMBOL_GPL(balloon_set_new_target); |
518 | 562 | ||
563 | static 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 | } |
551 | EXPORT_SYMBOL(alloc_xenballooned_pages); | 618 | EXPORT_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; |