diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-02-09 17:24:09 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-02-09 17:24:09 -0500 |
commit | 76ebd0548df6ee48586e9b80d8fc2f58aa5fb51c (patch) | |
tree | 10af366ea643126913cd588aa46741961be1d7cb | |
parent | a03c2a48e02aacaaea211c94691b729be357e047 (diff) |
x86: introduce page pool in cpa
DEBUG_PAGEALLOC was not possible on 64-bit due to its early-bootup
hardcoded reliance on PSE pages, and the unrobustness of the runtime
splitup of large pages. The splitup ended in recursive calls to
alloc_pages() when a page for a pte split was requested.
Avoid the recursion with a preallocated page pool, which is used to
split up large mappings and gets refilled in the return path of
kernel_map_pages after the split has been done. The size of the page
pool is adjusted to the available memory.
This part just implements the page pool and the initialization w/o
using it yet.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/mm/init_32.c | 2 | ||||
-rw-r--r-- | arch/x86/mm/init_64.c | 2 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 82 | ||||
-rw-r--r-- | include/asm-x86/cacheflush.h | 2 |
4 files changed, 87 insertions, 1 deletions
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 54aba3cf9efe..8106bba41ecb 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -664,6 +664,8 @@ void __init mem_init(void) | |||
664 | if (boot_cpu_data.wp_works_ok < 0) | 664 | if (boot_cpu_data.wp_works_ok < 0) |
665 | test_wp_bit(); | 665 | test_wp_bit(); |
666 | 666 | ||
667 | cpa_init(); | ||
668 | |||
667 | /* | 669 | /* |
668 | * Subtle. SMP is doing it's boot stuff late (because it has to | 670 | * Subtle. SMP is doing it's boot stuff late (because it has to |
669 | * fork idle threads) - but it also needs low mappings for the | 671 | * fork idle threads) - but it also needs low mappings for the |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 620d2b6b6bf4..b59fc238151f 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -528,6 +528,8 @@ void __init mem_init(void) | |||
528 | reservedpages << (PAGE_SHIFT-10), | 528 | reservedpages << (PAGE_SHIFT-10), |
529 | datasize >> 10, | 529 | datasize >> 10, |
530 | initsize >> 10); | 530 | initsize >> 10); |
531 | |||
532 | cpa_init(); | ||
531 | } | 533 | } |
532 | 534 | ||
533 | void free_init_pages(char *what, unsigned long begin, unsigned long end) | 535 | void free_init_pages(char *what, unsigned long begin, unsigned long end) |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index eb2a54415a77..831462c3bc35 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/interrupt.h> | ||
11 | 12 | ||
12 | #include <asm/e820.h> | 13 | #include <asm/e820.h> |
13 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
@@ -336,6 +337,77 @@ out_unlock: | |||
336 | return do_split; | 337 | return do_split; |
337 | } | 338 | } |
338 | 339 | ||
340 | static LIST_HEAD(page_pool); | ||
341 | static unsigned long pool_size, pool_pages, pool_low; | ||
342 | static unsigned long pool_used, pool_failed, pool_refill; | ||
343 | |||
344 | static void cpa_fill_pool(void) | ||
345 | { | ||
346 | struct page *p; | ||
347 | gfp_t gfp = GFP_KERNEL; | ||
348 | |||
349 | /* Do not allocate from interrupt context */ | ||
350 | if (in_irq() || irqs_disabled()) | ||
351 | return; | ||
352 | /* | ||
353 | * Check unlocked. I does not matter when we have one more | ||
354 | * page in the pool. The bit lock avoids recursive pool | ||
355 | * allocations: | ||
356 | */ | ||
357 | if (pool_pages >= pool_size || test_and_set_bit_lock(0, &pool_refill)) | ||
358 | return; | ||
359 | |||
360 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
361 | /* | ||
362 | * We could do: | ||
363 | * gfp = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; | ||
364 | * but this fails on !PREEMPT kernels | ||
365 | */ | ||
366 | gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN; | ||
367 | #endif | ||
368 | |||
369 | while (pool_pages < pool_size) { | ||
370 | p = alloc_pages(gfp, 0); | ||
371 | if (!p) { | ||
372 | pool_failed++; | ||
373 | break; | ||
374 | } | ||
375 | spin_lock_irq(&pgd_lock); | ||
376 | list_add(&p->lru, &page_pool); | ||
377 | pool_pages++; | ||
378 | spin_unlock_irq(&pgd_lock); | ||
379 | } | ||
380 | clear_bit_unlock(0, &pool_refill); | ||
381 | } | ||
382 | |||
383 | #define SHIFT_MB (20 - PAGE_SHIFT) | ||
384 | #define ROUND_MB_GB ((1 << 10) - 1) | ||
385 | #define SHIFT_MB_GB 10 | ||
386 | #define POOL_PAGES_PER_GB 16 | ||
387 | |||
388 | void __init cpa_init(void) | ||
389 | { | ||
390 | struct sysinfo si; | ||
391 | unsigned long gb; | ||
392 | |||
393 | si_meminfo(&si); | ||
394 | /* | ||
395 | * Calculate the number of pool pages: | ||
396 | * | ||
397 | * Convert totalram (nr of pages) to MiB and round to the next | ||
398 | * GiB. Shift MiB to Gib and multiply the result by | ||
399 | * POOL_PAGES_PER_GB: | ||
400 | */ | ||
401 | gb = ((si.totalram >> SHIFT_MB) + ROUND_MB_GB) >> SHIFT_MB_GB; | ||
402 | pool_size = POOL_PAGES_PER_GB * gb; | ||
403 | pool_low = pool_size; | ||
404 | |||
405 | cpa_fill_pool(); | ||
406 | printk(KERN_DEBUG | ||
407 | "CPA: page pool initialized %lu of %lu pages preallocated\n", | ||
408 | pool_pages, pool_size); | ||
409 | } | ||
410 | |||
339 | static int split_large_page(pte_t *kpte, unsigned long address) | 411 | static int split_large_page(pte_t *kpte, unsigned long address) |
340 | { | 412 | { |
341 | unsigned long flags, pfn, pfninc = 1; | 413 | unsigned long flags, pfn, pfninc = 1; |
@@ -600,7 +672,7 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, | |||
600 | * Check whether we really changed something: | 672 | * Check whether we really changed something: |
601 | */ | 673 | */ |
602 | if (!cpa.flushtlb) | 674 | if (!cpa.flushtlb) |
603 | return ret; | 675 | goto out; |
604 | 676 | ||
605 | /* | 677 | /* |
606 | * No need to flush, when we did not set any of the caching | 678 | * No need to flush, when we did not set any of the caching |
@@ -619,6 +691,8 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, | |||
619 | else | 691 | else |
620 | cpa_flush_all(cache); | 692 | cpa_flush_all(cache); |
621 | 693 | ||
694 | out: | ||
695 | cpa_fill_pool(); | ||
622 | return ret; | 696 | return ret; |
623 | } | 697 | } |
624 | 698 | ||
@@ -772,6 +846,12 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
772 | * but that can deadlock->flush only current cpu: | 846 | * but that can deadlock->flush only current cpu: |
773 | */ | 847 | */ |
774 | __flush_tlb_all(); | 848 | __flush_tlb_all(); |
849 | |||
850 | /* | ||
851 | * Try to refill the page pool here. We can do this only after | ||
852 | * the tlb flush. | ||
853 | */ | ||
854 | cpa_fill_pool(); | ||
775 | } | 855 | } |
776 | #endif | 856 | #endif |
777 | 857 | ||
diff --git a/include/asm-x86/cacheflush.h b/include/asm-x86/cacheflush.h index 8dd8c5e3cc7f..6a22212b4b20 100644 --- a/include/asm-x86/cacheflush.h +++ b/include/asm-x86/cacheflush.h | |||
@@ -44,6 +44,8 @@ int set_memory_np(unsigned long addr, int numpages); | |||
44 | 44 | ||
45 | void clflush_cache_range(void *addr, unsigned int size); | 45 | void clflush_cache_range(void *addr, unsigned int size); |
46 | 46 | ||
47 | void cpa_init(void); | ||
48 | |||
47 | #ifdef CONFIG_DEBUG_RODATA | 49 | #ifdef CONFIG_DEBUG_RODATA |
48 | void mark_rodata_ro(void); | 50 | void mark_rodata_ro(void); |
49 | #endif | 51 | #endif |