diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-01-07 08:14:15 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-01-07 08:14:15 -0500 |
commit | 1c2a48cf65580a276552151eb8f78d78c55b828e (patch) | |
tree | 68ed0628a276b33cb5aa0ad4899c1afe0a33a69d /arch/x86/kernel/alternative.c | |
parent | 0aa002fe602939370e9476e5ec32b562000a0425 (diff) | |
parent | cb600d2f83c854ec3d6660063e4466431999489b (diff) |
Merge branch 'linus' into x86/apic-cleanups
Conflicts:
arch/x86/include/asm/io_apic.h
Merge reason: Resolve the conflict, update to a more recent -rc base
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/alternative.c')
-rw-r--r-- | arch/x86/kernel/alternative.c | 52 |
1 files changed, 42 insertions, 10 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 5079f24c955a..123608531c8f 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -353,6 +353,7 @@ void __init_or_module alternatives_smp_module_del(struct module *mod) | |||
353 | mutex_unlock(&smp_alt); | 353 | mutex_unlock(&smp_alt); |
354 | } | 354 | } |
355 | 355 | ||
356 | bool skip_smp_alternatives; | ||
356 | void alternatives_smp_switch(int smp) | 357 | void alternatives_smp_switch(int smp) |
357 | { | 358 | { |
358 | struct smp_alt_module *mod; | 359 | struct smp_alt_module *mod; |
@@ -368,7 +369,7 @@ void alternatives_smp_switch(int smp) | |||
368 | printk("lockdep: fixing up alternatives.\n"); | 369 | printk("lockdep: fixing up alternatives.\n"); |
369 | #endif | 370 | #endif |
370 | 371 | ||
371 | if (noreplace_smp || smp_alt_once) | 372 | if (noreplace_smp || smp_alt_once || skip_smp_alternatives) |
372 | return; | 373 | return; |
373 | BUG_ON(!smp && (num_online_cpus() > 1)); | 374 | BUG_ON(!smp && (num_online_cpus() > 1)); |
374 | 375 | ||
@@ -591,17 +592,21 @@ static atomic_t stop_machine_first; | |||
591 | static int wrote_text; | 592 | static int wrote_text; |
592 | 593 | ||
593 | struct text_poke_params { | 594 | struct text_poke_params { |
594 | void *addr; | 595 | struct text_poke_param *params; |
595 | const void *opcode; | 596 | int nparams; |
596 | size_t len; | ||
597 | }; | 597 | }; |
598 | 598 | ||
599 | static int __kprobes stop_machine_text_poke(void *data) | 599 | static int __kprobes stop_machine_text_poke(void *data) |
600 | { | 600 | { |
601 | struct text_poke_params *tpp = data; | 601 | struct text_poke_params *tpp = data; |
602 | struct text_poke_param *p; | ||
603 | int i; | ||
602 | 604 | ||
603 | if (atomic_dec_and_test(&stop_machine_first)) { | 605 | if (atomic_dec_and_test(&stop_machine_first)) { |
604 | text_poke(tpp->addr, tpp->opcode, tpp->len); | 606 | for (i = 0; i < tpp->nparams; i++) { |
607 | p = &tpp->params[i]; | ||
608 | text_poke(p->addr, p->opcode, p->len); | ||
609 | } | ||
605 | smp_wmb(); /* Make sure other cpus see that this has run */ | 610 | smp_wmb(); /* Make sure other cpus see that this has run */ |
606 | wrote_text = 1; | 611 | wrote_text = 1; |
607 | } else { | 612 | } else { |
@@ -610,8 +615,12 @@ static int __kprobes stop_machine_text_poke(void *data) | |||
610 | smp_mb(); /* Load wrote_text before following execution */ | 615 | smp_mb(); /* Load wrote_text before following execution */ |
611 | } | 616 | } |
612 | 617 | ||
613 | flush_icache_range((unsigned long)tpp->addr, | 618 | for (i = 0; i < tpp->nparams; i++) { |
614 | (unsigned long)tpp->addr + tpp->len); | 619 | p = &tpp->params[i]; |
620 | flush_icache_range((unsigned long)p->addr, | ||
621 | (unsigned long)p->addr + p->len); | ||
622 | } | ||
623 | |||
615 | return 0; | 624 | return 0; |
616 | } | 625 | } |
617 | 626 | ||
@@ -631,10 +640,13 @@ static int __kprobes stop_machine_text_poke(void *data) | |||
631 | void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) | 640 | void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) |
632 | { | 641 | { |
633 | struct text_poke_params tpp; | 642 | struct text_poke_params tpp; |
643 | struct text_poke_param p; | ||
634 | 644 | ||
635 | tpp.addr = addr; | 645 | p.addr = addr; |
636 | tpp.opcode = opcode; | 646 | p.opcode = opcode; |
637 | tpp.len = len; | 647 | p.len = len; |
648 | tpp.params = &p; | ||
649 | tpp.nparams = 1; | ||
638 | atomic_set(&stop_machine_first, 1); | 650 | atomic_set(&stop_machine_first, 1); |
639 | wrote_text = 0; | 651 | wrote_text = 0; |
640 | /* Use __stop_machine() because the caller already got online_cpus. */ | 652 | /* Use __stop_machine() because the caller already got online_cpus. */ |
@@ -642,6 +654,26 @@ void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) | |||
642 | return addr; | 654 | return addr; |
643 | } | 655 | } |
644 | 656 | ||
657 | /** | ||
658 | * text_poke_smp_batch - Update instructions on a live kernel on SMP | ||
659 | * @params: an array of text_poke parameters | ||
660 | * @n: the number of elements in params. | ||
661 | * | ||
662 | * Modify multi-byte instruction by using stop_machine() on SMP. Since the | ||
663 | * stop_machine() is heavy task, it is better to aggregate text_poke requests | ||
664 | * and do it once if possible. | ||
665 | * | ||
666 | * Note: Must be called under get_online_cpus() and text_mutex. | ||
667 | */ | ||
668 | void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n) | ||
669 | { | ||
670 | struct text_poke_params tpp = {.params = params, .nparams = n}; | ||
671 | |||
672 | atomic_set(&stop_machine_first, 1); | ||
673 | wrote_text = 0; | ||
674 | stop_machine(stop_machine_text_poke, (void *)&tpp, NULL); | ||
675 | } | ||
676 | |||
645 | #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) | 677 | #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) |
646 | 678 | ||
647 | #ifdef CONFIG_X86_64 | 679 | #ifdef CONFIG_X86_64 |