aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-02-09 17:24:09 -0500
committerThomas Gleixner <tglx@linutronix.de>2008-02-09 17:24:09 -0500
commit76ebd0548df6ee48586e9b80d8fc2f58aa5fb51c (patch)
tree10af366ea643126913cd588aa46741961be1d7cb
parenta03c2a48e02aacaaea211c94691b729be357e047 (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.c2
-rw-r--r--arch/x86/mm/init_64.c2
-rw-r--r--arch/x86/mm/pageattr.c82
-rw-r--r--include/asm-x86/cacheflush.h2
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
533void free_init_pages(char *what, unsigned long begin, unsigned long end) 535void 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
340static LIST_HEAD(page_pool);
341static unsigned long pool_size, pool_pages, pool_low;
342static unsigned long pool_used, pool_failed, pool_refill;
343
344static 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
388void __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
339static int split_large_page(pte_t *kpte, unsigned long address) 411static 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
694out:
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
45void clflush_cache_range(void *addr, unsigned int size); 45void clflush_cache_range(void *addr, unsigned int size);
46 46
47void cpa_init(void);
48
47#ifdef CONFIG_DEBUG_RODATA 49#ifdef CONFIG_DEBUG_RODATA
48void mark_rodata_ro(void); 50void mark_rodata_ro(void);
49#endif 51#endif