From: jbeulich@novell.com Subject: fix issues with the assignment of huge amounts of memory Patch-mainline: obsolete References: bnc#482614, bnc#537435 --- head-2010-04-15.orig/arch/x86/kernel/e820-xen.c 2010-04-15 10:48:32.000000000 +0200 +++ head-2010-04-15/arch/x86/kernel/e820-xen.c 2010-04-15 11:48:01.000000000 +0200 @@ -1093,6 +1093,26 @@ static int __init parse_memopt(char *p) userdef = 1; mem_size = memparse(p, &p); +#ifdef CONFIG_XEN + /* + * A little less than 2% of available memory are needed for page + * tables, p2m map, and mem_map. Hence the maximum amount of memory + * we can potentially balloon up to can in no case exceed about 50 + * times of what we've been given initially. Since even with that we + * won't be able to boot (due to various calculations done based on + * the total number of pages) we further restrict this to factor 32. + */ + if ((mem_size >> (PAGE_SHIFT + 5)) > xen_start_info->nr_pages) { + u64 size = (u64)xen_start_info->nr_pages << 5; + + printk(KERN_WARNING "mem=%Luk is invalid for an initial" + " allocation of %luk, using %Luk\n", + (unsigned long long)mem_size >> 10, + xen_start_info->nr_pages << (PAGE_SHIFT - 10), + (unsigned long long)size << (PAGE_SHIFT - 10)); + mem_size = size << PAGE_SHIFT; + } +#endif e820_remove_range(mem_size, ULLONG_MAX - mem_size, E820_RAM, 1); i = e820.nr_map - 1; @@ -1291,6 +1311,7 @@ void __init e820_reserve_resources_late( char *__init default_machine_specific_memory_setup(void) { int rc, nr_map; + unsigned long long maxmem; struct xen_memory_map memmap; static struct e820entry __initdata map[E820MAX]; @@ -1316,6 +1337,22 @@ char *__init default_machine_specific_me BUG(); #ifdef CONFIG_XEN + /* See the comment in parse_memopt(). */ + for (maxmem = rc = 0; rc < e820.nr_map; ++rc) + if (e820.map[rc].type == E820_RAM) + maxmem += e820.map[rc].size; + if ((maxmem >> (PAGE_SHIFT + 5)) > xen_start_info->nr_pages) { + unsigned long long size = (u64)xen_start_info->nr_pages << 5; + + printk(KERN_WARNING "maxmem of %LuM is invalid for an initial" + " allocation of %luM, using %LuM\n", + maxmem >> 20, + xen_start_info->nr_pages >> (20 - PAGE_SHIFT), + size >> (20 - PAGE_SHIFT)); + size <<= PAGE_SHIFT; + e820_remove_range(size, ULLONG_MAX - size, E820_RAM, 1); + } + if (is_initial_xendomain()) { memmap.nr_entries = E820MAX; set_xen_guest_handle(memmap.buffer, machine_e820.map); --- head-2010-04-15.orig/arch/x86/kernel/setup-xen.c 2010-04-15 11:46:02.000000000 +0200 +++ head-2010-04-15/arch/x86/kernel/setup-xen.c 2010-04-15 11:48:03.000000000 +0200 @@ -130,12 +130,7 @@ static struct notifier_block xen_panic_b unsigned long *phys_to_machine_mapping; EXPORT_SYMBOL(phys_to_machine_mapping); -unsigned long *pfn_to_mfn_frame_list_list, -#ifdef CONFIG_X86_64 - *pfn_to_mfn_frame_list[512]; -#else - *pfn_to_mfn_frame_list[128]; -#endif +unsigned long *pfn_to_mfn_frame_list_list, **pfn_to_mfn_frame_list; /* Raw start-of-day parameters from the hypervisor. */ start_info_t *xen_start_info; @@ -1167,17 +1162,17 @@ void __init setup_arch(char **cmdline_p) p2m_pages = xen_start_info->nr_pages; if (!xen_feature(XENFEAT_auto_translated_physmap)) { - unsigned long i, j; + unsigned long i, j, size; unsigned int k, fpp; /* Make sure we have a large enough P->M table. */ phys_to_machine_mapping = alloc_bootmem_pages( max_pfn * sizeof(unsigned long)); - memset(phys_to_machine_mapping, ~0, - max_pfn * sizeof(unsigned long)); memcpy(phys_to_machine_mapping, (unsigned long *)xen_start_info->mfn_list, p2m_pages * sizeof(unsigned long)); + memset(phys_to_machine_mapping + p2m_pages, ~0, + (max_pfn - p2m_pages) * sizeof(unsigned long)); free_bootmem( __pa(xen_start_info->mfn_list), PFN_PHYS(PFN_UP(xen_start_info->nr_pages * @@ -1187,15 +1182,26 @@ void __init setup_arch(char **cmdline_p) * Initialise the list of the frames that specify the list of * frames that make up the p2m table. Used by save/restore. */ - pfn_to_mfn_frame_list_list = alloc_bootmem_pages(PAGE_SIZE); - fpp = PAGE_SIZE/sizeof(unsigned long); + size = (max_pfn + fpp - 1) / fpp; + size = (size + fpp - 1) / fpp; + ++size; /* include a zero terminator for crash tools */ + size *= sizeof(unsigned long); + pfn_to_mfn_frame_list_list = alloc_bootmem_pages(size); + if (size > PAGE_SIZE + && xen_create_contiguous_region((unsigned long) + pfn_to_mfn_frame_list_list, + get_order(size), 0)) + BUG(); + size -= sizeof(unsigned long); + pfn_to_mfn_frame_list = alloc_bootmem(size); + for (i = j = 0, k = -1; i < max_pfn; i += fpp, j++) { if (j == fpp) j = 0; if (j == 0) { k++; - BUG_ON(k>=ARRAY_SIZE(pfn_to_mfn_frame_list)); + BUG_ON(k * sizeof(unsigned long) >= size); pfn_to_mfn_frame_list[k] = alloc_bootmem_pages(PAGE_SIZE); pfn_to_mfn_frame_list_list[k] = --- head-2010-04-15.orig/drivers/xen/core/machine_reboot.c 2010-03-25 14:39:15.000000000 +0100 +++ head-2010-04-15/drivers/xen/core/machine_reboot.c 2010-03-25 14:41:06.000000000 +0100 @@ -80,7 +80,7 @@ static void post_suspend(int suspend_can unsigned long shinfo_mfn; extern unsigned long max_pfn; extern unsigned long *pfn_to_mfn_frame_list_list; - extern unsigned long *pfn_to_mfn_frame_list[]; + extern unsigned long **pfn_to_mfn_frame_list; if (suspend_cancelled) { xen_start_info->store_mfn =