diff options
-rw-r--r-- | arch/Kconfig | 14 | ||||
-rw-r--r-- | arch/sparc/include/asm/jump_label.h | 1 | ||||
-rw-r--r-- | arch/x86/Makefile_32.cpu | 13 | ||||
-rw-r--r-- | arch/x86/kernel/alternative.c | 69 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 2 | ||||
-rw-r--r-- | drivers/oprofile/buffer_sync.c | 2 | ||||
-rw-r--r-- | drivers/oprofile/cpu_buffer.c | 10 | ||||
-rw-r--r-- | drivers/oprofile/cpu_buffer.h | 1 | ||||
-rw-r--r-- | drivers/oprofile/timer_int.c | 13 | ||||
-rw-r--r-- | include/linux/jump_label.h | 7 | ||||
-rw-r--r-- | kernel/jump_label.c | 77 | ||||
-rw-r--r-- | kernel/kprobes.c | 26 |
12 files changed, 153 insertions, 82 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 53d7f619a1b9..8bf0fa652eb6 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -42,6 +42,20 @@ config KPROBES | |||
42 | for kernel debugging, non-intrusive instrumentation and testing. | 42 | for kernel debugging, non-intrusive instrumentation and testing. |
43 | If in doubt, say "N". | 43 | If in doubt, say "N". |
44 | 44 | ||
45 | config JUMP_LABEL | ||
46 | bool "Optimize trace point call sites" | ||
47 | depends on HAVE_ARCH_JUMP_LABEL | ||
48 | help | ||
49 | If it is detected that the compiler has support for "asm goto", | ||
50 | the kernel will compile trace point locations with just a | ||
51 | nop instruction. When trace points are enabled, the nop will | ||
52 | be converted to a jump to the trace function. This technique | ||
53 | lowers overhead and stress on the branch prediction of the | ||
54 | processor. | ||
55 | |||
56 | On i386, options added to the compiler flags may increase | ||
57 | the size of the kernel slightly. | ||
58 | |||
45 | config OPTPROBES | 59 | config OPTPROBES |
46 | def_bool y | 60 | def_bool y |
47 | depends on KPROBES && HAVE_OPTPROBES | 61 | depends on KPROBES && HAVE_OPTPROBES |
diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h index 65c0d3029796..427d4684e0d2 100644 --- a/arch/sparc/include/asm/jump_label.h +++ b/arch/sparc/include/asm/jump_label.h | |||
@@ -13,6 +13,7 @@ | |||
13 | "nop\n\t" \ | 13 | "nop\n\t" \ |
14 | "nop\n\t" \ | 14 | "nop\n\t" \ |
15 | ".pushsection __jump_table, \"a\"\n\t"\ | 15 | ".pushsection __jump_table, \"a\"\n\t"\ |
16 | ".align 4\n\t" \ | ||
16 | ".word 1b, %l[" #label "], %c0\n\t" \ | 17 | ".word 1b, %l[" #label "], %c0\n\t" \ |
17 | ".popsection \n\t" \ | 18 | ".popsection \n\t" \ |
18 | : : "i" (key) : : label);\ | 19 | : : "i" (key) : : label);\ |
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index 1255d953c65d..f2ee1abb1df9 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu | |||
@@ -51,7 +51,18 @@ cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686)) | |||
51 | # prologue (push %ebp, mov %esp, %ebp) which breaks the function graph | 51 | # prologue (push %ebp, mov %esp, %ebp) which breaks the function graph |
52 | # tracer assumptions. For i686, generic, core2 this is set by the | 52 | # tracer assumptions. For i686, generic, core2 this is set by the |
53 | # compiler anyway | 53 | # compiler anyway |
54 | cflags-$(CONFIG_FUNCTION_GRAPH_TRACER) += $(call cc-option,-maccumulate-outgoing-args) | 54 | ifeq ($(CONFIG_FUNCTION_GRAPH_TRACER), y) |
55 | ADD_ACCUMULATE_OUTGOING_ARGS := y | ||
56 | endif | ||
57 | |||
58 | # Work around to a bug with asm goto with first implementations of it | ||
59 | # in gcc causing gcc to mess up the push and pop of the stack in some | ||
60 | # uses of asm goto. | ||
61 | ifeq ($(CONFIG_JUMP_LABEL), y) | ||
62 | ADD_ACCUMULATE_OUTGOING_ARGS := y | ||
63 | endif | ||
64 | |||
65 | cflags-$(ADD_ACCUMULATE_OUTGOING_ARGS) += $(call cc-option,-maccumulate-outgoing-args) | ||
55 | 66 | ||
56 | # Bug fix for binutils: this option is required in order to keep | 67 | # Bug fix for binutils: this option is required in order to keep |
57 | # binutils from generating NOPL instructions against our will. | 68 | # binutils from generating NOPL instructions against our will. |
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 5ceeca382820..5079f24c955a 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -644,65 +644,26 @@ void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) | |||
644 | 644 | ||
645 | #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) | 645 | #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) |
646 | 646 | ||
647 | unsigned char ideal_nop5[IDEAL_NOP_SIZE_5]; | 647 | #ifdef CONFIG_X86_64 |
648 | unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 }; | ||
649 | #else | ||
650 | unsigned char ideal_nop5[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; | ||
651 | #endif | ||
648 | 652 | ||
649 | void __init arch_init_ideal_nop5(void) | 653 | void __init arch_init_ideal_nop5(void) |
650 | { | 654 | { |
651 | extern const unsigned char ftrace_test_p6nop[]; | ||
652 | extern const unsigned char ftrace_test_nop5[]; | ||
653 | extern const unsigned char ftrace_test_jmp[]; | ||
654 | int faulted = 0; | ||
655 | |||
656 | /* | 655 | /* |
657 | * There is no good nop for all x86 archs. | 656 | * There is no good nop for all x86 archs. This selection |
658 | * We will default to using the P6_NOP5, but first we | 657 | * algorithm should be unified with the one in find_nop_table(), |
659 | * will test to make sure that the nop will actually | 658 | * but this should be good enough for now. |
660 | * work on this CPU. If it faults, we will then | ||
661 | * go to a lesser efficient 5 byte nop. If that fails | ||
662 | * we then just use a jmp as our nop. This isn't the most | ||
663 | * efficient nop, but we can not use a multi part nop | ||
664 | * since we would then risk being preempted in the middle | ||
665 | * of that nop, and if we enabled tracing then, it might | ||
666 | * cause a system crash. | ||
667 | * | 659 | * |
668 | * TODO: check the cpuid to determine the best nop. | 660 | * For cases other than the ones below, use the safe (as in |
661 | * always functional) defaults above. | ||
669 | */ | 662 | */ |
670 | asm volatile ( | 663 | #ifdef CONFIG_X86_64 |
671 | "ftrace_test_jmp:" | 664 | /* Don't use these on 32 bits due to broken virtualizers */ |
672 | "jmp ftrace_test_p6nop\n" | 665 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) |
673 | "nop\n" | 666 | memcpy(ideal_nop5, p6_nops[5], 5); |
674 | "nop\n" | 667 | #endif |
675 | "nop\n" /* 2 byte jmp + 3 bytes */ | ||
676 | "ftrace_test_p6nop:" | ||
677 | P6_NOP5 | ||
678 | "jmp 1f\n" | ||
679 | "ftrace_test_nop5:" | ||
680 | ".byte 0x66,0x66,0x66,0x66,0x90\n" | ||
681 | "1:" | ||
682 | ".section .fixup, \"ax\"\n" | ||
683 | "2: movl $1, %0\n" | ||
684 | " jmp ftrace_test_nop5\n" | ||
685 | "3: movl $2, %0\n" | ||
686 | " jmp 1b\n" | ||
687 | ".previous\n" | ||
688 | _ASM_EXTABLE(ftrace_test_p6nop, 2b) | ||
689 | _ASM_EXTABLE(ftrace_test_nop5, 3b) | ||
690 | : "=r"(faulted) : "0" (faulted)); | ||
691 | |||
692 | switch (faulted) { | ||
693 | case 0: | ||
694 | pr_info("converting mcount calls to 0f 1f 44 00 00\n"); | ||
695 | memcpy(ideal_nop5, ftrace_test_p6nop, IDEAL_NOP_SIZE_5); | ||
696 | break; | ||
697 | case 1: | ||
698 | pr_info("converting mcount calls to 66 66 66 66 90\n"); | ||
699 | memcpy(ideal_nop5, ftrace_test_nop5, IDEAL_NOP_SIZE_5); | ||
700 | break; | ||
701 | case 2: | ||
702 | pr_info("converting mcount calls to jmp . + 5\n"); | ||
703 | memcpy(ideal_nop5, ftrace_test_jmp, IDEAL_NOP_SIZE_5); | ||
704 | break; | ||
705 | } | ||
706 | |||
707 | } | 668 | } |
708 | #endif | 669 | #endif |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 0929191d83cf..7cc0a721f628 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -3109,7 +3109,7 @@ void destroy_irq(unsigned int irq) | |||
3109 | 3109 | ||
3110 | irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); | 3110 | irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); |
3111 | 3111 | ||
3112 | if (intr_remapping_enabled) | 3112 | if (irq_remapped(cfg)) |
3113 | free_irte(irq); | 3113 | free_irte(irq); |
3114 | raw_spin_lock_irqsave(&vector_lock, flags); | 3114 | raw_spin_lock_irqsave(&vector_lock, flags); |
3115 | __clear_irq_vector(irq, cfg); | 3115 | __clear_irq_vector(irq, cfg); |
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index b7e755f4178a..a3984f4ef192 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c | |||
@@ -190,7 +190,7 @@ void sync_stop(void) | |||
190 | profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); | 190 | profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); |
191 | task_handoff_unregister(&task_free_nb); | 191 | task_handoff_unregister(&task_free_nb); |
192 | mutex_unlock(&buffer_mutex); | 192 | mutex_unlock(&buffer_mutex); |
193 | flush_scheduled_work(); | 193 | flush_cpu_work(); |
194 | 194 | ||
195 | /* make sure we don't leak task structs */ | 195 | /* make sure we don't leak task structs */ |
196 | process_task_mortuary(); | 196 | process_task_mortuary(); |
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index f179ac2ea801..59f55441e075 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c | |||
@@ -111,14 +111,18 @@ void start_cpu_work(void) | |||
111 | 111 | ||
112 | void end_cpu_work(void) | 112 | void end_cpu_work(void) |
113 | { | 113 | { |
114 | int i; | ||
115 | |||
116 | work_enabled = 0; | 114 | work_enabled = 0; |
115 | } | ||
116 | |||
117 | void flush_cpu_work(void) | ||
118 | { | ||
119 | int i; | ||
117 | 120 | ||
118 | for_each_online_cpu(i) { | 121 | for_each_online_cpu(i) { |
119 | struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i); | 122 | struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i); |
120 | 123 | ||
121 | cancel_delayed_work(&b->work); | 124 | /* these works are per-cpu, no need for flush_sync */ |
125 | flush_delayed_work(&b->work); | ||
122 | } | 126 | } |
123 | } | 127 | } |
124 | 128 | ||
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index 68ea16ab645f..e1d097e250ae 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h | |||
@@ -25,6 +25,7 @@ void free_cpu_buffers(void); | |||
25 | 25 | ||
26 | void start_cpu_work(void); | 26 | void start_cpu_work(void); |
27 | void end_cpu_work(void); | 27 | void end_cpu_work(void); |
28 | void flush_cpu_work(void); | ||
28 | 29 | ||
29 | /* CPU buffer is composed of such entries (which are | 30 | /* CPU buffer is composed of such entries (which are |
30 | * also used for context switch notes) | 31 | * also used for context switch notes) |
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index dc0ae4d14dff..010725117dbb 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "oprof.h" | 21 | #include "oprof.h" |
22 | 22 | ||
23 | static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer); | 23 | static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer); |
24 | static int ctr_running; | ||
24 | 25 | ||
25 | static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer) | 26 | static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer) |
26 | { | 27 | { |
@@ -33,6 +34,9 @@ static void __oprofile_hrtimer_start(void *unused) | |||
33 | { | 34 | { |
34 | struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer); | 35 | struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer); |
35 | 36 | ||
37 | if (!ctr_running) | ||
38 | return; | ||
39 | |||
36 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 40 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
37 | hrtimer->function = oprofile_hrtimer_notify; | 41 | hrtimer->function = oprofile_hrtimer_notify; |
38 | 42 | ||
@@ -42,7 +46,10 @@ static void __oprofile_hrtimer_start(void *unused) | |||
42 | 46 | ||
43 | static int oprofile_hrtimer_start(void) | 47 | static int oprofile_hrtimer_start(void) |
44 | { | 48 | { |
49 | get_online_cpus(); | ||
50 | ctr_running = 1; | ||
45 | on_each_cpu(__oprofile_hrtimer_start, NULL, 1); | 51 | on_each_cpu(__oprofile_hrtimer_start, NULL, 1); |
52 | put_online_cpus(); | ||
46 | return 0; | 53 | return 0; |
47 | } | 54 | } |
48 | 55 | ||
@@ -50,6 +57,9 @@ static void __oprofile_hrtimer_stop(int cpu) | |||
50 | { | 57 | { |
51 | struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu); | 58 | struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu); |
52 | 59 | ||
60 | if (!ctr_running) | ||
61 | return; | ||
62 | |||
53 | hrtimer_cancel(hrtimer); | 63 | hrtimer_cancel(hrtimer); |
54 | } | 64 | } |
55 | 65 | ||
@@ -57,8 +67,11 @@ static void oprofile_hrtimer_stop(void) | |||
57 | { | 67 | { |
58 | int cpu; | 68 | int cpu; |
59 | 69 | ||
70 | get_online_cpus(); | ||
60 | for_each_online_cpu(cpu) | 71 | for_each_online_cpu(cpu) |
61 | __oprofile_hrtimer_stop(cpu); | 72 | __oprofile_hrtimer_stop(cpu); |
73 | ctr_running = 0; | ||
74 | put_online_cpus(); | ||
62 | } | 75 | } |
63 | 76 | ||
64 | static int __cpuinit oprofile_cpu_notify(struct notifier_block *self, | 77 | static int __cpuinit oprofile_cpu_notify(struct notifier_block *self, |
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index b67cb180e6e9..7880f18e4b86 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef _LINUX_JUMP_LABEL_H | 1 | #ifndef _LINUX_JUMP_LABEL_H |
2 | #define _LINUX_JUMP_LABEL_H | 2 | #define _LINUX_JUMP_LABEL_H |
3 | 3 | ||
4 | #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_HAVE_ARCH_JUMP_LABEL) | 4 | #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) |
5 | # include <asm/jump_label.h> | 5 | # include <asm/jump_label.h> |
6 | # define HAVE_JUMP_LABEL | 6 | # define HAVE_JUMP_LABEL |
7 | #endif | 7 | #endif |
@@ -18,6 +18,8 @@ struct module; | |||
18 | extern struct jump_entry __start___jump_table[]; | 18 | extern struct jump_entry __start___jump_table[]; |
19 | extern struct jump_entry __stop___jump_table[]; | 19 | extern struct jump_entry __stop___jump_table[]; |
20 | 20 | ||
21 | extern void jump_label_lock(void); | ||
22 | extern void jump_label_unlock(void); | ||
21 | extern void arch_jump_label_transform(struct jump_entry *entry, | 23 | extern void arch_jump_label_transform(struct jump_entry *entry, |
22 | enum jump_label_type type); | 24 | enum jump_label_type type); |
23 | extern void arch_jump_label_text_poke_early(jump_label_t addr); | 25 | extern void arch_jump_label_text_poke_early(jump_label_t addr); |
@@ -59,6 +61,9 @@ static inline int jump_label_text_reserved(void *start, void *end) | |||
59 | return 0; | 61 | return 0; |
60 | } | 62 | } |
61 | 63 | ||
64 | static inline void jump_label_lock(void) {} | ||
65 | static inline void jump_label_unlock(void) {} | ||
66 | |||
62 | #endif | 67 | #endif |
63 | 68 | ||
64 | #define COND_STMT(key, stmt) \ | 69 | #define COND_STMT(key, stmt) \ |
diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 7be868bf25c6..3b79bd938330 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c | |||
@@ -39,6 +39,16 @@ struct jump_label_module_entry { | |||
39 | struct module *mod; | 39 | struct module *mod; |
40 | }; | 40 | }; |
41 | 41 | ||
42 | void jump_label_lock(void) | ||
43 | { | ||
44 | mutex_lock(&jump_label_mutex); | ||
45 | } | ||
46 | |||
47 | void jump_label_unlock(void) | ||
48 | { | ||
49 | mutex_unlock(&jump_label_mutex); | ||
50 | } | ||
51 | |||
42 | static int jump_label_cmp(const void *a, const void *b) | 52 | static int jump_label_cmp(const void *a, const void *b) |
43 | { | 53 | { |
44 | const struct jump_entry *jea = a; | 54 | const struct jump_entry *jea = a; |
@@ -152,7 +162,7 @@ void jump_label_update(unsigned long key, enum jump_label_type type) | |||
152 | struct jump_label_module_entry *e_module; | 162 | struct jump_label_module_entry *e_module; |
153 | int count; | 163 | int count; |
154 | 164 | ||
155 | mutex_lock(&jump_label_mutex); | 165 | jump_label_lock(); |
156 | entry = get_jump_label_entry((jump_label_t)key); | 166 | entry = get_jump_label_entry((jump_label_t)key); |
157 | if (entry) { | 167 | if (entry) { |
158 | count = entry->nr_entries; | 168 | count = entry->nr_entries; |
@@ -168,13 +178,14 @@ void jump_label_update(unsigned long key, enum jump_label_type type) | |||
168 | count = e_module->nr_entries; | 178 | count = e_module->nr_entries; |
169 | iter = e_module->table; | 179 | iter = e_module->table; |
170 | while (count--) { | 180 | while (count--) { |
171 | if (kernel_text_address(iter->code)) | 181 | if (iter->key && |
182 | kernel_text_address(iter->code)) | ||
172 | arch_jump_label_transform(iter, type); | 183 | arch_jump_label_transform(iter, type); |
173 | iter++; | 184 | iter++; |
174 | } | 185 | } |
175 | } | 186 | } |
176 | } | 187 | } |
177 | mutex_unlock(&jump_label_mutex); | 188 | jump_label_unlock(); |
178 | } | 189 | } |
179 | 190 | ||
180 | static int addr_conflict(struct jump_entry *entry, void *start, void *end) | 191 | static int addr_conflict(struct jump_entry *entry, void *start, void *end) |
@@ -231,6 +242,7 @@ out: | |||
231 | * overlaps with any of the jump label patch addresses. Code | 242 | * overlaps with any of the jump label patch addresses. Code |
232 | * that wants to modify kernel text should first verify that | 243 | * that wants to modify kernel text should first verify that |
233 | * it does not overlap with any of the jump label addresses. | 244 | * it does not overlap with any of the jump label addresses. |
245 | * Caller must hold jump_label_mutex. | ||
234 | * | 246 | * |
235 | * returns 1 if there is an overlap, 0 otherwise | 247 | * returns 1 if there is an overlap, 0 otherwise |
236 | */ | 248 | */ |
@@ -241,7 +253,6 @@ int jump_label_text_reserved(void *start, void *end) | |||
241 | struct jump_entry *iter_stop = __start___jump_table; | 253 | struct jump_entry *iter_stop = __start___jump_table; |
242 | int conflict = 0; | 254 | int conflict = 0; |
243 | 255 | ||
244 | mutex_lock(&jump_label_mutex); | ||
245 | iter = iter_start; | 256 | iter = iter_start; |
246 | while (iter < iter_stop) { | 257 | while (iter < iter_stop) { |
247 | if (addr_conflict(iter, start, end)) { | 258 | if (addr_conflict(iter, start, end)) { |
@@ -256,10 +267,16 @@ int jump_label_text_reserved(void *start, void *end) | |||
256 | conflict = module_conflict(start, end); | 267 | conflict = module_conflict(start, end); |
257 | #endif | 268 | #endif |
258 | out: | 269 | out: |
259 | mutex_unlock(&jump_label_mutex); | ||
260 | return conflict; | 270 | return conflict; |
261 | } | 271 | } |
262 | 272 | ||
273 | /* | ||
274 | * Not all archs need this. | ||
275 | */ | ||
276 | void __weak arch_jump_label_text_poke_early(jump_label_t addr) | ||
277 | { | ||
278 | } | ||
279 | |||
263 | static __init int init_jump_label(void) | 280 | static __init int init_jump_label(void) |
264 | { | 281 | { |
265 | int ret; | 282 | int ret; |
@@ -267,7 +284,7 @@ static __init int init_jump_label(void) | |||
267 | struct jump_entry *iter_stop = __stop___jump_table; | 284 | struct jump_entry *iter_stop = __stop___jump_table; |
268 | struct jump_entry *iter; | 285 | struct jump_entry *iter; |
269 | 286 | ||
270 | mutex_lock(&jump_label_mutex); | 287 | jump_label_lock(); |
271 | ret = build_jump_label_hashtable(__start___jump_table, | 288 | ret = build_jump_label_hashtable(__start___jump_table, |
272 | __stop___jump_table); | 289 | __stop___jump_table); |
273 | iter = iter_start; | 290 | iter = iter_start; |
@@ -275,7 +292,7 @@ static __init int init_jump_label(void) | |||
275 | arch_jump_label_text_poke_early(iter->code); | 292 | arch_jump_label_text_poke_early(iter->code); |
276 | iter++; | 293 | iter++; |
277 | } | 294 | } |
278 | mutex_unlock(&jump_label_mutex); | 295 | jump_label_unlock(); |
279 | return ret; | 296 | return ret; |
280 | } | 297 | } |
281 | early_initcall(init_jump_label); | 298 | early_initcall(init_jump_label); |
@@ -366,6 +383,39 @@ static void remove_jump_label_module(struct module *mod) | |||
366 | } | 383 | } |
367 | } | 384 | } |
368 | 385 | ||
386 | static void remove_jump_label_module_init(struct module *mod) | ||
387 | { | ||
388 | struct hlist_head *head; | ||
389 | struct hlist_node *node, *node_next, *module_node, *module_node_next; | ||
390 | struct jump_label_entry *e; | ||
391 | struct jump_label_module_entry *e_module; | ||
392 | struct jump_entry *iter; | ||
393 | int i, count; | ||
394 | |||
395 | /* if the module doesn't have jump label entries, just return */ | ||
396 | if (!mod->num_jump_entries) | ||
397 | return; | ||
398 | |||
399 | for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) { | ||
400 | head = &jump_label_table[i]; | ||
401 | hlist_for_each_entry_safe(e, node, node_next, head, hlist) { | ||
402 | hlist_for_each_entry_safe(e_module, module_node, | ||
403 | module_node_next, | ||
404 | &(e->modules), hlist) { | ||
405 | if (e_module->mod != mod) | ||
406 | continue; | ||
407 | count = e_module->nr_entries; | ||
408 | iter = e_module->table; | ||
409 | while (count--) { | ||
410 | if (within_module_init(iter->code, mod)) | ||
411 | iter->key = 0; | ||
412 | iter++; | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | |||
369 | static int | 419 | static int |
370 | jump_label_module_notify(struct notifier_block *self, unsigned long val, | 420 | jump_label_module_notify(struct notifier_block *self, unsigned long val, |
371 | void *data) | 421 | void *data) |
@@ -375,16 +425,21 @@ jump_label_module_notify(struct notifier_block *self, unsigned long val, | |||
375 | 425 | ||
376 | switch (val) { | 426 | switch (val) { |
377 | case MODULE_STATE_COMING: | 427 | case MODULE_STATE_COMING: |
378 | mutex_lock(&jump_label_mutex); | 428 | jump_label_lock(); |
379 | ret = add_jump_label_module(mod); | 429 | ret = add_jump_label_module(mod); |
380 | if (ret) | 430 | if (ret) |
381 | remove_jump_label_module(mod); | 431 | remove_jump_label_module(mod); |
382 | mutex_unlock(&jump_label_mutex); | 432 | jump_label_unlock(); |
383 | break; | 433 | break; |
384 | case MODULE_STATE_GOING: | 434 | case MODULE_STATE_GOING: |
385 | mutex_lock(&jump_label_mutex); | 435 | jump_label_lock(); |
386 | remove_jump_label_module(mod); | 436 | remove_jump_label_module(mod); |
387 | mutex_unlock(&jump_label_mutex); | 437 | jump_label_unlock(); |
438 | break; | ||
439 | case MODULE_STATE_LIVE: | ||
440 | jump_label_lock(); | ||
441 | remove_jump_label_module_init(mod); | ||
442 | jump_label_unlock(); | ||
388 | break; | 443 | break; |
389 | } | 444 | } |
390 | return ret; | 445 | return ret; |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 99865c33a60d..9737a76e106f 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -1145,14 +1145,13 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
1145 | if (ret) | 1145 | if (ret) |
1146 | return ret; | 1146 | return ret; |
1147 | 1147 | ||
1148 | jump_label_lock(); | ||
1148 | preempt_disable(); | 1149 | preempt_disable(); |
1149 | if (!kernel_text_address((unsigned long) p->addr) || | 1150 | if (!kernel_text_address((unsigned long) p->addr) || |
1150 | in_kprobes_functions((unsigned long) p->addr) || | 1151 | in_kprobes_functions((unsigned long) p->addr) || |
1151 | ftrace_text_reserved(p->addr, p->addr) || | 1152 | ftrace_text_reserved(p->addr, p->addr) || |
1152 | jump_label_text_reserved(p->addr, p->addr)) { | 1153 | jump_label_text_reserved(p->addr, p->addr)) |
1153 | preempt_enable(); | 1154 | goto fail_with_jump_label; |
1154 | return -EINVAL; | ||
1155 | } | ||
1156 | 1155 | ||
1157 | /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ | 1156 | /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ |
1158 | p->flags &= KPROBE_FLAG_DISABLED; | 1157 | p->flags &= KPROBE_FLAG_DISABLED; |
@@ -1166,10 +1165,9 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
1166 | * We must hold a refcount of the probed module while updating | 1165 | * We must hold a refcount of the probed module while updating |
1167 | * its code to prohibit unexpected unloading. | 1166 | * its code to prohibit unexpected unloading. |
1168 | */ | 1167 | */ |
1169 | if (unlikely(!try_module_get(probed_mod))) { | 1168 | if (unlikely(!try_module_get(probed_mod))) |
1170 | preempt_enable(); | 1169 | goto fail_with_jump_label; |
1171 | return -EINVAL; | 1170 | |
1172 | } | ||
1173 | /* | 1171 | /* |
1174 | * If the module freed .init.text, we couldn't insert | 1172 | * If the module freed .init.text, we couldn't insert |
1175 | * kprobes in there. | 1173 | * kprobes in there. |
@@ -1177,16 +1175,18 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
1177 | if (within_module_init((unsigned long)p->addr, probed_mod) && | 1175 | if (within_module_init((unsigned long)p->addr, probed_mod) && |
1178 | probed_mod->state != MODULE_STATE_COMING) { | 1176 | probed_mod->state != MODULE_STATE_COMING) { |
1179 | module_put(probed_mod); | 1177 | module_put(probed_mod); |
1180 | preempt_enable(); | 1178 | goto fail_with_jump_label; |
1181 | return -EINVAL; | ||
1182 | } | 1179 | } |
1183 | } | 1180 | } |
1184 | preempt_enable(); | 1181 | preempt_enable(); |
1182 | jump_label_unlock(); | ||
1185 | 1183 | ||
1186 | p->nmissed = 0; | 1184 | p->nmissed = 0; |
1187 | INIT_LIST_HEAD(&p->list); | 1185 | INIT_LIST_HEAD(&p->list); |
1188 | mutex_lock(&kprobe_mutex); | 1186 | mutex_lock(&kprobe_mutex); |
1189 | 1187 | ||
1188 | jump_label_lock(); /* needed to call jump_label_text_reserved() */ | ||
1189 | |||
1190 | get_online_cpus(); /* For avoiding text_mutex deadlock. */ | 1190 | get_online_cpus(); /* For avoiding text_mutex deadlock. */ |
1191 | mutex_lock(&text_mutex); | 1191 | mutex_lock(&text_mutex); |
1192 | 1192 | ||
@@ -1214,12 +1214,18 @@ int __kprobes register_kprobe(struct kprobe *p) | |||
1214 | out: | 1214 | out: |
1215 | mutex_unlock(&text_mutex); | 1215 | mutex_unlock(&text_mutex); |
1216 | put_online_cpus(); | 1216 | put_online_cpus(); |
1217 | jump_label_unlock(); | ||
1217 | mutex_unlock(&kprobe_mutex); | 1218 | mutex_unlock(&kprobe_mutex); |
1218 | 1219 | ||
1219 | if (probed_mod) | 1220 | if (probed_mod) |
1220 | module_put(probed_mod); | 1221 | module_put(probed_mod); |
1221 | 1222 | ||
1222 | return ret; | 1223 | return ret; |
1224 | |||
1225 | fail_with_jump_label: | ||
1226 | preempt_enable(); | ||
1227 | jump_label_unlock(); | ||
1228 | return -EINVAL; | ||
1223 | } | 1229 | } |
1224 | EXPORT_SYMBOL_GPL(register_kprobe); | 1230 | EXPORT_SYMBOL_GPL(register_kprobe); |
1225 | 1231 | ||