diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-02-04 10:48:08 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-02-04 10:48:08 -0500 |
commit | 07cf89c05f2bbafa002401ac4e09ac31678513e4 (patch) | |
tree | 24c5beac69602ed5f1cc8f34e1660be821048847 /arch/x86/mm/pageattr.c | |
parent | 31422c51e0dc72532d82e80895932d430c3ed307 (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/x86/mm/pageattr.c')
-rw-r--r-- | arch/x86/mm/pageattr.c | 10 |
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 | ||
337 | static int split_large_page(pte_t *kpte, unsigned long address) | 337 | static 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 | ||