diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-06 23:20:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-06 23:20:46 -0500 |
commit | b32fc0a0629bf5894b35f33554c118aacfd0d1e2 (patch) | |
tree | 5d6aaa9a35b7fa63681adab91da3b3dec5276f84 | |
parent | 403299a8515c56db58454c57712f4dc96d6c1fde (diff) | |
parent | 97ce2c88f9ad42e3c60a9beb9fca87abf3639faa (diff) |
Merge branch 'upstream/jump-label-noearly' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen
* 'upstream/jump-label-noearly' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen:
jump-label: initialize jump-label subsystem much earlier
x86/jump_label: add arch_jump_label_transform_static()
s390/jump-label: add arch_jump_label_transform_static()
jump_label: add arch_jump_label_transform_static() to optimise non-live code updates
sparc/jump_label: drop arch_jump_label_text_poke_early()
x86/jump_label: drop arch_jump_label_text_poke_early()
jump_label: if a key has already been initialized, don't nop it out
stop_machine: make stop_machine safe and efficient to call early
jump_label: use proper atomic_t initializer
Conflicts:
- arch/x86/kernel/jump_label.c
Added __init_or_module to arch_jump_label_text_poke_early vs
removal of that function entirely
- kernel/stop_machine.c
same patch ("stop_machine: make stop_machine safe and efficient
to call early") merged twice, with whitespace fix in one version
-rw-r--r-- | arch/s390/kernel/jump_label.c | 51 | ||||
-rw-r--r-- | arch/sparc/kernel/jump_label.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/jump_label.c | 20 | ||||
-rw-r--r-- | include/linux/jump_label.h | 23 | ||||
-rw-r--r-- | init/main.c | 3 | ||||
-rw-r--r-- | kernel/jump_label.c | 37 |
6 files changed, 83 insertions, 59 deletions
diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c index 44cc06bedf77..b987ab2c1541 100644 --- a/arch/s390/kernel/jump_label.c +++ b/arch/s390/kernel/jump_label.c | |||
@@ -18,26 +18,15 @@ struct insn { | |||
18 | } __packed; | 18 | } __packed; |
19 | 19 | ||
20 | struct insn_args { | 20 | struct insn_args { |
21 | unsigned long *target; | 21 | struct jump_entry *entry; |
22 | struct insn *insn; | 22 | enum jump_label_type type; |
23 | ssize_t size; | ||
24 | }; | 23 | }; |
25 | 24 | ||
26 | static int __arch_jump_label_transform(void *data) | 25 | static void __jump_label_transform(struct jump_entry *entry, |
26 | enum jump_label_type type) | ||
27 | { | 27 | { |
28 | struct insn_args *args = data; | ||
29 | int rc; | ||
30 | |||
31 | rc = probe_kernel_write(args->target, args->insn, args->size); | ||
32 | WARN_ON_ONCE(rc < 0); | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | void arch_jump_label_transform(struct jump_entry *entry, | ||
37 | enum jump_label_type type) | ||
38 | { | ||
39 | struct insn_args args; | ||
40 | struct insn insn; | 28 | struct insn insn; |
29 | int rc; | ||
41 | 30 | ||
42 | if (type == JUMP_LABEL_ENABLE) { | 31 | if (type == JUMP_LABEL_ENABLE) { |
43 | /* brcl 15,offset */ | 32 | /* brcl 15,offset */ |
@@ -49,11 +38,33 @@ void arch_jump_label_transform(struct jump_entry *entry, | |||
49 | insn.offset = 0; | 38 | insn.offset = 0; |
50 | } | 39 | } |
51 | 40 | ||
52 | args.target = (void *) entry->code; | 41 | rc = probe_kernel_write((void *)entry->code, &insn, JUMP_LABEL_NOP_SIZE); |
53 | args.insn = &insn; | 42 | WARN_ON_ONCE(rc < 0); |
54 | args.size = JUMP_LABEL_NOP_SIZE; | 43 | } |
55 | 44 | ||
56 | stop_machine(__arch_jump_label_transform, &args, NULL); | 45 | static int __sm_arch_jump_label_transform(void *data) |
46 | { | ||
47 | struct insn_args *args = data; | ||
48 | |||
49 | __jump_label_transform(args->entry, args->type); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | void arch_jump_label_transform(struct jump_entry *entry, | ||
54 | enum jump_label_type type) | ||
55 | { | ||
56 | struct insn_args args; | ||
57 | |||
58 | args.entry = entry; | ||
59 | args.type = type; | ||
60 | |||
61 | stop_machine(__sm_arch_jump_label_transform, &args, NULL); | ||
62 | } | ||
63 | |||
64 | void arch_jump_label_transform_static(struct jump_entry *entry, | ||
65 | enum jump_label_type type) | ||
66 | { | ||
67 | __jump_label_transform(entry, type); | ||
57 | } | 68 | } |
58 | 69 | ||
59 | #endif | 70 | #endif |
diff --git a/arch/sparc/kernel/jump_label.c b/arch/sparc/kernel/jump_label.c index ea2dafc93d78..971fd435a281 100644 --- a/arch/sparc/kernel/jump_label.c +++ b/arch/sparc/kernel/jump_label.c | |||
@@ -36,12 +36,4 @@ void arch_jump_label_transform(struct jump_entry *entry, | |||
36 | put_online_cpus(); | 36 | put_online_cpus(); |
37 | } | 37 | } |
38 | 38 | ||
39 | void arch_jump_label_text_poke_early(jump_label_t addr) | ||
40 | { | ||
41 | u32 *insn_p = (u32 *) (unsigned long) addr; | ||
42 | |||
43 | *insn_p = 0x01000000; | ||
44 | flushi(insn_p); | ||
45 | } | ||
46 | |||
47 | #endif | 39 | #endif |
diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c index cacdd46d184d..ea9d5f2f13ef 100644 --- a/arch/x86/kernel/jump_label.c +++ b/arch/x86/kernel/jump_label.c | |||
@@ -24,8 +24,9 @@ union jump_code_union { | |||
24 | } __attribute__((packed)); | 24 | } __attribute__((packed)); |
25 | }; | 25 | }; |
26 | 26 | ||
27 | void arch_jump_label_transform(struct jump_entry *entry, | 27 | static void __jump_label_transform(struct jump_entry *entry, |
28 | enum jump_label_type type) | 28 | enum jump_label_type type, |
29 | void *(*poker)(void *, const void *, size_t)) | ||
29 | { | 30 | { |
30 | union jump_code_union code; | 31 | union jump_code_union code; |
31 | 32 | ||
@@ -35,17 +36,24 @@ void arch_jump_label_transform(struct jump_entry *entry, | |||
35 | (entry->code + JUMP_LABEL_NOP_SIZE); | 36 | (entry->code + JUMP_LABEL_NOP_SIZE); |
36 | } else | 37 | } else |
37 | memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); | 38 | memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); |
39 | |||
40 | (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE); | ||
41 | } | ||
42 | |||
43 | void arch_jump_label_transform(struct jump_entry *entry, | ||
44 | enum jump_label_type type) | ||
45 | { | ||
38 | get_online_cpus(); | 46 | get_online_cpus(); |
39 | mutex_lock(&text_mutex); | 47 | mutex_lock(&text_mutex); |
40 | text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE); | 48 | __jump_label_transform(entry, type, text_poke_smp); |
41 | mutex_unlock(&text_mutex); | 49 | mutex_unlock(&text_mutex); |
42 | put_online_cpus(); | 50 | put_online_cpus(); |
43 | } | 51 | } |
44 | 52 | ||
45 | void __init_or_module arch_jump_label_text_poke_early(jump_label_t addr) | 53 | void arch_jump_label_transform_static(struct jump_entry *entry, |
54 | enum jump_label_type type) | ||
46 | { | 55 | { |
47 | text_poke_early((void *)addr, ideal_nops[NOP_ATOMIC5], | 56 | __jump_label_transform(entry, type, text_poke_early); |
48 | JUMP_LABEL_NOP_SIZE); | ||
49 | } | 57 | } |
50 | 58 | ||
51 | #endif | 59 | #endif |
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index 66f23dc5e76a..388b0d425b50 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h | |||
@@ -16,7 +16,7 @@ struct jump_label_key { | |||
16 | 16 | ||
17 | # include <asm/jump_label.h> | 17 | # include <asm/jump_label.h> |
18 | # define HAVE_JUMP_LABEL | 18 | # define HAVE_JUMP_LABEL |
19 | #endif | 19 | #endif /* CC_HAVE_ASM_GOTO && CONFIG_JUMP_LABEL */ |
20 | 20 | ||
21 | enum jump_label_type { | 21 | enum jump_label_type { |
22 | JUMP_LABEL_DISABLE = 0, | 22 | JUMP_LABEL_DISABLE = 0, |
@@ -28,9 +28,9 @@ struct module; | |||
28 | #ifdef HAVE_JUMP_LABEL | 28 | #ifdef HAVE_JUMP_LABEL |
29 | 29 | ||
30 | #ifdef CONFIG_MODULES | 30 | #ifdef CONFIG_MODULES |
31 | #define JUMP_LABEL_INIT {{ 0 }, NULL, NULL} | 31 | #define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL, NULL} |
32 | #else | 32 | #else |
33 | #define JUMP_LABEL_INIT {{ 0 }, NULL} | 33 | #define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL} |
34 | #endif | 34 | #endif |
35 | 35 | ||
36 | static __always_inline bool static_branch(struct jump_label_key *key) | 36 | static __always_inline bool static_branch(struct jump_label_key *key) |
@@ -41,18 +41,20 @@ static __always_inline bool static_branch(struct jump_label_key *key) | |||
41 | extern struct jump_entry __start___jump_table[]; | 41 | extern struct jump_entry __start___jump_table[]; |
42 | extern struct jump_entry __stop___jump_table[]; | 42 | extern struct jump_entry __stop___jump_table[]; |
43 | 43 | ||
44 | extern void jump_label_init(void); | ||
44 | extern void jump_label_lock(void); | 45 | extern void jump_label_lock(void); |
45 | extern void jump_label_unlock(void); | 46 | extern void jump_label_unlock(void); |
46 | extern void arch_jump_label_transform(struct jump_entry *entry, | 47 | extern void arch_jump_label_transform(struct jump_entry *entry, |
47 | enum jump_label_type type); | 48 | enum jump_label_type type); |
48 | extern void arch_jump_label_text_poke_early(jump_label_t addr); | 49 | extern void arch_jump_label_transform_static(struct jump_entry *entry, |
50 | enum jump_label_type type); | ||
49 | extern int jump_label_text_reserved(void *start, void *end); | 51 | extern int jump_label_text_reserved(void *start, void *end); |
50 | extern void jump_label_inc(struct jump_label_key *key); | 52 | extern void jump_label_inc(struct jump_label_key *key); |
51 | extern void jump_label_dec(struct jump_label_key *key); | 53 | extern void jump_label_dec(struct jump_label_key *key); |
52 | extern bool jump_label_enabled(struct jump_label_key *key); | 54 | extern bool jump_label_enabled(struct jump_label_key *key); |
53 | extern void jump_label_apply_nops(struct module *mod); | 55 | extern void jump_label_apply_nops(struct module *mod); |
54 | 56 | ||
55 | #else | 57 | #else /* !HAVE_JUMP_LABEL */ |
56 | 58 | ||
57 | #include <linux/atomic.h> | 59 | #include <linux/atomic.h> |
58 | 60 | ||
@@ -62,6 +64,10 @@ struct jump_label_key { | |||
62 | atomic_t enabled; | 64 | atomic_t enabled; |
63 | }; | 65 | }; |
64 | 66 | ||
67 | static __always_inline void jump_label_init(void) | ||
68 | { | ||
69 | } | ||
70 | |||
65 | static __always_inline bool static_branch(struct jump_label_key *key) | 71 | static __always_inline bool static_branch(struct jump_label_key *key) |
66 | { | 72 | { |
67 | if (unlikely(atomic_read(&key->enabled))) | 73 | if (unlikely(atomic_read(&key->enabled))) |
@@ -96,7 +102,6 @@ static inline int jump_label_apply_nops(struct module *mod) | |||
96 | { | 102 | { |
97 | return 0; | 103 | return 0; |
98 | } | 104 | } |
105 | #endif /* HAVE_JUMP_LABEL */ | ||
99 | 106 | ||
100 | #endif | 107 | #endif /* _LINUX_JUMP_LABEL_H */ |
101 | |||
102 | #endif | ||
diff --git a/init/main.c b/init/main.c index 63f5f6f8dc3b..217ed23e9487 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -512,6 +512,9 @@ asmlinkage void __init start_kernel(void) | |||
512 | parse_args("Booting kernel", static_command_line, __start___param, | 512 | parse_args("Booting kernel", static_command_line, __start___param, |
513 | __stop___param - __start___param, | 513 | __stop___param - __start___param, |
514 | &unknown_bootoption); | 514 | &unknown_bootoption); |
515 | |||
516 | jump_label_init(); | ||
517 | |||
515 | /* | 518 | /* |
516 | * These use large bootmem allocations and must precede | 519 | * These use large bootmem allocations and must precede |
517 | * kmem_cache_init() | 520 | * kmem_cache_init() |
diff --git a/kernel/jump_label.c b/kernel/jump_label.c index a8ce45097f3d..bbdfe2a462a0 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c | |||
@@ -104,6 +104,18 @@ static int __jump_label_text_reserved(struct jump_entry *iter_start, | |||
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | 106 | ||
107 | /* | ||
108 | * Update code which is definitely not currently executing. | ||
109 | * Architectures which need heavyweight synchronization to modify | ||
110 | * running code can override this to make the non-live update case | ||
111 | * cheaper. | ||
112 | */ | ||
113 | void __weak arch_jump_label_transform_static(struct jump_entry *entry, | ||
114 | enum jump_label_type type) | ||
115 | { | ||
116 | arch_jump_label_transform(entry, type); | ||
117 | } | ||
118 | |||
107 | static void __jump_label_update(struct jump_label_key *key, | 119 | static void __jump_label_update(struct jump_label_key *key, |
108 | struct jump_entry *entry, | 120 | struct jump_entry *entry, |
109 | struct jump_entry *stop, int enable) | 121 | struct jump_entry *stop, int enable) |
@@ -121,14 +133,7 @@ static void __jump_label_update(struct jump_label_key *key, | |||
121 | } | 133 | } |
122 | } | 134 | } |
123 | 135 | ||
124 | /* | 136 | void __init jump_label_init(void) |
125 | * Not all archs need this. | ||
126 | */ | ||
127 | void __weak arch_jump_label_text_poke_early(jump_label_t addr) | ||
128 | { | ||
129 | } | ||
130 | |||
131 | static __init int jump_label_init(void) | ||
132 | { | 137 | { |
133 | struct jump_entry *iter_start = __start___jump_table; | 138 | struct jump_entry *iter_start = __start___jump_table; |
134 | struct jump_entry *iter_stop = __stop___jump_table; | 139 | struct jump_entry *iter_stop = __stop___jump_table; |
@@ -139,22 +144,22 @@ static __init int jump_label_init(void) | |||
139 | jump_label_sort_entries(iter_start, iter_stop); | 144 | jump_label_sort_entries(iter_start, iter_stop); |
140 | 145 | ||
141 | for (iter = iter_start; iter < iter_stop; iter++) { | 146 | for (iter = iter_start; iter < iter_stop; iter++) { |
142 | arch_jump_label_text_poke_early(iter->code); | 147 | struct jump_label_key *iterk; |
143 | if (iter->key == (jump_label_t)(unsigned long)key) | 148 | |
149 | iterk = (struct jump_label_key *)(unsigned long)iter->key; | ||
150 | arch_jump_label_transform_static(iter, jump_label_enabled(iterk) ? | ||
151 | JUMP_LABEL_ENABLE : JUMP_LABEL_DISABLE); | ||
152 | if (iterk == key) | ||
144 | continue; | 153 | continue; |
145 | 154 | ||
146 | key = (struct jump_label_key *)(unsigned long)iter->key; | 155 | key = iterk; |
147 | atomic_set(&key->enabled, 0); | ||
148 | key->entries = iter; | 156 | key->entries = iter; |
149 | #ifdef CONFIG_MODULES | 157 | #ifdef CONFIG_MODULES |
150 | key->next = NULL; | 158 | key->next = NULL; |
151 | #endif | 159 | #endif |
152 | } | 160 | } |
153 | jump_label_unlock(); | 161 | jump_label_unlock(); |
154 | |||
155 | return 0; | ||
156 | } | 162 | } |
157 | early_initcall(jump_label_init); | ||
158 | 163 | ||
159 | #ifdef CONFIG_MODULES | 164 | #ifdef CONFIG_MODULES |
160 | 165 | ||
@@ -212,7 +217,7 @@ void jump_label_apply_nops(struct module *mod) | |||
212 | return; | 217 | return; |
213 | 218 | ||
214 | for (iter = iter_start; iter < iter_stop; iter++) | 219 | for (iter = iter_start; iter < iter_stop; iter++) |
215 | arch_jump_label_text_poke_early(iter->code); | 220 | arch_jump_label_transform_static(iter, JUMP_LABEL_DISABLE); |
216 | } | 221 | } |
217 | 222 | ||
218 | static int jump_label_add_module(struct module *mod) | 223 | static int jump_label_add_module(struct module *mod) |