aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/alternative.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2009-03-06 10:37:54 -0500
committerIngo Molnar <mingo@elte.hu>2009-03-06 10:49:01 -0500
commit78ff7fae04554b49d29226ed12536268c2500d1f (patch)
tree377980e0543a7c9d0f6567498a186284ae85e432 /arch/x86/kernel/alternative.c
parent3945dab45aa8c89014893bfa8eb1e1661a409cef (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.c24
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 */
509void *__kprobes text_poke(void *addr, const void *opcode, size_t len) 513void *__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. */