aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2008-01-30 07:34:11 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:34:11 -0500
commit6194ba6ff6ccf8d5c54c857600843c67aa82c407 (patch)
tree657dd9f452b252260fcf59959c0586920b8fe4c3 /arch/x86
parentfd40d6e3188b12c59696d6cb4a6f26333814d66f (diff)
x86: don't special-case pmd allocations as much
In x86 PAE mode, stop treating pmds as a special case. Previously they were always allocated and freed with the pgd. The modifies the code to be the same as 64-bit mode, where they are allocated on demand. This is a step on the way to unifying 32/64-bit pagetable allocation as much as possible. There is a complicating wart, however. When you install a new reference to a pmd in the pgd, the processor isn't guaranteed to see it unless you reload cr3. Since reloading cr3 also has the side-effect of flushing the tlb, this is an expense that we want to avoid whereever possible. This patch simply avoids reloading cr3 unless the update is to the current pagetable. Later patches will optimise this further. Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Cc: Andi Kleen <ak@suse.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: H. Peter Anvin <hpa@zytor.com> Cc: William Irwin <wli@holomorphy.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/mm/init_32.c13
-rw-r--r--arch/x86/mm/pgtable_32.c68
2 files changed, 0 insertions, 81 deletions
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 02d269c07b96..da524fb22422 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -704,19 +704,6 @@ int arch_add_memory(int nid, u64 start, u64 size)
704} 704}
705#endif 705#endif
706 706
707struct kmem_cache *pmd_cache;
708
709void __init pgtable_cache_init(void)
710{
711 if (PTRS_PER_PMD > 1) {
712 pmd_cache = kmem_cache_create("pmd",
713 PTRS_PER_PMD*sizeof(pmd_t),
714 PTRS_PER_PMD*sizeof(pmd_t),
715 SLAB_PANIC,
716 pmd_ctor);
717 }
718}
719
720/* 707/*
721 * This function cannot be __init, since exceptions don't work in that 708 * This function cannot be __init, since exceptions don't work in that
722 * section. Put this after the callers, so that it cannot be inlined. 709 * section. Put this after the callers, so that it cannot be inlined.
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c
index 3a6c9200058d..5ca3552474ae 100644
--- a/arch/x86/mm/pgtable_32.c
+++ b/arch/x86/mm/pgtable_32.c
@@ -195,11 +195,6 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
195 return pte; 195 return pte;
196} 196}
197 197
198void pmd_ctor(struct kmem_cache *cache, void *pmd)
199{
200 memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
201}
202
203/* 198/*
204 * List of all pgd's needed for non-PAE so it can invalidate entries 199 * List of all pgd's needed for non-PAE so it can invalidate entries
205 * in both cached and uncached pgd's; not needed for PAE since the 200 * in both cached and uncached pgd's; not needed for PAE since the
@@ -285,7 +280,6 @@ static void pgd_dtor(void *pgd)
285 if (SHARED_KERNEL_PMD) 280 if (SHARED_KERNEL_PMD)
286 return; 281 return;
287 282
288 paravirt_release_pd(__pa(pgd) >> PAGE_SHIFT);
289 spin_lock_irqsave(&pgd_lock, flags); 283 spin_lock_irqsave(&pgd_lock, flags);
290 pgd_list_del(pgd); 284 pgd_list_del(pgd);
291 spin_unlock_irqrestore(&pgd_lock, flags); 285 spin_unlock_irqrestore(&pgd_lock, flags);
@@ -367,84 +361,22 @@ static void pgd_mop_up_pmds(pgd_t *pgd)
367} 361}
368#endif /* CONFIG_X86_PAE */ 362#endif /* CONFIG_X86_PAE */
369 363
370/* If we allocate a pmd for part of the kernel address space, then
371 make sure its initialized with the appropriate kernel mappings.
372 Otherwise use a cached zeroed pmd. */
373static pmd_t *pmd_cache_alloc(int idx)
374{
375 pmd_t *pmd;
376
377 if (idx >= USER_PTRS_PER_PGD) {
378 pmd = (pmd_t *)__get_free_page(GFP_KERNEL);
379
380 if (pmd)
381 memcpy(pmd,
382 (void *)pgd_page_vaddr(swapper_pg_dir[idx]),
383 sizeof(pmd_t) * PTRS_PER_PMD);
384 } else
385 pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
386
387 return pmd;
388}
389
390static void pmd_cache_free(pmd_t *pmd, int idx)
391{
392 if (idx >= USER_PTRS_PER_PGD)
393 free_page((unsigned long)pmd);
394 else
395 kmem_cache_free(pmd_cache, pmd);
396}
397
398pgd_t *pgd_alloc(struct mm_struct *mm) 364pgd_t *pgd_alloc(struct mm_struct *mm)
399{ 365{
400 int i;
401 pgd_t *pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor); 366 pgd_t *pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
402 367
403 if (PTRS_PER_PMD == 1 || !pgd)
404 return pgd;
405
406 mm->pgd = pgd; /* so that alloc_pd can use it */ 368 mm->pgd = pgd; /* so that alloc_pd can use it */
407 369
408 for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) {
409 pmd_t *pmd = pmd_cache_alloc(i);
410
411 if (!pmd)
412 goto out_oom;
413
414 paravirt_alloc_pd(mm, __pa(pmd) >> PAGE_SHIFT);
415 set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
416 }
417 if (pgd && !pgd_prepopulate_pmd(mm, pgd)) { 370 if (pgd && !pgd_prepopulate_pmd(mm, pgd)) {
418 quicklist_free(0, pgd_dtor, pgd); 371 quicklist_free(0, pgd_dtor, pgd);
419 pgd = NULL; 372 pgd = NULL;
420 } 373 }
421 374
422 return pgd; 375 return pgd;
423
424out_oom:
425 for (i--; i >= 0; i--) {
426 pgd_t pgdent = pgd[i];
427 void* pmd = (void *)__va(pgd_val(pgdent)-1);
428 paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
429 pmd_cache_free(pmd, i);
430 }
431 quicklist_free(0, pgd_dtor, pgd);
432 return NULL;
433} 376}
434 377
435void pgd_free(pgd_t *pgd) 378void pgd_free(pgd_t *pgd)
436{ 379{
437 int i;
438
439 /* in the PAE case user pgd entries are overwritten before usage */
440 if (PTRS_PER_PMD > 1)
441 for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) {
442 pgd_t pgdent = pgd[i];
443 void* pmd = (void *)__va(pgd_val(pgdent)-1);
444 paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
445 pmd_cache_free(pmd, i);
446 }
447 /* in the non-PAE case, free_pgtables() clears user pgd entries */
448 pgd_mop_up_pmds(pgd); 380 pgd_mop_up_pmds(pgd);
449 quicklist_free(0, pgd_dtor, pgd); 381 quicklist_free(0, pgd_dtor, pgd);
450} 382}