diff options
| -rw-r--r-- | drivers/xen/Kconfig | 30 | ||||
| -rw-r--r-- | drivers/xen/balloon.c | 139 | ||||
| -rw-r--r-- | include/xen/balloon.h | 4 |
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 | ||
| 29 | config 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 | |||
| 29 | config XEN_SCRUB_PAGES | 59 | config 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 | ||
| 207 | static long current_credit(void) | ||
| 208 | { | ||
| 209 | return balloon_stats.target_pages - balloon_stats.current_pages - | ||
| 210 | balloon_stats.hotplug_pages; | ||
| 211 | } | ||
| 212 | |||
| 213 | static 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 | |||
| 233 | static 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 | |||
| 258 | static 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 | |||
| 274 | static 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 | |||
| 282 | static struct notifier_block xen_memory_nb = { | ||
| 283 | .notifier_call = xen_memory_notifier, | ||
| 284 | .priority = 0 | ||
| 285 | }; | ||
| 286 | #else | ||
| 197 | static long current_credit(void) | 287 | static 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 | ||
| 299 | static 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 | |||
| 307 | static 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 | |||
| 209 | static enum bp_state increase_reservation(unsigned long nr_pages) | 314 | static 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 | |||
