From: jbeulich@novell.com
Subject: fix issues with the assignment of huge amounts of memory
Patch-mainline: obsolete
References: bnc#482614

At the same time remove the non-applicable and broken support for the
memmap= command line option.

--- head-2009-08-17.orig/arch/x86/kernel/e820-xen.c	2009-08-17 14:26:01.000000000 +0200
+++ head-2009-08-17/arch/x86/kernel/e820-xen.c	2009-08-17 15:01:51.000000000 +0200
@@ -1354,6 +1354,26 @@ static int __init parse_memopt(char *p)
 
 	i = e820.nr_map - 1;
 	current_end = e820.map[i].addr + e820.map[i].size;
+
+	/*
+	 * 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;
+	}
+
 	if (current_end < mem_size) {
 		/*
 		 * The e820 map ends before our requested size so
@@ -1413,6 +1433,7 @@ static int __init parse_memmap_opt(char 
 	return *p == '\0' ? 0 : -EINVAL;
 }
 early_param("memmap", parse_memmap_opt);
+#endif
 
 void __init finish_e820_parsing(void)
 {
@@ -1427,7 +1448,6 @@ void __init finish_e820_parsing(void)
 		e820_print_map("user");
 	}
 }
-#endif
 
 static inline const char *e820_type_to_string(int e820_type)
 {
@@ -1455,7 +1475,7 @@ void __init e820_reserve_resources(void)
 	struct resource *res;
 	u64 end;
 
-	res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map);
+	res = alloc_bootmem(sizeof(struct resource) * e820.nr_map);
 	e820_res = res;
 	for (i = 0; i < e820.nr_map; i++) {
 		end = e820.map[i].addr + e820.map[i].size - 1;
--- head-2009-08-17.orig/arch/x86/kernel/setup-xen.c	2009-08-17 15:01:40.000000000 +0200
+++ head-2009-08-17/arch/x86/kernel/setup-xen.c	2009-08-17 15:01:51.000000000 +0200
@@ -126,12 +126,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;
@@ -1140,17 +1135,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 *
@@ -1160,15 +1155,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-2009-08-17.orig/drivers/xen/core/machine_kexec.c	2009-08-17 14:25:33.000000000 +0200
+++ head-2009-08-17/drivers/xen/core/machine_kexec.c	2009-08-17 15:01:51.000000000 +0200
@@ -57,7 +57,7 @@ void __init xen_machine_kexec_setup_reso
 
 	/* allocate xen_phys_cpus */
 
-	xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource));
+	xen_phys_cpus = alloc_bootmem(k * sizeof(struct resource));
 	BUG_ON(xen_phys_cpus == NULL);
 
 	/* fill in xen_phys_cpus with per-cpu crash note information */
--- head-2009-08-17.orig/drivers/xen/core/machine_reboot.c	2009-08-17 15:01:15.000000000 +0200
+++ head-2009-08-17/drivers/xen/core/machine_reboot.c	2009-08-17 15:01:51.000000000 +0200
@@ -79,7 +79,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 =
