diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2009-03-06 10:37:54 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-06 10:49:01 -0500 |
commit | 78ff7fae04554b49d29226ed12536268c2500d1f (patch) | |
tree | 377980e0543a7c9d0f6567498a186284ae85e432 /arch/x86/kernel/alternative.c | |
parent | 3945dab45aa8c89014893bfa8eb1e1661a409cef (diff) |
x86: implement atomic text_poke() via fixmap
Use fixmaps instead of vmap/vunmap in text_poke() for avoiding
page allocation and delayed unmapping.
At the result of above change, text_poke() becomes atomic and can be called
from stop_machine() etc.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Acked-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
LKML-Reference: <49B14352.2040705@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/alternative.c')
-rw-r--r-- | arch/x86/kernel/alternative.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 092a7b8be68d..2d903b760ddb 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -13,7 +13,9 @@ | |||
13 | #include <asm/nmi.h> | 13 | #include <asm/nmi.h> |
14 | #include <asm/vsyscall.h> | 14 | #include <asm/vsyscall.h> |
15 | #include <asm/cacheflush.h> | 15 | #include <asm/cacheflush.h> |
16 | #include <asm/tlbflush.h> | ||
16 | #include <asm/io.h> | 17 | #include <asm/io.h> |
18 | #include <asm/fixmap.h> | ||
17 | 19 | ||
18 | #define MAX_PATCH_LEN (255-1) | 20 | #define MAX_PATCH_LEN (255-1) |
19 | 21 | ||
@@ -505,15 +507,16 @@ void *text_poke_early(void *addr, const void *opcode, size_t len) | |||
505 | * It means the size must be writable atomically and the address must be aligned | 507 | * It means the size must be writable atomically and the address must be aligned |
506 | * in a way that permits an atomic write. It also makes sure we fit on a single | 508 | * in a way that permits an atomic write. It also makes sure we fit on a single |
507 | * page. | 509 | * page. |
510 | * | ||
511 | * Note: Must be called under text_mutex. | ||
508 | */ | 512 | */ |
509 | void *__kprobes text_poke(void *addr, const void *opcode, size_t len) | 513 | void *__kprobes text_poke(void *addr, const void *opcode, size_t len) |
510 | { | 514 | { |
515 | unsigned long flags; | ||
511 | char *vaddr; | 516 | char *vaddr; |
512 | int nr_pages = 2; | ||
513 | struct page *pages[2]; | 517 | struct page *pages[2]; |
514 | int i; | 518 | int i; |
515 | 519 | ||
516 | might_sleep(); | ||
517 | if (!core_kernel_text((unsigned long)addr)) { | 520 | if (!core_kernel_text((unsigned long)addr)) { |
518 | pages[0] = vmalloc_to_page(addr); | 521 | pages[0] = vmalloc_to_page(addr); |
519 | pages[1] = vmalloc_to_page(addr + PAGE_SIZE); | 522 | pages[1] = vmalloc_to_page(addr + PAGE_SIZE); |
@@ -523,14 +526,17 @@ void *__kprobes text_poke(void *addr, const void *opcode, size_t len) | |||
523 | pages[1] = virt_to_page(addr + PAGE_SIZE); | 526 | pages[1] = virt_to_page(addr + PAGE_SIZE); |
524 | } | 527 | } |
525 | BUG_ON(!pages[0]); | 528 | BUG_ON(!pages[0]); |
526 | if (!pages[1]) | 529 | set_fixmap(FIX_TEXT_POKE0, page_to_phys(pages[0])); |
527 | nr_pages = 1; | 530 | if (pages[1]) |
528 | vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL); | 531 | set_fixmap(FIX_TEXT_POKE1, page_to_phys(pages[1])); |
529 | BUG_ON(!vaddr); | 532 | vaddr = (char *)fix_to_virt(FIX_TEXT_POKE0); |
530 | local_irq_disable(); | 533 | local_irq_save(flags); |
531 | memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len); | 534 | memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len); |
532 | local_irq_enable(); | 535 | local_irq_restore(flags); |
533 | vunmap(vaddr); | 536 | clear_fixmap(FIX_TEXT_POKE0); |
537 | if (pages[1]) | ||
538 | clear_fixmap(FIX_TEXT_POKE1); | ||
539 | local_flush_tlb(); | ||
534 | sync_core(); | 540 | sync_core(); |
535 | /* Could also do a CLFLUSH here to speed up CPU recovery; but | 541 | /* Could also do a CLFLUSH here to speed up CPU recovery; but |
536 | that causes hangs on some VIA CPUs. */ | 542 | that causes hangs on some VIA CPUs. */ |