aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-02-04 10:48:08 -0500
committerIngo Molnar <mingo@elte.hu>2008-02-04 10:48:08 -0500
commit07cf89c05f2bbafa002401ac4e09ac31678513e4 (patch)
tree24c5beac69602ed5f1cc8f34e1660be821048847 /arch
parent31422c51e0dc72532d82e80895932d430c3ed307 (diff)
x86: CPA fix pagetable split
Move the readout of the large entry into the spinlock section to prevent an unlikely but possible race. Mark the pmd/pud entry present after the split. We preserved the non present bit in the new split mapping. Remove the stale gfp_flags double initialization. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/mm/pageattr.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 74446ea23ffb..72880993af89 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -336,7 +336,7 @@ out_unlock:
336 336
337static int split_large_page(pte_t *kpte, unsigned long address) 337static int split_large_page(pte_t *kpte, unsigned long address)
338{ 338{
339 pgprot_t ref_prot = pte_pgprot(pte_clrhuge(*kpte)); 339 pgprot_t ref_prot;
340 gfp_t gfp_flags = GFP_KERNEL; 340 gfp_t gfp_flags = GFP_KERNEL;
341 unsigned long flags, addr, pfn; 341 unsigned long flags, addr, pfn;
342 pte_t *pbase, *tmp; 342 pte_t *pbase, *tmp;
@@ -344,7 +344,6 @@ static int split_large_page(pte_t *kpte, unsigned long address)
344 unsigned int i, level; 344 unsigned int i, level;
345 345
346#ifdef CONFIG_DEBUG_PAGEALLOC 346#ifdef CONFIG_DEBUG_PAGEALLOC
347 gfp_flags = __GFP_HIGH | __GFP_NOFAIL | __GFP_NOWARN;
348 gfp_flags = GFP_ATOMIC | __GFP_NOWARN; 347 gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
349#endif 348#endif
350 base = alloc_pages(gfp_flags, 0); 349 base = alloc_pages(gfp_flags, 0);
@@ -368,6 +367,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
368#ifdef CONFIG_X86_32 367#ifdef CONFIG_X86_32
369 paravirt_alloc_pt(&init_mm, page_to_pfn(base)); 368 paravirt_alloc_pt(&init_mm, page_to_pfn(base));
370#endif 369#endif
370 ref_prot = pte_pgprot(pte_clrhuge(*kpte));
371 371
372 /* 372 /*
373 * Get the target pfn from the original entry: 373 * Get the target pfn from the original entry:
@@ -377,13 +377,17 @@ static int split_large_page(pte_t *kpte, unsigned long address)
377 set_pte(&pbase[i], pfn_pte(pfn, ref_prot)); 377 set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
378 378
379 /* 379 /*
380 * Install the new, split up pagetable. Important detail here: 380 * Install the new, split up pagetable. Important details here:
381 * 381 *
382 * On Intel the NX bit of all levels must be cleared to make a 382 * On Intel the NX bit of all levels must be cleared to make a
383 * page executable. See section 4.13.2 of Intel 64 and IA-32 383 * page executable. See section 4.13.2 of Intel 64 and IA-32
384 * Architectures Software Developer's Manual). 384 * Architectures Software Developer's Manual).
385 *
386 * Mark the entry present. The current mapping might be
387 * set to not present, which we preserved above.
385 */ 388 */
386 ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte))); 389 ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte)));
390 pgprot_val(ref_prot) |= _PAGE_PRESENT;
387 __set_pmd_pte(kpte, address, mk_pte(base, ref_prot)); 391 __set_pmd_pte(kpte, address, mk_pte(base, ref_prot));
388 base = NULL; 392 base = NULL;
389 393