diff options
author | Ingo Molnar <mingo@elte.hu> | 2007-10-17 12:04:34 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@inhelltoy.tec.linutronix.de> | 2007-10-17 14:15:39 -0400 |
commit | 509a80c49c512ac88bd67b981145f925a306111b (patch) | |
tree | df922dea1aea98bc513845da55ec12a1a82bfbe0 /arch/x86/mm/init_32.c | |
parent | 1e3e19723ecd58149388f3eecbd3285825f64f3b (diff) |
x86: fix CONFIG_PAGEALLOC related boot hangs/OOMs
if CONFIG_PAGEALLOC is enabled then X86_FEATURE_PSE is disabled and all
the kernel physical RAM pagetables are set up as 4K pages. This is
needed so that CONFIG_PAGEALLOC can do finegrained mapping and unmapping
of pages.
as a side-effect though, the total size of memory allocated as kernel
pagetables increases significantly. All these pagetables are allocated
via alloc_bootmem_low_pages(), straight out of the lowmem DMA pool. If
the system has enough RAM and a large kernel image then almost all of
the 16 MB lowmem DMA pool is allocated to the image and to pagetables -
leaving no space for __GFP_DMA allocations.
this results in drivers failing and the bootup hanging:
swapper invoked oom-killer: gfp_mask=0x80d1, order=0, oomkilladj=0
[<4015059f>] out_of_memory+0x17f/0x1c0
[<40151f3c>] __alloc_pages+0x37c/0x3a0
[<40168cd7>] slob_new_page+0x37/0x50
[<40168dff>] slob_alloc+0x10f/0x190
[<40169010>] __kmalloc_node+0x80/0x90
[<405a17e3>] scsi_host_alloc+0x33/0x2c0
[<405a1a82>] scsi_register+0x12/0x60
[<40d5889e>] aha1542_detect+0x9e/0x940
[<405c5ba5>] ultrastor_detect+0x265/0x5f0
[<401352f5>] getnstimeofday+0x35/0xf0
[<40d58751>] init_this_scsi_driver+0x41/0xf0
[<40d0b856>] kernel_init+0x136/0x310
[<40d58710>] init_this_scsi_driver+0x0/0xf0
[<40d0b720>] kernel_init+0x0/0x310
[<40105547>] kernel_thread_helper+0x7/0x10
=======================
the fix is to first allocate from above the DMA pool, and if that fails
(for example due to it being a machine with less than 16 MB of RAM),
allocate from the DMA pool as a fallback.
With this fix applied i was able to boot a PAGEALLOC=y kernel that would
hang before.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/mm/init_32.c')
-rw-r--r-- | arch/x86/mm/init_32.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index dda4e83649a0..e4e37d4f4c52 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -85,13 +85,20 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd) | |||
85 | static pte_t * __init one_page_table_init(pmd_t *pmd) | 85 | static pte_t * __init one_page_table_init(pmd_t *pmd) |
86 | { | 86 | { |
87 | if (!(pmd_val(*pmd) & _PAGE_PRESENT)) { | 87 | if (!(pmd_val(*pmd) & _PAGE_PRESENT)) { |
88 | pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); | 88 | pte_t *page_table = NULL; |
89 | |||
90 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
91 | page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE); | ||
92 | #endif | ||
93 | if (!page_table) | ||
94 | page_table = | ||
95 | (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); | ||
89 | 96 | ||
90 | paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT); | 97 | paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT); |
91 | set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); | 98 | set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); |
92 | BUG_ON(page_table != pte_offset_kernel(pmd, 0)); | 99 | BUG_ON(page_table != pte_offset_kernel(pmd, 0)); |
93 | } | 100 | } |
94 | 101 | ||
95 | return pte_offset_kernel(pmd, 0); | 102 | return pte_offset_kernel(pmd, 0); |
96 | } | 103 | } |
97 | 104 | ||