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>
static pte_t * __init one_page_table_init(pmd_t *pmd)
{
if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
- pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ pte_t *page_table = NULL;
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
+#endif
+ if (!page_table)
+ page_table =
+ (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT);
set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
BUG_ON(page_table != pte_offset_kernel(pmd, 0));
}
-
+
return pte_offset_kernel(pmd, 0);
}