Re: bugreport kernel panic on early stage, with HIGHMEM4G:
From: Ingo Molnar
Date: Tue Jan 15 2008 - 06:40:30 EST
* Denys Fedoryshchenko <denys@xxxxxxxxxxx> wrote:
> Hi
>
> After physical memory upgrade from 3GB to 4GB (also it happens on 5GB)
> got kernel panic.
>
> Because it is happening on early stage and my machine doesn't contain
> serial port, i had to take photo. Kernel boots fine with 64GB highmem,
> no highmem, or highmem4G with limited memory by mem=3G. All dmesg
> attached. Also i attach dmidecode and lspci -vvv output, probably it
> will be useful.
thanks for the detailed report, i think i know what's going on. Could
you try the patch below, does it fix your problem?
this seems to be a SPARSEMEM bug which is present in v2.6.23 as well and
has probably been present ever since SPARSEMEM was added to 32-bit x86.
There's a ~256MB hole in your e820 memory map (the pci aperture), which
causes the last 4 sparsemem sections (each covering 64MB of RAM) to be
not present - and they are thus missing from the sparsemem mem_map[]
too. The highmem init code on the other hand assumes that all pages are
in the mem_map[]:
static void __init set_highmem_pages_init(int bad_ppro)
{
int pfn;
for (pfn = highstart_pfn; pfn < highend_pfn; pfn++)
add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro);
the pfn_to_page() is unconditional and dereferences to a NULL-ish
pointer which crashes your box. highend_pfn is what got miscalculated by
256 MB, so set_highmem_pages_init() tried to reference a non-existing
struct page - but it should still be robust enough against non-existent
pages.
The patch below fixes this bug. Please also send a dmesg if you manage
to boot the box up fine, i've added a few debug printouts to confirm
this theory. (i'll figure out whether we need to clip highend_pfn as
well - but this patch alone should be good enough to fix the crash on
your box.)
Ingo
------------->
Subject: x86: fix CONFIG_SPARSEMEM highmem init bug
From: Ingo Molnar <mingo@xxxxxxx>
fix CONFIG_SPARSEMEM highmem init bug.
Signed-off-by: Ingo Molnar <mingo@xxxxxxx>
---
arch/x86/mm/init_32.c | 43 ++++++++++++++++++++++++++++++++++++++++---
mm/sparse.c | 8 +++++++-
2 files changed, 47 insertions(+), 4 deletions(-)
Index: linux/arch/x86/mm/init_32.c
===================================================================
--- linux.orig/arch/x86/mm/init_32.c
+++ linux/arch/x86/mm/init_32.c
@@ -321,11 +321,48 @@ extern void set_highmem_pages_init(int);
static void __init set_highmem_pages_init(int bad_ppro)
{
int pfn;
- for (pfn = highstart_pfn; pfn < highend_pfn; pfn++)
- add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro);
+
+ printk("set_highmem_pages_init(bad_ppro:%d)\n", bad_ppro);
+ printk("sizeof(struct page): %d\n", sizeof(struct page));
+ printk("sizeof(struct mem_section): %d\n", sizeof(struct mem_section));
+ printk("PFN_SECTION_SHIFT: %d\n", PFN_SECTION_SHIFT);
+
+ printk("mem_map: %p\n", mem_map);
+ printk(" highstart_pfn: %9ld [page: %p]\n",
+ highstart_pfn, pfn_to_page(highstart_pfn));
+ printk(" highend_pfn: %9ld [page: %p]\n",
+ highend_pfn, pfn_to_page(highend_pfn));
+ printk(" highend_pfn-1: %9ld [page: %p]\n",
+ highend_pfn-1, pfn_to_page(highend_pfn-1));
+
+ printk("NR_MEM_SECTIONS: %ld\n", NR_MEM_SECTIONS);
+ printk("pfn_to_section_nr(highstart_pfn): %9ld\n",
+ pfn_to_section_nr(highstart_pfn));
+ printk("pfn_to_section_nr(highend_pfn): %9ld\n",
+ pfn_to_section_nr(highend_pfn));
+ printk("pfn_to_section_nr(highend_pfn-1): %9ld\n",
+ pfn_to_section_nr(highend_pfn-1));
+
+ printk("totalhigh_pages: %9ld\n", totalhigh_pages);
+ printk(" totalram_pages: %9ld\n", totalram_pages);
+
+ for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) {
+ if (pfn_valid(pfn))
+ add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro);
+ else {
+ if (WARN_ON_ONCE(1)) {
+ printk("bad pfn: %d\n", pfn);
+ break;
+ }
+ }
+ }
+ printk("totalhigh_pages: %9ld\n", totalhigh_pages);
+ printk(" totalram_pages: %9ld\n", totalram_pages);
+
+
totalram_pages += totalhigh_pages;
}
-#endif /* CONFIG_FLATMEM */
+#endif /* CONFIG_NUMA */
#else
#define kmap_init() do { } while (0)
Index: linux/mm/sparse.c
===================================================================
--- linux.orig/mm/sparse.c
+++ linux/mm/sparse.c
@@ -295,9 +295,13 @@ void __init sparse_init(void)
struct page *map;
unsigned long *usemap;
+ printk("sparse_init()\n");
for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
- if (!present_section_nr(pnum))
+ printk("section %2ld: ", pnum);
+ if (!present_section_nr(pnum)) {
+ printk("!present\n");
continue;
+ }
map = sparse_early_mem_map_alloc(pnum);
if (!map)
@@ -309,6 +313,8 @@ void __init sparse_init(void)
sparse_init_one_section(__nr_to_section(pnum), pnum, map,
usemap);
+ printk("map: %p, usemap: %p [content: %08lx]\n",
+ map, usemap, __nr_to_section(pnum)->section_mem_map);
}
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/