diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-14 14:13:24 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-14 14:13:24 -0400 |
| commit | 6c4c4d4bdaff7ec0b7b26da67d741f639727c934 (patch) | |
| tree | 207d37c90d4a476a50b412158f9e0f4448344ba4 /arch/x86 | |
| parent | af788e35bff2b98a413c3e81b13c2a27ef6b7528 (diff) | |
| parent | 26564600c9e88c6572a5e6ef5ae9121907edfb7f (diff) | |
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Ingo Molnar:
"Misc fixes"
* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/mm: Flush lazy MMU when DEBUG_PAGEALLOC is set
x86/mm/cpa/selftest: Fix false positive in CPA self test
x86/mm/cpa: Convert noop to functional fix
x86, mm: Patch out arch_flush_lazy_mmu_mode() when running on bare metal
x86, mm, paravirt: Fix vmalloc_fault oops during lazy MMU updates
Diffstat (limited to 'arch/x86')
| -rw-r--r-- | arch/x86/include/asm/paravirt.h | 5 | ||||
| -rw-r--r-- | arch/x86/include/asm/paravirt_types.h | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/paravirt.c | 25 | ||||
| -rw-r--r-- | arch/x86/lguest/boot.c | 1 | ||||
| -rw-r--r-- | arch/x86/mm/fault.c | 6 | ||||
| -rw-r--r-- | arch/x86/mm/pageattr-test.c | 2 | ||||
| -rw-r--r-- | arch/x86/mm/pageattr.c | 12 | ||||
| -rw-r--r-- | arch/x86/xen/mmu.c | 1 |
8 files changed, 33 insertions, 21 deletions
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 5edd1742cfd0..7361e47db79f 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h | |||
| @@ -703,7 +703,10 @@ static inline void arch_leave_lazy_mmu_mode(void) | |||
| 703 | PVOP_VCALL0(pv_mmu_ops.lazy_mode.leave); | 703 | PVOP_VCALL0(pv_mmu_ops.lazy_mode.leave); |
| 704 | } | 704 | } |
| 705 | 705 | ||
| 706 | void arch_flush_lazy_mmu_mode(void); | 706 | static inline void arch_flush_lazy_mmu_mode(void) |
| 707 | { | ||
| 708 | PVOP_VCALL0(pv_mmu_ops.lazy_mode.flush); | ||
| 709 | } | ||
| 707 | 710 | ||
| 708 | static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx, | 711 | static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx, |
| 709 | phys_addr_t phys, pgprot_t flags) | 712 | phys_addr_t phys, pgprot_t flags) |
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 142236ed83af..b3b0ec1dac86 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h | |||
| @@ -91,6 +91,7 @@ struct pv_lazy_ops { | |||
| 91 | /* Set deferred update mode, used for batching operations. */ | 91 | /* Set deferred update mode, used for batching operations. */ |
| 92 | void (*enter)(void); | 92 | void (*enter)(void); |
| 93 | void (*leave)(void); | 93 | void (*leave)(void); |
| 94 | void (*flush)(void); | ||
| 94 | }; | 95 | }; |
| 95 | 96 | ||
| 96 | struct pv_time_ops { | 97 | struct pv_time_ops { |
| @@ -679,6 +680,7 @@ void paravirt_end_context_switch(struct task_struct *next); | |||
| 679 | 680 | ||
| 680 | void paravirt_enter_lazy_mmu(void); | 681 | void paravirt_enter_lazy_mmu(void); |
| 681 | void paravirt_leave_lazy_mmu(void); | 682 | void paravirt_leave_lazy_mmu(void); |
| 683 | void paravirt_flush_lazy_mmu(void); | ||
| 682 | 684 | ||
| 683 | void _paravirt_nop(void); | 685 | void _paravirt_nop(void); |
| 684 | u32 _paravirt_ident_32(u32); | 686 | u32 _paravirt_ident_32(u32); |
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 17fff18a1031..8bfb335f74bb 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c | |||
| @@ -263,6 +263,18 @@ void paravirt_leave_lazy_mmu(void) | |||
| 263 | leave_lazy(PARAVIRT_LAZY_MMU); | 263 | leave_lazy(PARAVIRT_LAZY_MMU); |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | void paravirt_flush_lazy_mmu(void) | ||
| 267 | { | ||
| 268 | preempt_disable(); | ||
| 269 | |||
| 270 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) { | ||
| 271 | arch_leave_lazy_mmu_mode(); | ||
| 272 | arch_enter_lazy_mmu_mode(); | ||
| 273 | } | ||
| 274 | |||
| 275 | preempt_enable(); | ||
| 276 | } | ||
| 277 | |||
| 266 | void paravirt_start_context_switch(struct task_struct *prev) | 278 | void paravirt_start_context_switch(struct task_struct *prev) |
| 267 | { | 279 | { |
| 268 | BUG_ON(preemptible()); | 280 | BUG_ON(preemptible()); |
| @@ -292,18 +304,6 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void) | |||
| 292 | return this_cpu_read(paravirt_lazy_mode); | 304 | return this_cpu_read(paravirt_lazy_mode); |
| 293 | } | 305 | } |
| 294 | 306 | ||
| 295 | void arch_flush_lazy_mmu_mode(void) | ||
| 296 | { | ||
| 297 | preempt_disable(); | ||
| 298 | |||
| 299 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) { | ||
| 300 | arch_leave_lazy_mmu_mode(); | ||
| 301 | arch_enter_lazy_mmu_mode(); | ||
| 302 | } | ||
| 303 | |||
| 304 | preempt_enable(); | ||
| 305 | } | ||
| 306 | |||
| 307 | struct pv_info pv_info = { | 307 | struct pv_info pv_info = { |
| 308 | .name = "bare hardware", | 308 | .name = "bare hardware", |
| 309 | .paravirt_enabled = 0, | 309 | .paravirt_enabled = 0, |
| @@ -475,6 +475,7 @@ struct pv_mmu_ops pv_mmu_ops = { | |||
| 475 | .lazy_mode = { | 475 | .lazy_mode = { |
| 476 | .enter = paravirt_nop, | 476 | .enter = paravirt_nop, |
| 477 | .leave = paravirt_nop, | 477 | .leave = paravirt_nop, |
| 478 | .flush = paravirt_nop, | ||
| 478 | }, | 479 | }, |
| 479 | 480 | ||
| 480 | .set_fixmap = native_set_fixmap, | 481 | .set_fixmap = native_set_fixmap, |
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 1cbd89ca5569..7114c63f047d 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c | |||
| @@ -1334,6 +1334,7 @@ __init void lguest_init(void) | |||
| 1334 | pv_mmu_ops.read_cr3 = lguest_read_cr3; | 1334 | pv_mmu_ops.read_cr3 = lguest_read_cr3; |
| 1335 | pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu; | 1335 | pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu; |
| 1336 | pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mmu_mode; | 1336 | pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mmu_mode; |
| 1337 | pv_mmu_ops.lazy_mode.flush = paravirt_flush_lazy_mmu; | ||
| 1337 | pv_mmu_ops.pte_update = lguest_pte_update; | 1338 | pv_mmu_ops.pte_update = lguest_pte_update; |
| 1338 | pv_mmu_ops.pte_update_defer = lguest_pte_update; | 1339 | pv_mmu_ops.pte_update_defer = lguest_pte_update; |
| 1339 | 1340 | ||
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 2b97525246d4..0e883364abb5 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
| @@ -378,10 +378,12 @@ static noinline __kprobes int vmalloc_fault(unsigned long address) | |||
| 378 | if (pgd_none(*pgd_ref)) | 378 | if (pgd_none(*pgd_ref)) |
| 379 | return -1; | 379 | return -1; |
| 380 | 380 | ||
| 381 | if (pgd_none(*pgd)) | 381 | if (pgd_none(*pgd)) { |
| 382 | set_pgd(pgd, *pgd_ref); | 382 | set_pgd(pgd, *pgd_ref); |
| 383 | else | 383 | arch_flush_lazy_mmu_mode(); |
| 384 | } else { | ||
| 384 | BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); | 385 | BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); |
| 386 | } | ||
| 385 | 387 | ||
| 386 | /* | 388 | /* |
| 387 | * Below here mismatches are bugs because these lower tables | 389 | * Below here mismatches are bugs because these lower tables |
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c index b0086567271c..0e38951e65eb 100644 --- a/arch/x86/mm/pageattr-test.c +++ b/arch/x86/mm/pageattr-test.c | |||
| @@ -68,7 +68,7 @@ static int print_split(struct split_state *s) | |||
| 68 | s->gpg++; | 68 | s->gpg++; |
| 69 | i += GPS/PAGE_SIZE; | 69 | i += GPS/PAGE_SIZE; |
| 70 | } else if (level == PG_LEVEL_2M) { | 70 | } else if (level == PG_LEVEL_2M) { |
| 71 | if (!(pte_val(*pte) & _PAGE_PSE)) { | 71 | if ((pte_val(*pte) & _PAGE_PRESENT) && !(pte_val(*pte) & _PAGE_PSE)) { |
| 72 | printk(KERN_ERR | 72 | printk(KERN_ERR |
| 73 | "%lx level %d but not PSE %Lx\n", | 73 | "%lx level %d but not PSE %Lx\n", |
| 74 | addr, level, (u64)pte_val(*pte)); | 74 | addr, level, (u64)pte_val(*pte)); |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 091934e1d0d9..fb4e73ec24d8 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
| @@ -467,7 +467,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 467 | * We are safe now. Check whether the new pgprot is the same: | 467 | * We are safe now. Check whether the new pgprot is the same: |
| 468 | */ | 468 | */ |
| 469 | old_pte = *kpte; | 469 | old_pte = *kpte; |
| 470 | old_prot = new_prot = req_prot = pte_pgprot(old_pte); | 470 | old_prot = req_prot = pte_pgprot(old_pte); |
| 471 | 471 | ||
| 472 | pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr); | 472 | pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr); |
| 473 | pgprot_val(req_prot) |= pgprot_val(cpa->mask_set); | 473 | pgprot_val(req_prot) |= pgprot_val(cpa->mask_set); |
| @@ -478,12 +478,12 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 478 | * a non present pmd. The canon_pgprot will clear _PAGE_GLOBAL | 478 | * a non present pmd. The canon_pgprot will clear _PAGE_GLOBAL |
| 479 | * for the ancient hardware that doesn't support it. | 479 | * for the ancient hardware that doesn't support it. |
| 480 | */ | 480 | */ |
| 481 | if (pgprot_val(new_prot) & _PAGE_PRESENT) | 481 | if (pgprot_val(req_prot) & _PAGE_PRESENT) |
| 482 | pgprot_val(new_prot) |= _PAGE_PSE | _PAGE_GLOBAL; | 482 | pgprot_val(req_prot) |= _PAGE_PSE | _PAGE_GLOBAL; |
| 483 | else | 483 | else |
| 484 | pgprot_val(new_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL); | 484 | pgprot_val(req_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL); |
| 485 | 485 | ||
| 486 | new_prot = canon_pgprot(new_prot); | 486 | req_prot = canon_pgprot(req_prot); |
| 487 | 487 | ||
| 488 | /* | 488 | /* |
| 489 | * old_pte points to the large page base address. So we need | 489 | * old_pte points to the large page base address. So we need |
| @@ -1413,6 +1413,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
| 1413 | * but that can deadlock->flush only current cpu: | 1413 | * but that can deadlock->flush only current cpu: |
| 1414 | */ | 1414 | */ |
| 1415 | __flush_tlb_all(); | 1415 | __flush_tlb_all(); |
| 1416 | |||
| 1417 | arch_flush_lazy_mmu_mode(); | ||
| 1416 | } | 1418 | } |
| 1417 | 1419 | ||
| 1418 | #ifdef CONFIG_HIBERNATION | 1420 | #ifdef CONFIG_HIBERNATION |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index a4ea92477e01..e006c18d288a 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
| @@ -2200,6 +2200,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = { | |||
| 2200 | .lazy_mode = { | 2200 | .lazy_mode = { |
| 2201 | .enter = paravirt_enter_lazy_mmu, | 2201 | .enter = paravirt_enter_lazy_mmu, |
| 2202 | .leave = xen_leave_lazy_mmu, | 2202 | .leave = xen_leave_lazy_mmu, |
| 2203 | .flush = paravirt_flush_lazy_mmu, | ||
| 2203 | }, | 2204 | }, |
| 2204 | 2205 | ||
| 2205 | .set_fixmap = xen_set_fixmap, | 2206 | .set_fixmap = xen_set_fixmap, |
