aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/xen/Kconfig30
-rw-r--r--drivers/xen/balloon.c139
-rw-r--r--include/xen/balloon.h4
3 files changed, 171 insertions, 2 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 03bc471c3eed..f815283667af 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -26,6 +26,36 @@ config XEN_SELFBALLOONING
26 kernel boot parameter. Note that systems without a sufficiently 26 kernel boot parameter. Note that systems without a sufficiently
27 large swap device should not enable self-ballooning. 27 large swap device should not enable self-ballooning.
28 28
29config XEN_BALLOON_MEMORY_HOTPLUG
30 bool "Memory hotplug support for Xen balloon driver"
31 default n
32 depends on XEN_BALLOON && MEMORY_HOTPLUG
33 help
34 Memory hotplug support for Xen balloon driver allows expanding memory
35 available for the system above limit declared at system startup.
36 It is very useful on critical systems which require long
37 run without rebooting.
38
39 Memory could be hotplugged in following steps:
40
41 1) dom0: xl mem-max <domU> <maxmem>
42 where <maxmem> is >= requested memory size,
43
44 2) dom0: xl mem-set <domU> <memory>
45 where <memory> is requested memory size; alternatively memory
46 could be added by writing proper value to
47 /sys/devices/system/xen_memory/xen_memory0/target or
48 /sys/devices/system/xen_memory/xen_memory0/target_kb on dumU,
49
50 3) domU: for i in /sys/devices/system/memory/memory*/state; do \
51 [ "`cat "$i"`" = offline ] && echo online > "$i"; done
52
53 Memory could be onlined automatically on domU by adding following line to udev rules:
54
55 SUBSYSTEM=="memory", ACTION=="add", RUN+="/bin/sh -c '[ -f /sys$devpath/state ] && echo online > /sys$devpath/state'"
56
57 In that case step 3 should be omitted.
58
29config XEN_SCRUB_PAGES 59config XEN_SCRUB_PAGES
30 bool "Scrub pages before returning them to system" 60 bool "Scrub pages before returning them to system"
31 depends on XEN_BALLOON 61 depends on XEN_BALLOON
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index f54290baa3db..5dfd8f8ff07f 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -4,6 +4,12 @@
4 * Copyright (c) 2003, B Dragovic 4 * Copyright (c) 2003, B Dragovic
5 * Copyright (c) 2003-2004, M Williamson, K Fraser 5 * Copyright (c) 2003-2004, M Williamson, K Fraser
6 * Copyright (c) 2005 Dan M. Smith, IBM Corporation 6 * Copyright (c) 2005 Dan M. Smith, IBM Corporation
7 * Copyright (c) 2010 Daniel Kiper
8 *
9 * Memory hotplug support was written by Daniel Kiper. Work on
10 * it was sponsored by Google under Google Summer of Code 2010
11 * program. Jeremy Fitzhardinge from Citrix was the mentor for
12 * this project.
7 * 13 *
8 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2 15 * modify it under the terms of the GNU General Public License version 2
@@ -40,6 +46,9 @@
40#include <linux/mutex.h> 46#include <linux/mutex.h>
41#include <linux/list.h> 47#include <linux/list.h>
42#include <linux/gfp.h> 48#include <linux/gfp.h>
49#include <linux/notifier.h>
50#include <linux/memory.h>
51#include <linux/memory_hotplug.h>
43 52
44#include <asm/page.h> 53#include <asm/page.h>
45#include <asm/pgalloc.h> 54#include <asm/pgalloc.h>
@@ -194,6 +203,87 @@ static enum bp_state update_schedule(enum bp_state state)
194 return BP_EAGAIN; 203 return BP_EAGAIN;
195} 204}
196 205
206#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
207static long current_credit(void)
208{
209 return balloon_stats.target_pages - balloon_stats.current_pages -
210 balloon_stats.hotplug_pages;
211}
212
213static bool balloon_is_inflated(void)
214{
215 if (balloon_stats.balloon_low || balloon_stats.balloon_high ||
216 balloon_stats.balloon_hotplug)
217 return true;
218 else
219 return false;
220}
221
222/*
223 * reserve_additional_memory() adds memory region of size >= credit above
224 * max_pfn. New region is section aligned and size is modified to be multiple
225 * of section size. Those features allow optimal use of address space and
226 * establish proper alignment when this function is called first time after
227 * boot (last section not fully populated at boot time contains unused memory
228 * pages with PG_reserved bit not set; online_pages_range() does not allow page
229 * onlining in whole range if first onlined page does not have PG_reserved
230 * bit set). Real size of added memory is established at page onlining stage.
231 */
232
233static enum bp_state reserve_additional_memory(long credit)
234{
235 int nid, rc;
236 u64 hotplug_start_paddr;
237 unsigned long balloon_hotplug = credit;
238
239 hotplug_start_paddr = PFN_PHYS(SECTION_ALIGN_UP(max_pfn));
240 balloon_hotplug = round_up(balloon_hotplug, PAGES_PER_SECTION);
241 nid = memory_add_physaddr_to_nid(hotplug_start_paddr);
242
243 rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT);
244
245 if (rc) {
246 pr_info("xen_balloon: %s: add_memory() failed: %i\n", __func__, rc);
247 return BP_EAGAIN;
248 }
249
250 balloon_hotplug -= credit;
251
252 balloon_stats.hotplug_pages += credit;
253 balloon_stats.balloon_hotplug = balloon_hotplug;
254
255 return BP_DONE;
256}
257
258static void xen_online_page(struct page *page)
259{
260 __online_page_set_limits(page);
261
262 mutex_lock(&balloon_mutex);
263
264 __balloon_append(page);
265
266 if (balloon_stats.hotplug_pages)
267 --balloon_stats.hotplug_pages;
268 else
269 --balloon_stats.balloon_hotplug;
270
271 mutex_unlock(&balloon_mutex);
272}
273
274static int xen_memory_notifier(struct notifier_block *nb, unsigned long val, void *v)
275{
276 if (val == MEM_ONLINE)
277 schedule_delayed_work(&balloon_worker, 0);
278
279 return NOTIFY_OK;
280}
281
282static struct notifier_block xen_memory_nb = {
283 .notifier_call = xen_memory_notifier,
284 .priority = 0
285};
286#else
197static long current_credit(void) 287static long current_credit(void)
198{ 288{
199 unsigned long target = balloon_stats.target_pages; 289 unsigned long target = balloon_stats.target_pages;
@@ -206,6 +296,21 @@ static long current_credit(void)
206 return target - balloon_stats.current_pages; 296 return target - balloon_stats.current_pages;
207} 297}
208 298
299static bool balloon_is_inflated(void)
300{
301 if (balloon_stats.balloon_low || balloon_stats.balloon_high)
302 return true;
303 else
304 return false;
305}
306
307static enum bp_state reserve_additional_memory(long credit)
308{
309 balloon_stats.target_pages = balloon_stats.current_pages;
310 return BP_DONE;
311}
312#endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */
313
209static enum bp_state increase_reservation(unsigned long nr_pages) 314static enum bp_state increase_reservation(unsigned long nr_pages)
210{ 315{
211 int rc; 316 int rc;
@@ -217,6 +322,15 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
217 .domid = DOMID_SELF 322 .domid = DOMID_SELF
218 }; 323 };
219 324
325#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
326 if (!balloon_stats.balloon_low && !balloon_stats.balloon_high) {
327 nr_pages = min(nr_pages, balloon_stats.balloon_hotplug);
328 balloon_stats.hotplug_pages += nr_pages;
329 balloon_stats.balloon_hotplug -= nr_pages;
330 return BP_DONE;
331 }
332#endif
333
220 if (nr_pages > ARRAY_SIZE(frame_list)) 334 if (nr_pages > ARRAY_SIZE(frame_list))
221 nr_pages = ARRAY_SIZE(frame_list); 335 nr_pages = ARRAY_SIZE(frame_list);
222 336
@@ -279,6 +393,15 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
279 .domid = DOMID_SELF 393 .domid = DOMID_SELF
280 }; 394 };
281 395
396#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
397 if (balloon_stats.hotplug_pages) {
398 nr_pages = min(nr_pages, balloon_stats.hotplug_pages);
399 balloon_stats.hotplug_pages -= nr_pages;
400 balloon_stats.balloon_hotplug += nr_pages;
401 return BP_DONE;
402 }
403#endif
404
282 if (nr_pages > ARRAY_SIZE(frame_list)) 405 if (nr_pages > ARRAY_SIZE(frame_list))
283 nr_pages = ARRAY_SIZE(frame_list); 406 nr_pages = ARRAY_SIZE(frame_list);
284 407
@@ -340,8 +463,12 @@ static void balloon_process(struct work_struct *work)
340 do { 463 do {
341 credit = current_credit(); 464 credit = current_credit();
342 465
343 if (credit > 0) 466 if (credit > 0) {
344 state = increase_reservation(credit); 467 if (balloon_is_inflated())
468 state = increase_reservation(credit);
469 else
470 state = reserve_additional_memory(credit);
471 }
345 472
346 if (credit < 0) 473 if (credit < 0)
347 state = decrease_reservation(-credit, GFP_BALLOON); 474 state = decrease_reservation(-credit, GFP_BALLOON);
@@ -448,6 +575,14 @@ static int __init balloon_init(void)
448 balloon_stats.retry_count = 1; 575 balloon_stats.retry_count = 1;
449 balloon_stats.max_retry_count = RETRY_UNLIMITED; 576 balloon_stats.max_retry_count = RETRY_UNLIMITED;
450 577
578#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
579 balloon_stats.hotplug_pages = 0;
580 balloon_stats.balloon_hotplug = 0;
581
582 set_online_page_callback(&xen_online_page);
583 register_memory_notifier(&xen_memory_nb);
584#endif
585
451 /* 586 /*
452 * Initialise the balloon with excess memory space. We need 587 * Initialise the balloon with excess memory space. We need
453 * to make sure we don't add memory which doesn't exist or 588 * to make sure we don't add memory which doesn't exist or
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
index 4076ed72afbd..76f7538bb339 100644
--- a/include/xen/balloon.h
+++ b/include/xen/balloon.h
@@ -15,6 +15,10 @@ struct balloon_stats {
15 unsigned long max_schedule_delay; 15 unsigned long max_schedule_delay;
16 unsigned long retry_count; 16 unsigned long retry_count;
17 unsigned long max_retry_count; 17 unsigned long max_retry_count;
18#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
19 unsigned long hotplug_pages;
20 unsigned long balloon_hotplug;
21#endif
18}; 22};
19 23
20extern struct balloon_stats balloon_stats; 24extern struct balloon_stats balloon_stats;