Hi, I am sending this e-mail once again because it probably has been lost in abyss of Xen-devel/LKLM list. Here is the second version of memory hotplug support for Xen guests patch. This one cleanly applies to git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git repository, xen/memory-hotplug head. Changes: - /sys/devices/system/memory/probe interface has been removed; /sys/devices/system/xen_memory/xen_memory0/{target,target_kb} are much better (I forgot about them), - most of the code have been moved to drivers/xen/balloon.c, - this changes forced me to export hotadd_new_pgdat and rollback_node_hotadd function from mm/memory_hotplug.c; could it be accepted by mm/memory_hotplug.c maintainers ??? - PV on HVM mode is supported now; it was tested on git://xenbits.xen.org/people/sstabellini/linux-pvhvm.git repository, 2.6.34-pvhvm head, - most of Jeremy suggestions have been applied. On Wed, Jul 28, 2010 at 11:36:29AM +0400, Vasiliy G Tolstov wrote: [...] > Work's fine with opensuse 11.3 (dom0 and domU) Thx. On Thu, Jul 29, 2010 at 12:39:52PM -0700, Jeremy Fitzhardinge wrote: > On 07/26/2010 05:41 PM, Daniel Kiper wrote: > >Hi, > > > >Currently there is fully working version. > >It has been tested on Xen Ver. 4.0.0 in PV > >guest i386/x86_64 with Linux kernel Ver. 2.6.32.16 > >and Ver. 2.6.34.1. This patch cleanly applys > >to Ver. 2.6.34.1 > > Thanks. I've pushed this into xen.git as xen/memory-hotplug so people > can play with it more easily (but I haven't merged it into any of the > other branches yet). Thx. > >+#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG > >+static inline unsigned long current_target(void) > >+{ > >+ return balloon_stats.target_pages; > > Why does this need its own version? Because original version return values not bigger then initial memory allocation which does not allow memory hotplug to function. > >+int __ref xen_add_memory(int nid, u64 start, u64 size) > >+{ > >+ pg_data_t *pgdat = NULL; > >+ int new_pgdat = 0, ret; > >+ > >+ lock_system_sleep(); > >+ > >+ if (!node_online(nid)) { > >+ pgdat = hotadd_new_pgdat(nid, start); > >+ ret = -ENOMEM; > >+ if (!pgdat) > >+ goto out; > >+ new_pgdat = 1; > >+ } > >+ > >+ /* call arch's memory hotadd */ > >+ ret = arch_add_memory(nid, start, size); > >+ > >+ if (ret< 0) > >+ goto error; > >+ > >+ /* we online node here. we can't roll back from here. */ > >+ node_set_online(nid); > >+ > >+ if (new_pgdat) { > >+ ret = register_one_node(nid); > >+ /* > >+ * If sysfs file of new node can't create, cpu on the node > >+ * can't be hot-added. There is no rollback way now. > >+ * So, check by BUG_ON() to catch it reluctantly.. > >+ */ > >+ BUG_ON(ret); > >+ } > > This doesn't seem to be doing anything particularly xen-specific. In general it could be generic however I do not know it will be useful for others. If this function would be accepted by mm/memory_hotplug.c maintainers we could move it there. I removed from original add_memory funtion resource allocation (and deallocation after error), which must be done before XENMEM_populate_physmap in Xen. xen_add_memory is called after physmap is fully populated. If you have a questions please drop me a line. Daniel Signed-off-by: Daniel Kiper <dkiper@xxxxxxxxxxxx> --- arch/x86/Kconfig | 2 +- drivers/base/memory.c | 23 --- drivers/xen/Kconfig | 2 +- drivers/xen/balloon.c | 416 ++++++++++++++++++++++------------------ include/linux/memory_hotplug.h | 10 +- include/xen/balloon.h | 6 - mm/Kconfig | 9 - mm/memory_hotplug.c | 146 +-------------- 8 files changed, 240 insertions(+), 374 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 38434da..beb1aa7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1273,7 +1273,7 @@ config ARCH_SELECT_MEMORY_MODEL depends on ARCH_SPARSEMEM_ENABLE config ARCH_MEMORY_PROBE - def_bool y + def_bool X86_64 && !XEN depends on MEMORY_HOTPLUG config ILLEGAL_POINTER_VALUE diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 709457b..933442f 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -27,14 +27,6 @@ #include <asm/atomic.h> #include <asm/uaccess.h> -#ifdef CONFIG_XEN_MEMORY_HOTPLUG -#include <xen/xen.h> -#endif - -#if defined(CONFIG_XEN_MEMORY_HOTPLUG) && defined(CONFIG_XEN_BALLOON) -#include <xen/balloon.h> -#endif - #define MEMORY_CLASS_NAME "memory" static struct sysdev_class memory_sysdev_class = { @@ -223,10 +215,6 @@ memory_block_action(struct memory_block *mem, unsigned long action) case MEM_ONLINE: start_pfn = page_to_pfn(first_page); ret = online_pages(start_pfn, PAGES_PER_SECTION); -#if defined(CONFIG_XEN_MEMORY_HOTPLUG) && defined(CONFIG_XEN_BALLOON) - if (xen_domain() && !ret) - balloon_update_stats(PAGES_PER_SECTION); -#endif break; case MEM_OFFLINE: mem->state = MEM_GOING_OFFLINE; @@ -237,10 +225,6 @@ memory_block_action(struct memory_block *mem, unsigned long action) mem->state = old_state; break; } -#if defined(CONFIG_XEN_MEMORY_HOTPLUG) && defined(CONFIG_XEN_BALLOON) - if (xen_domain()) - balloon_update_stats(-PAGES_PER_SECTION); -#endif break; default: WARN(1, KERN_WARNING "%s(%p, %ld) unknown action: %ld\n", @@ -357,13 +341,6 @@ memory_probe_store(struct class *class, struct class_attribute *attr, phys_addr = simple_strtoull(buf, NULL, 0); -#ifdef CONFIG_XEN_MEMORY_HOTPLUG - if (xen_domain()) { - ret = xen_memory_probe(phys_addr); - return ret ? ret : count; - } -#endif - nid = memory_add_physaddr_to_nid(phys_addr); ret = add_memory(nid, phys_addr, PAGES_PER_SECTION << PAGE_SHIFT); diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 9713048..4f35eaf 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -11,8 +11,8 @@ config XEN_BALLOON config XEN_BALLOON_MEMORY_HOTPLUG bool "Xen memory balloon driver with memory hotplug support" - depends on EXPERIMENTAL && XEN_BALLOON && MEMORY_HOTPLUG default n + depends on XEN_BALLOON && MEMORY_HOTPLUG help Xen memory balloon driver with memory hotplug support allows expanding memory available for the system above limit declared at system startup. diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index f80bba0..31edc26 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -45,6 +45,8 @@ #include <linux/list.h> #include <linux/sysdev.h> #include <linux/gfp.h> +#include <linux/memory.h> +#include <linux/suspend.h> #include <asm/page.h> #include <asm/pgalloc.h> @@ -62,10 +64,6 @@ #include <xen/features.h> #include <xen/page.h> -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG -#include <linux/memory.h> -#endif - #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) #define BALLOON_CLASS_NAME "xen_memory" @@ -199,6 +197,196 @@ static inline unsigned long current_target(void) { return balloon_stats.target_pages; } + +static inline u64 is_memory_resource_reserved(void) +{ + return balloon_stats.hotplug_start_paddr; +} + +/* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */ +static int __ref xen_add_memory(int nid, u64 start, u64 size) +{ + pg_data_t *pgdat = NULL; + int new_pgdat = 0, ret; + + lock_system_sleep(); + + if (!node_online(nid)) { + pgdat = hotadd_new_pgdat(nid, start); + ret = -ENOMEM; + if (!pgdat) + goto out; + new_pgdat = 1; + } + + /* call arch's memory hotadd */ + ret = arch_add_memory(nid, start, size); + + if (ret < 0) + goto error; + + /* we online node here. we can't roll back from here. */ + node_set_online(nid); + + if (new_pgdat) { + ret = register_one_node(nid); + /* + * If sysfs file of new node can't create, cpu on the node + * can't be hot-added. There is no rollback way now. + * So, check by BUG_ON() to catch it reluctantly.. + */ + BUG_ON(ret); + } + + goto out; + +error: + /* rollback pgdat allocation */ + if (new_pgdat) + rollback_node_hotadd(nid, pgdat); + +out: + unlock_system_sleep(); + return ret; +} + +static int allocate_additional_memory(unsigned long nr_pages) +{ + long rc; + resource_size_t r_min, r_size; + struct resource *r; + struct xen_memory_reservation reservation = { + .address_bits = 0, + .extent_order = 0, + .domid = DOMID_SELF + }; + unsigned long flags, i, pfn; + + if (nr_pages > ARRAY_SIZE(frame_list)) + nr_pages = ARRAY_SIZE(frame_list); + + spin_lock_irqsave(&balloon_lock, flags); + + if (!is_memory_resource_reserved()) { + + /* + * Look for first unused memory region starting at page + * boundary. Skip last memory section created at boot time + * becuase it may contains unused memory pages with PG_reserved + * bit not set (online_pages require PG_reserved bit set). + */ + + r = kzalloc(sizeof(struct resource), GFP_KERNEL); + + if (!r) { + rc = -ENOMEM; + goto out; + } + + r->name = "System RAM"; + r->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + r_min = PFN_PHYS(section_nr_to_pfn(pfn_to_section_nr(balloon_stats.boot_max_pfn) + 1)); + r_size = (balloon_stats.target_pages - balloon_stats.current_pages) << PAGE_SHIFT; + + rc = allocate_resource(&iomem_resource, r, r_size, r_min, + ULONG_MAX, PAGE_SIZE, NULL, NULL); + + if (rc < 0) { + kfree(r); + goto out; + } + + balloon_stats.hotplug_start_paddr = r->start; + } + + pfn = PFN_DOWN(balloon_stats.hotplug_start_paddr + balloon_stats.hotplug_size); + + for (i = 0; i < nr_pages; ++i, ++pfn) + frame_list[i] = pfn; + + set_xen_guest_handle(reservation.extent_start, frame_list); + reservation.nr_extents = nr_pages; + + rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); + + if (rc < 0) + goto out; + + pfn = PFN_DOWN(balloon_stats.hotplug_start_paddr + balloon_stats.hotplug_size); + + for (i = 0; i < rc; ++i, ++pfn) { + BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) && + phys_to_machine_mapping_valid(pfn)); + set_phys_to_machine(pfn, frame_list[i]); + } + + balloon_stats.hotplug_size += rc << PAGE_SHIFT; + balloon_stats.current_pages += rc; + +out: + spin_unlock_irqrestore(&balloon_lock, flags); + + return rc < 0 ? rc : rc != nr_pages; +} + +static void hotplug_allocated_memory(void) +{ + int nid, ret; + struct memory_block *mem; + unsigned long pfn, pfn_limit; + + nid = memory_add_physaddr_to_nid(balloon_stats.hotplug_start_paddr); + + ret = xen_add_memory(nid, balloon_stats.hotplug_start_paddr, + balloon_stats.hotplug_size); + + if (ret) { + pr_err("%s: xen_add_memory: Memory hotplug failed: %i\n", + __func__, ret); + goto error; + } + + if (xen_pv_domain()) { + pfn = PFN_DOWN(balloon_stats.hotplug_start_paddr); + pfn_limit = pfn + (balloon_stats.hotplug_size >> PAGE_SHIFT); + + for (; pfn < pfn_limit; ++pfn) + if (!PageHighMem(pfn_to_page(pfn))) + BUG_ON(HYPERVISOR_update_va_mapping( + (unsigned long)__va(pfn << PAGE_SHIFT), + mfn_pte(pfn_to_mfn(pfn), PAGE_KERNEL), 0)); + } + + ret = online_pages(PFN_DOWN(balloon_stats.hotplug_start_paddr), + balloon_stats.hotplug_size >> PAGE_SHIFT); + + if (ret) { + pr_err("%s: online_pages: Failed: %i\n", __func__, ret); + goto error; + } + + pfn = PFN_DOWN(balloon_stats.hotplug_start_paddr); + pfn_limit = pfn + (balloon_stats.hotplug_size >> PAGE_SHIFT); + + for (; pfn < pfn_limit; pfn += PAGES_PER_SECTION) { + mem = find_memory_block(__pfn_to_section(pfn)); + BUG_ON(!mem); + BUG_ON(!present_section_nr(mem->phys_index)); + mutex_lock(&mem->state_mutex); + mem->state = MEM_ONLINE; + mutex_unlock(&mem->state_mutex); + } + + goto out; + +error: + balloon_stats.current_pages -= balloon_stats.hotplug_size >> PAGE_SHIFT; + balloon_stats.target_pages -= balloon_stats.hotplug_size >> PAGE_SHIFT; + +out: + balloon_stats.hotplug_start_paddr = 0; + balloon_stats.hotplug_size = 0; +} #else static unsigned long current_target(void) { @@ -211,12 +399,26 @@ static unsigned long current_target(void) return target; } + +static inline u64 is_memory_resource_reserved(void) +{ + return 0; +} + +static inline int allocate_additional_memory(unsigned long nr_pages) +{ + return 0; +} + +static inline void hotplug_allocated_memory(void) +{ +} #endif static int increase_reservation(unsigned long nr_pages) { - unsigned long uninitialized_var(pfn), i, flags; - struct page *uninitialized_var(page); + unsigned long pfn, i, flags; + struct page *page; long rc; struct xen_memory_reservation reservation = { .address_bits = 0, @@ -224,63 +426,11 @@ static int increase_reservation(unsigned long nr_pages) .domid = DOMID_SELF }; -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG - resource_size_t r_min, r_size; - struct resource *r; -#endif - if (nr_pages > ARRAY_SIZE(frame_list)) nr_pages = ARRAY_SIZE(frame_list); spin_lock_irqsave(&balloon_lock, flags); -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG - if (!balloon_stats.balloon_low && !balloon_stats.balloon_high) { - if (!balloon_stats.hotplug_start_paddr) { - - /* - * Look for first unused memory region starting - * at page boundary. Skip last memory section created - * at boot time becuase it may contains unused memory - * pages with PG_reserved bit not set (online_pages - * require PG_reserved bit set). - */ - - r = kzalloc(sizeof(struct resource), GFP_KERNEL); - - if (!r) { - rc = -ENOMEM; - goto out; - } - - r->name = "System RAM"; - r->flags = IORESOURCE_MEM | IORESOURCE_BUSY; - r_min = PFN_PHYS(section_nr_to_pfn(pfn_to_section_nr(balloon_stats.boot_max_pfn) + 1)); - r_size = (balloon_stats.target_pages - balloon_stats.current_pages) << PAGE_SHIFT; - - rc = allocate_resource(&iomem_resource, r, - r_size, r_min, ULONG_MAX, - PAGE_SIZE, NULL, NULL); - - if (rc < 0) { - kfree(r); - goto out; - } - - balloon_stats.hotplug_start_paddr = r->start; - } - - pfn = PFN_DOWN(balloon_stats.hotplug_start_paddr + - balloon_stats.hotplug_size); - - for (i = 0; i < nr_pages; ++i, ++pfn) - frame_list[i] = pfn; - - pfn -= nr_pages + 1; - goto populate_physmap; - } -#endif - page = balloon_first_page(); for (i = 0; i < nr_pages; i++) { BUG_ON(page == NULL); @@ -288,9 +438,6 @@ static int increase_reservation(unsigned long nr_pages) page = balloon_next_page(page); } -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG -populate_physmap: -#endif set_xen_guest_handle(reservation.extent_start, frame_list); reservation.nr_extents = nr_pages; rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); @@ -298,33 +445,17 @@ populate_physmap: goto out; for (i = 0; i < rc; i++) { -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG - if (balloon_stats.hotplug_start_paddr) { - ++pfn; - goto set_p2m; - } -#endif - page = balloon_retrieve(); BUG_ON(page == NULL); pfn = page_to_pfn(page); - -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG -set_p2m: -#endif BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) && phys_to_machine_mapping_valid(pfn)); set_phys_to_machine(pfn, frame_list[i]); -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG - if (balloon_stats.hotplug_start_paddr) - continue; -#endif - /* Link back into the page tables if not highmem. */ - if (!PageHighMem(page)) { + if (xen_pv_domain() && !PageHighMem(page)) { int ret; ret = HYPERVISOR_update_va_mapping( (unsigned long)__va(pfn << PAGE_SHIFT), @@ -339,11 +470,6 @@ set_p2m: __free_page(page); } -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG - if (balloon_stats.hotplug_start_paddr) - balloon_stats.hotplug_size += rc << PAGE_SHIFT; -#endif - balloon_stats.current_pages += rc; out: @@ -379,7 +505,7 @@ static int decrease_reservation(unsigned long nr_pages) scrub_page(page); - if (!PageHighMem(page)) { + if (xen_pv_domain() && !PageHighMem(page)) { ret = HYPERVISOR_update_va_mapping( (unsigned long)__va(pfn << PAGE_SHIFT), __pte_ma(0), 0); @@ -424,18 +550,18 @@ static void balloon_process(struct work_struct *work) int need_sleep = 0; long credit; -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG - int nid, ret; - struct memory_block *mem; - unsigned long pfn, pfn_limit; -#endif - mutex_lock(&balloon_mutex); do { credit = current_target() - balloon_stats.current_pages; - if (credit > 0) - need_sleep = (increase_reservation(credit) != 0); + + if (credit > 0) { + if (balloon_stats.balloon_low || balloon_stats.balloon_high) + need_sleep = (increase_reservation(credit) != 0); + else + need_sleep = (allocate_additional_memory(credit) != 0); + } + if (credit < 0) need_sleep = (decrease_reservation(-credit) != 0); @@ -448,93 +574,12 @@ static void balloon_process(struct work_struct *work) /* Schedule more work if there is some still to be done. */ if (current_target() != balloon_stats.current_pages) mod_timer(&balloon_timer, jiffies + HZ); -#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG - else if (balloon_stats.hotplug_start_paddr) { - nid = memory_add_physaddr_to_nid(balloon_stats.hotplug_start_paddr); - - ret = xen_add_memory(nid, balloon_stats.hotplug_start_paddr, - balloon_stats.hotplug_size); - - if (ret) { - printk(KERN_ERR "%s: xen_add_memory: " - "Memory hotplug failed: %i\n", - __func__, ret); - goto error; - } - - pfn = PFN_DOWN(balloon_stats.hotplug_start_paddr); - pfn_limit = pfn + (balloon_stats.hotplug_size >> PAGE_SHIFT); - - for (; pfn < pfn_limit; ++pfn) - if (!PageHighMem(pfn_to_page(pfn))) - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)__va(pfn << PAGE_SHIFT), - mfn_pte(pfn_to_mfn(pfn), PAGE_KERNEL), 0)); - - ret = online_pages(PFN_DOWN(balloon_stats.hotplug_start_paddr), - balloon_stats.hotplug_size >> PAGE_SHIFT); - - if (ret) { - printk(KERN_ERR "%s: online_pages: Failed: %i\n", - __func__, ret); - goto error; - } - - pfn = PFN_DOWN(balloon_stats.hotplug_start_paddr); - pfn_limit = pfn + (balloon_stats.hotplug_size >> PAGE_SHIFT); - - for (; pfn < pfn_limit; pfn += PAGES_PER_SECTION) { - mem = find_memory_block(__pfn_to_section(pfn)); - BUG_ON(!mem); - BUG_ON(!present_section_nr(mem->phys_index)); - mutex_lock(&mem->state_mutex); - mem->state = MEM_ONLINE; - mutex_unlock(&mem->state_mutex); - } - - goto out; - -error: - balloon_stats.current_pages -= balloon_stats.hotplug_size >> PAGE_SHIFT; - balloon_stats.target_pages -= balloon_stats.hotplug_size >> PAGE_SHIFT; - -out: - balloon_stats.hotplug_start_paddr = 0; - balloon_stats.hotplug_size = 0; - } -#endif + else if (is_memory_resource_reserved()) + hotplug_allocated_memory(); mutex_unlock(&balloon_mutex); } -#ifdef CONFIG_XEN_MEMORY_HOTPLUG - -/* Resets the Xen limit, sets new target, and kicks off processing. */ -static void balloon_set_new_target(unsigned long target) -{ - mutex_lock(&balloon_mutex); - balloon_stats.target_pages = target; - mutex_unlock(&balloon_mutex); - - schedule_work(&balloon_worker); -} - -void balloon_update_stats(long nr_pages) -{ - mutex_lock(&balloon_mutex); - - balloon_stats.current_pages += nr_pages; - balloon_stats.target_pages += nr_pages; - - xenbus_printf(XBT_NIL, "memory", "target", "%llu", - (unsigned long long)balloon_stats.target_pages << (PAGE_SHIFT - 10)); - - mutex_unlock(&balloon_mutex); -} -EXPORT_SYMBOL_GPL(balloon_update_stats); - -#else - /* Resets the Xen limit, sets new target, and kicks off processing. */ static void balloon_set_new_target(unsigned long target) { @@ -543,8 +588,6 @@ static void balloon_set_new_target(unsigned long target) schedule_work(&balloon_worker); } -#endif - static struct xenbus_watch target_watch = { .node = "memory/target" @@ -589,12 +632,16 @@ static int __init balloon_init(void) unsigned long pfn; struct page *page; - if (!xen_pv_domain()) + if (!xen_domain()) return -ENODEV; pr_info("xen_balloon: Initialising balloon driver.\n"); - balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn); + if (xen_pv_domain()) + balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn); + else + balloon_stats.current_pages = max_pfn; + balloon_stats.target_pages = balloon_stats.current_pages; balloon_stats.balloon_low = 0; balloon_stats.balloon_high = 0; @@ -613,11 +660,12 @@ static int __init balloon_init(void) register_balloon(&balloon_sysdev); /* Initialise the balloon with excess memory space. */ - for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { - page = pfn_to_page(pfn); - if (!PageReserved(page)) - balloon_append(page); - } + if (xen_pv_domain()) + for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { + page = pfn_to_page(pfn); + if (!PageReserved(page)) + balloon_append(page); + } target_watch.callback = watch_target; xenstore_notifier.notifier_call = balloon_init_watcher; diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 04e67b8..6652eae 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -202,6 +202,8 @@ static inline int is_mem_section_removable(unsigned long pfn, } #endif /* CONFIG_MEMORY_HOTREMOVE */ +extern pg_data_t *hotadd_new_pgdat(int nid, u64 start); +extern void rollback_node_hotadd(int nid, pg_data_t *pgdat); extern int add_memory(int nid, u64 start, u64 size); extern int arch_add_memory(int nid, u64 start, u64 size); extern int remove_memory(u64 start, u64 size); @@ -211,12 +213,4 @@ extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms) extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum); -#if defined(CONFIG_XEN_MEMORY_HOTPLUG) || defined(CONFIG_XEN_BALLOON_MEMORY_HOTPLUG) -extern int xen_add_memory(int nid, u64 start, u64 size); -#endif - -#ifdef CONFIG_XEN_MEMORY_HOTPLUG -extern int xen_memory_probe(u64 phys_addr); -#endif - #endif /* __LINUX_MEMORY_HOTPLUG_H */ diff --git a/include/xen/balloon.h b/include/xen/balloon.h deleted file mode 100644 index 84b17b7..0000000 --- a/include/xen/balloon.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _XEN_BALLOON_H -#define _XEN_BALLOON_H - -extern void balloon_update_stats(long nr_pages); - -#endif /* _XEN_BALLOON_H */ diff --git a/mm/Kconfig b/mm/Kconfig index b04f3a8..9c61158 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -144,15 +144,6 @@ config MEMORY_HOTREMOVE depends on MEMORY_HOTPLUG && ARCH_ENABLE_MEMORY_HOTREMOVE depends on MIGRATION -config XEN_MEMORY_HOTPLUG - bool "Allow for memory hot-add in Xen guests" - depends on EXPERIMENTAL && ARCH_MEMORY_PROBE && XEN - default n - help - Memory hotplug allows expanding memory available for the system - above limit declared at system startup. It is very useful on critical - systems which require long run without rebooting. - # # If we have space for more page flags then we can enable additional # optimizations and functionality. diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 1c73703..143e03c 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -32,14 +32,6 @@ #include <asm/tlbflush.h> -#ifdef CONFIG_XEN_MEMORY_HOTPLUG -#include <asm/xen/hypercall.h> -#include <xen/interface/xen.h> -#include <xen/interface/memory.h> -#include <xen/features.h> -#include <xen/page.h> -#endif - #include "internal.h" /* add this memory to iomem resource */ @@ -461,7 +453,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */ -static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start) +pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start) { struct pglist_data *pgdat; unsigned long zones_size[MAX_NR_ZONES] = {0}; @@ -481,13 +473,15 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start) return pgdat; } +EXPORT_SYMBOL_GPL(hotadd_new_pgdat); -static void rollback_node_hotadd(int nid, pg_data_t *pgdat) +void rollback_node_hotadd(int nid, pg_data_t *pgdat) { arch_refresh_nodedata(nid, NULL); arch_free_nodedata(pgdat); return; } +EXPORT_SYMBOL_GPL(rollback_node_hotadd); /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */ @@ -550,138 +544,6 @@ out: } EXPORT_SYMBOL_GPL(add_memory); -#if defined(CONFIG_XEN_MEMORY_HOTPLUG) || defined(CONFIG_XEN_BALLOON_MEMORY_HOTPLUG) -/* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */ -int __ref xen_add_memory(int nid, u64 start, u64 size) -{ - pg_data_t *pgdat = NULL; - int new_pgdat = 0, ret; - - lock_system_sleep(); - - if (!node_online(nid)) { - pgdat = hotadd_new_pgdat(nid, start); - ret = -ENOMEM; - if (!pgdat) - goto out; - new_pgdat = 1; - } - - /* call arch's memory hotadd */ - ret = arch_add_memory(nid, start, size); - - if (ret < 0) - goto error; - - /* we online node here. we can't roll back from here. */ - node_set_online(nid); - - if (new_pgdat) { - ret = register_one_node(nid); - /* - * If sysfs file of new node can't create, cpu on the node - * can't be hot-added. There is no rollback way now. - * So, check by BUG_ON() to catch it reluctantly.. - */ - BUG_ON(ret); - } - - goto out; - -error: - /* rollback pgdat allocation */ - if (new_pgdat) - rollback_node_hotadd(nid, pgdat); - -out: - unlock_system_sleep(); - return ret; -} -EXPORT_SYMBOL_GPL(xen_add_memory); -#endif - -#ifdef CONFIG_XEN_MEMORY_HOTPLUG -int xen_memory_probe(u64 phys_addr) -{ - int nr_pages, ret; - struct resource *r; - struct xen_memory_reservation reservation = { - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF, - .nr_extents = PAGES_PER_SECTION - }; - unsigned long *frame_list, i, pfn; - - r = register_memory_resource(phys_addr, PAGES_PER_SECTION << PAGE_SHIFT); - - if (!r) - return -EEXIST; - - frame_list = vmalloc(PAGES_PER_SECTION * sizeof(unsigned long)); - - if (!frame_list) { - printk(KERN_ERR "%s: vmalloc: Out of memory\n", __func__); - ret = -ENOMEM; - goto error; - } - - set_xen_guest_handle(reservation.extent_start, frame_list); - for (i = 0, pfn = PFN_DOWN(phys_addr); i < PAGES_PER_SECTION; ++i, ++pfn) - frame_list[i] = pfn; - - ret = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); - - if (ret < PAGES_PER_SECTION) { - if (ret > 0) { - printk(KERN_ERR "%s: PHYSMAP is not fully " - "populated: %i/%lu\n", __func__, - ret, PAGES_PER_SECTION); - reservation.nr_extents = nr_pages = ret; - ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); - BUG_ON(ret != nr_pages); - ret = -ENOMEM; - } else { - ret = (ret < 0) ? ret : -ENOMEM; - printk(KERN_ERR "%s: Can't populate PHYSMAP: %i\n", __func__, ret); - } - goto error; - } - - for (i = 0, pfn = PFN_DOWN(phys_addr); i < PAGES_PER_SECTION; ++i, ++pfn) { - BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) && - phys_to_machine_mapping_valid(pfn)); - set_phys_to_machine(pfn, frame_list[i]); - } - - ret = xen_add_memory(memory_add_physaddr_to_nid(phys_addr), phys_addr, - PAGES_PER_SECTION << PAGE_SHIFT); - - if (ret) { - printk(KERN_ERR "%s: xen_add_memory: Memory hotplug " - "failed: %i\n", __func__, ret); - goto out; - } - - for (i = 0, pfn = PFN_DOWN(phys_addr); i < PAGES_PER_SECTION; ++i, ++pfn) - if (!PageHighMem(pfn_to_page(pfn))) - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)__va(pfn << PAGE_SHIFT), - mfn_pte(frame_list[i], PAGE_KERNEL), 0)); - - goto out; - -error: - release_memory_resource(r); - -out: - vfree(frame_list); - - return (ret < 0) ? ret : 0; -} -EXPORT_SYMBOL_GPL(xen_memory_probe); -#endif - #ifdef CONFIG_MEMORY_HOTREMOVE /* * A free page on the buddy free lists (not the per-cpu lists) has PageBuddy -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxxx For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>