diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2010-12-03 04:54:22 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-12-06 11:59:31 -0500 |
commit | 7deb18dcf0478940ac979de002db1ed8ba6531dc (patch) | |
tree | 6fb52200daf5d02cb5aa59c46b856d25c44ea037 /arch/x86/kernel/alternative.c | |
parent | 0490cd1f9d99569d3bd64e17adc88db06a5007be (diff) |
x86: Introduce text_poke_smp_batch() for batch-code modifying
Introduce text_poke_smp_batch(). This function modifies several
text areas with one stop_machine() on SMP. Because calling
stop_machine() is heavy task, it is better to aggregate
text_poke requests.
( Note: I've talked with Rusty about this interface, and
he would not like to expand stop_machine() interface, since
it is not for generic use. )
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Jan Beulich <jbeulich@novell.com>
Cc: 2nddept-manager@sdl.hitachi.co.jp
LKML-Reference: <20101203095422.2961.51217.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/alternative.c')
-rw-r--r-- | arch/x86/kernel/alternative.c | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 5079f24c955a..553d0b0d639b 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -591,17 +591,21 @@ static atomic_t stop_machine_first; | |||
591 | static int wrote_text; | 591 | static int wrote_text; |
592 | 592 | ||
593 | struct text_poke_params { | 593 | struct text_poke_params { |
594 | void *addr; | 594 | struct text_poke_param *params; |
595 | const void *opcode; | 595 | int nparams; |
596 | size_t len; | ||
597 | }; | 596 | }; |
598 | 597 | ||
599 | static int __kprobes stop_machine_text_poke(void *data) | 598 | static int __kprobes stop_machine_text_poke(void *data) |
600 | { | 599 | { |
601 | struct text_poke_params *tpp = data; | 600 | struct text_poke_params *tpp = data; |
601 | struct text_poke_param *p; | ||
602 | int i; | ||
602 | 603 | ||
603 | if (atomic_dec_and_test(&stop_machine_first)) { | 604 | if (atomic_dec_and_test(&stop_machine_first)) { |
604 | text_poke(tpp->addr, tpp->opcode, tpp->len); | 605 | for (i = 0; i < tpp->nparams; i++) { |
606 | p = &tpp->params[i]; | ||
607 | text_poke(p->addr, p->opcode, p->len); | ||
608 | } | ||
605 | smp_wmb(); /* Make sure other cpus see that this has run */ | 609 | smp_wmb(); /* Make sure other cpus see that this has run */ |
606 | wrote_text = 1; | 610 | wrote_text = 1; |
607 | } else { | 611 | } else { |
@@ -610,8 +614,12 @@ static int __kprobes stop_machine_text_poke(void *data) | |||
610 | smp_mb(); /* Load wrote_text before following execution */ | 614 | smp_mb(); /* Load wrote_text before following execution */ |
611 | } | 615 | } |
612 | 616 | ||
613 | flush_icache_range((unsigned long)tpp->addr, | 617 | for (i = 0; i < tpp->nparams; i++) { |
614 | (unsigned long)tpp->addr + tpp->len); | 618 | p = &tpp->params[i]; |
619 | flush_icache_range((unsigned long)p->addr, | ||
620 | (unsigned long)p->addr + p->len); | ||
621 | } | ||
622 | |||
615 | return 0; | 623 | return 0; |
616 | } | 624 | } |
617 | 625 | ||
@@ -631,10 +639,13 @@ static int __kprobes stop_machine_text_poke(void *data) | |||
631 | void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) | 639 | void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) |
632 | { | 640 | { |
633 | struct text_poke_params tpp; | 641 | struct text_poke_params tpp; |
642 | struct text_poke_param p; | ||
634 | 643 | ||
635 | tpp.addr = addr; | 644 | p.addr = addr; |
636 | tpp.opcode = opcode; | 645 | p.opcode = opcode; |
637 | tpp.len = len; | 646 | p.len = len; |
647 | tpp.params = &p; | ||
648 | tpp.nparams = 1; | ||
638 | atomic_set(&stop_machine_first, 1); | 649 | atomic_set(&stop_machine_first, 1); |
639 | wrote_text = 0; | 650 | wrote_text = 0; |
640 | /* Use __stop_machine() because the caller already got online_cpus. */ | 651 | /* Use __stop_machine() because the caller already got online_cpus. */ |
@@ -642,6 +653,26 @@ void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) | |||
642 | return addr; | 653 | return addr; |
643 | } | 654 | } |
644 | 655 | ||
656 | /** | ||
657 | * text_poke_smp_batch - Update instructions on a live kernel on SMP | ||
658 | * @params: an array of text_poke parameters | ||
659 | * @n: the number of elements in params. | ||
660 | * | ||
661 | * Modify multi-byte instruction by using stop_machine() on SMP. Since the | ||
662 | * stop_machine() is heavy task, it is better to aggregate text_poke requests | ||
663 | * and do it once if possible. | ||
664 | * | ||
665 | * Note: Must be called under get_online_cpus() and text_mutex. | ||
666 | */ | ||
667 | void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n) | ||
668 | { | ||
669 | struct text_poke_params tpp = {.params = params, .nparams = n}; | ||
670 | |||
671 | atomic_set(&stop_machine_first, 1); | ||
672 | wrote_text = 0; | ||
673 | stop_machine(stop_machine_text_poke, (void *)&tpp, NULL); | ||
674 | } | ||
675 | |||
645 | #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) | 676 | #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) |
646 | 677 | ||
647 | #ifdef CONFIG_X86_64 | 678 | #ifdef CONFIG_X86_64 |