aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2015-07-24 09:09:55 -0400
committerIngo Molnar <mingo@kernel.org>2015-08-03 05:34:15 -0400
commit11276d5306b8e5b438a36bbff855fe792d7eaa61 (patch)
tree9ddfc5e1bec6174e838cce8eb67af9e911c4e5f8
parent706249c222f68471b6f8e9e8e9b77665c404b226 (diff)
locking/static_keys: Add a new static_key interface
There are various problems and short-comings with the current static_key interface: - static_key_{true,false}() read like a branch depending on the key value, instead of the actual likely/unlikely branch depending on init value. - static_key_{true,false}() are, as stated above, tied to the static_key init values STATIC_KEY_INIT_{TRUE,FALSE}. - we're limited to the 2 (out of 4) possible options that compile to a default NOP because that's what our arch_static_branch() assembly emits. So provide a new static_key interface: DEFINE_STATIC_KEY_TRUE(name); DEFINE_STATIC_KEY_FALSE(name); Which define a key of different types with an initial true/false value. Then allow: static_branch_likely() static_branch_unlikely() to take a key of either type and emit the right instruction for the case. This means adding a second arch_static_branch_jump() assembly helper which emits a JMP per default. In order to determine the right instruction for the right state, encode the branch type in the LSB of jump_entry::key. This is the final step in removing the naming confusion that has led to a stream of avoidable bugs such as: a833581e372a ("x86, perf: Fix static_key bug in load_mm_cr4()") ... but it also allows new static key combinations that will give us performance enhancements in the subsequent patches. Tested-by: Rabin Vincent <rabin@rab.in> # arm Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Michael Ellerman <mpe@ellerman.id.au> # ppc Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com> # s390 Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/arm/include/asm/jump_label.h25
-rw-r--r--arch/arm64/include/asm/jump_label.h18
-rw-r--r--arch/mips/include/asm/jump_label.h19
-rw-r--r--arch/powerpc/include/asm/jump_label.h19
-rw-r--r--arch/s390/include/asm/jump_label.h19
-rw-r--r--arch/sparc/include/asm/jump_label.h35
-rw-r--r--arch/x86/include/asm/jump_label.h21
-rw-r--r--include/linux/jump_label.h149
-rw-r--r--kernel/jump_label.c37
9 files changed, 298 insertions, 44 deletions
diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h
index 5f337dc5c108..34f7b6980d21 100644
--- a/arch/arm/include/asm/jump_label.h
+++ b/arch/arm/include/asm/jump_label.h
@@ -4,23 +4,32 @@
4#ifndef __ASSEMBLY__ 4#ifndef __ASSEMBLY__
5 5
6#include <linux/types.h> 6#include <linux/types.h>
7#include <asm/unified.h>
7 8
8#define JUMP_LABEL_NOP_SIZE 4 9#define JUMP_LABEL_NOP_SIZE 4
9 10
10#ifdef CONFIG_THUMB2_KERNEL 11static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
11#define JUMP_LABEL_NOP "nop.w" 12{
12#else 13 asm_volatile_goto("1:\n\t"
13#define JUMP_LABEL_NOP "nop" 14 WASM(nop) "\n\t"
14#endif 15 ".pushsection __jump_table, \"aw\"\n\t"
16 ".word 1b, %l[l_yes], %c0\n\t"
17 ".popsection\n\t"
18 : : "i" (&((char *)key)[branch]) : : l_yes);
19
20 return false;
21l_yes:
22 return true;
23}
15 24
16static __always_inline bool arch_static_branch(struct static_key *key) 25static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
17{ 26{
18 asm_volatile_goto("1:\n\t" 27 asm_volatile_goto("1:\n\t"
19 JUMP_LABEL_NOP "\n\t" 28 WASM(b) " %l[l_yes]\n\t"
20 ".pushsection __jump_table, \"aw\"\n\t" 29 ".pushsection __jump_table, \"aw\"\n\t"
21 ".word 1b, %l[l_yes], %c0\n\t" 30 ".word 1b, %l[l_yes], %c0\n\t"
22 ".popsection\n\t" 31 ".popsection\n\t"
23 : : "i" (key) : : l_yes); 32 : : "i" (&((char *)key)[branch]) : : l_yes);
24 33
25 return false; 34 return false;
26l_yes: 35l_yes:
diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h
index c0e5165c2f76..1b5e0e843c3a 100644
--- a/arch/arm64/include/asm/jump_label.h
+++ b/arch/arm64/include/asm/jump_label.h
@@ -26,14 +26,28 @@
26 26
27#define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE 27#define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE
28 28
29static __always_inline bool arch_static_branch(struct static_key *key) 29static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
30{ 30{
31 asm goto("1: nop\n\t" 31 asm goto("1: nop\n\t"
32 ".pushsection __jump_table, \"aw\"\n\t" 32 ".pushsection __jump_table, \"aw\"\n\t"
33 ".align 3\n\t" 33 ".align 3\n\t"
34 ".quad 1b, %l[l_yes], %c0\n\t" 34 ".quad 1b, %l[l_yes], %c0\n\t"
35 ".popsection\n\t" 35 ".popsection\n\t"
36 : : "i"(key) : : l_yes); 36 : : "i"(&((char *)key)[branch]) : : l_yes);
37
38 return false;
39l_yes:
40 return true;
41}
42
43static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
44{
45 asm goto("1: b %l[l_yes]\n\t"
46 ".pushsection __jump_table, \"aw\"\n\t"
47 ".align 3\n\t"
48 ".quad 1b, %l[l_yes], %c0\n\t"
49 ".popsection\n\t"
50 : : "i"(&((char *)key)[branch]) : : l_yes);
37 51
38 return false; 52 return false;
39l_yes: 53l_yes:
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h
index 608aa57799c8..e77672539e8e 100644
--- a/arch/mips/include/asm/jump_label.h
+++ b/arch/mips/include/asm/jump_label.h
@@ -26,14 +26,29 @@
26#define NOP_INSN "nop" 26#define NOP_INSN "nop"
27#endif 27#endif
28 28
29static __always_inline bool arch_static_branch(struct static_key *key) 29static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
30{ 30{
31 asm_volatile_goto("1:\t" NOP_INSN "\n\t" 31 asm_volatile_goto("1:\t" NOP_INSN "\n\t"
32 "nop\n\t" 32 "nop\n\t"
33 ".pushsection __jump_table, \"aw\"\n\t" 33 ".pushsection __jump_table, \"aw\"\n\t"
34 WORD_INSN " 1b, %l[l_yes], %0\n\t" 34 WORD_INSN " 1b, %l[l_yes], %0\n\t"
35 ".popsection\n\t" 35 ".popsection\n\t"
36 : : "i" (key) : : l_yes); 36 : : "i" (&((char *)key)[branch]) : : l_yes);
37
38 return false;
39l_yes:
40 return true;
41}
42
43static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
44{
45 asm_volatile_goto("1:\tj %l[l_yes]\n\t"
46 "nop\n\t"
47 ".pushsection __jump_table, \"aw\"\n\t"
48 WORD_INSN " 1b, %l[l_yes], %0\n\t"
49 ".popsection\n\t"
50 : : "i" (&((char *)key)[branch]) : : l_yes);
51
37 return false; 52 return false;
38l_yes: 53l_yes:
39 return true; 54 return true;
diff --git a/arch/powerpc/include/asm/jump_label.h b/arch/powerpc/include/asm/jump_label.h
index efbf9a322a23..47e155f15433 100644
--- a/arch/powerpc/include/asm/jump_label.h
+++ b/arch/powerpc/include/asm/jump_label.h
@@ -18,14 +18,29 @@
18#define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG) 18#define JUMP_ENTRY_TYPE stringify_in_c(FTR_ENTRY_LONG)
19#define JUMP_LABEL_NOP_SIZE 4 19#define JUMP_LABEL_NOP_SIZE 4
20 20
21static __always_inline bool arch_static_branch(struct static_key *key) 21static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
22{ 22{
23 asm_volatile_goto("1:\n\t" 23 asm_volatile_goto("1:\n\t"
24 "nop\n\t" 24 "nop\n\t"
25 ".pushsection __jump_table, \"aw\"\n\t" 25 ".pushsection __jump_table, \"aw\"\n\t"
26 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t" 26 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
27 ".popsection \n\t" 27 ".popsection \n\t"
28 : : "i" (key) : : l_yes); 28 : : "i" (&((char *)key)[branch]) : : l_yes);
29
30 return false;
31l_yes:
32 return true;
33}
34
35static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
36{
37 asm_volatile_goto("1:\n\t"
38 "b %l[l_yes]\n\t"
39 ".pushsection __jump_table, \"aw\"\n\t"
40 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
41 ".popsection \n\t"
42 : : "i" (&((char *)key)[branch]) : : l_yes);
43
29 return false; 44 return false;
30l_yes: 45l_yes:
31 return true; 46 return true;
diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h
index 69972b7957ee..7f9fd5e3f1bf 100644
--- a/arch/s390/include/asm/jump_label.h
+++ b/arch/s390/include/asm/jump_label.h
@@ -12,14 +12,29 @@
12 * We use a brcl 0,2 instruction for jump labels at compile time so it 12 * We use a brcl 0,2 instruction for jump labels at compile time so it
13 * can be easily distinguished from a hotpatch generated instruction. 13 * can be easily distinguished from a hotpatch generated instruction.
14 */ 14 */
15static __always_inline bool arch_static_branch(struct static_key *key) 15static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
16{ 16{
17 asm_volatile_goto("0: brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n" 17 asm_volatile_goto("0: brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n"
18 ".pushsection __jump_table, \"aw\"\n" 18 ".pushsection __jump_table, \"aw\"\n"
19 ".balign 8\n" 19 ".balign 8\n"
20 ".quad 0b, %l[label], %0\n" 20 ".quad 0b, %l[label], %0\n"
21 ".popsection\n" 21 ".popsection\n"
22 : : "X" (key) : : label); 22 : : "X" (&((char *)key)[branch]) : : label);
23
24 return false;
25label:
26 return true;
27}
28
29static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
30{
31 asm_volatile_goto("0: brcl 15, %l[label]\n"
32 ".pushsection __jump_table, \"aw\"\n"
33 ".balign 8\n"
34 ".quad 0b, %l[label], %0\n"
35 ".popsection\n"
36 : : "X" (&((char *)key)[branch]) : : label);
37
23 return false; 38 return false;
24label: 39label:
25 return true; 40 return true;
diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h
index cc9b04a2b11b..62d0354d1727 100644
--- a/arch/sparc/include/asm/jump_label.h
+++ b/arch/sparc/include/asm/jump_label.h
@@ -7,16 +7,33 @@
7 7
8#define JUMP_LABEL_NOP_SIZE 4 8#define JUMP_LABEL_NOP_SIZE 4
9 9
10static __always_inline bool arch_static_branch(struct static_key *key) 10static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
11{ 11{
12 asm_volatile_goto("1:\n\t" 12 asm_volatile_goto("1:\n\t"
13 "nop\n\t" 13 "nop\n\t"
14 "nop\n\t" 14 "nop\n\t"
15 ".pushsection __jump_table, \"aw\"\n\t" 15 ".pushsection __jump_table, \"aw\"\n\t"
16 ".align 4\n\t" 16 ".align 4\n\t"
17 ".word 1b, %l[l_yes], %c0\n\t" 17 ".word 1b, %l[l_yes], %c0\n\t"
18 ".popsection \n\t" 18 ".popsection \n\t"
19 : : "i" (key) : : l_yes); 19 : : "i" (&((char *)key)[branch]) : : l_yes);
20
21 return false;
22l_yes:
23 return true;
24}
25
26static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
27{
28 asm_volatile_goto("1:\n\t"
29 "b %l[l_yes]\n\t"
30 "nop\n\t"
31 ".pushsection __jump_table, \"aw\"\n\t"
32 ".align 4\n\t"
33 ".word 1b, %l[l_yes], %c0\n\t"
34 ".popsection \n\t"
35 : : "i" (&((char *)key)[branch]) : : l_yes);
36
20 return false; 37 return false;
21l_yes: 38l_yes:
22 return true; 39 return true;
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index a4c1cf7e93f8..28d7a857f9d1 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -16,7 +16,7 @@
16# define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC 16# define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC
17#endif 17#endif
18 18
19static __always_inline bool arch_static_branch(struct static_key *key) 19static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
20{ 20{
21 asm_volatile_goto("1:" 21 asm_volatile_goto("1:"
22 ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t" 22 ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t"
@@ -24,7 +24,24 @@ static __always_inline bool arch_static_branch(struct static_key *key)
24 _ASM_ALIGN "\n\t" 24 _ASM_ALIGN "\n\t"
25 _ASM_PTR "1b, %l[l_yes], %c0 \n\t" 25 _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
26 ".popsection \n\t" 26 ".popsection \n\t"
27 : : "i" (key) : : l_yes); 27 : : "i" (&((char *)key)[branch]) : : l_yes);
28
29 return false;
30l_yes:
31 return true;
32}
33
34static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
35{
36 asm_volatile_goto("1:"
37 ".byte 0xe9\n\t .long %l[l_yes] - 2f\n\t"
38 "2:\n\t"
39 ".pushsection __jump_table, \"aw\" \n\t"
40 _ASM_ALIGN "\n\t"
41 _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
42 ".popsection \n\t"
43 : : "i" (&((char *)key)[branch]) : : l_yes);
44
28 return false; 45 return false;
29l_yes: 46l_yes:
30 return true; 47 return true;
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
index 65f0ebac63cf..e337a1961933 100644
--- a/include/linux/jump_label.h
+++ b/include/linux/jump_label.h
@@ -107,12 +107,12 @@ static inline int static_key_count(struct static_key *key)
107 107
108static __always_inline bool static_key_false(struct static_key *key) 108static __always_inline bool static_key_false(struct static_key *key)
109{ 109{
110 return arch_static_branch(key); 110 return arch_static_branch(key, false);
111} 111}
112 112
113static __always_inline bool static_key_true(struct static_key *key) 113static __always_inline bool static_key_true(struct static_key *key)
114{ 114{
115 return !static_key_false(key); 115 return !arch_static_branch(key, true);
116} 116}
117 117
118extern struct jump_entry __start___jump_table[]; 118extern struct jump_entry __start___jump_table[];
@@ -130,12 +130,12 @@ extern void static_key_slow_inc(struct static_key *key);
130extern void static_key_slow_dec(struct static_key *key); 130extern void static_key_slow_dec(struct static_key *key);
131extern void jump_label_apply_nops(struct module *mod); 131extern void jump_label_apply_nops(struct module *mod);
132 132
133#define STATIC_KEY_INIT_TRUE ((struct static_key) \ 133#define STATIC_KEY_INIT_TRUE \
134 { .enabled = ATOMIC_INIT(1), \ 134 { .enabled = ATOMIC_INIT(1), \
135 .entries = (void *)JUMP_TYPE_TRUE }) 135 .entries = (void *)JUMP_TYPE_TRUE }
136#define STATIC_KEY_INIT_FALSE ((struct static_key) \ 136#define STATIC_KEY_INIT_FALSE \
137 { .enabled = ATOMIC_INIT(0), \ 137 { .enabled = ATOMIC_INIT(0), \
138 .entries = (void *)JUMP_TYPE_FALSE }) 138 .entries = (void *)JUMP_TYPE_FALSE }
139 139
140#else /* !HAVE_JUMP_LABEL */ 140#else /* !HAVE_JUMP_LABEL */
141 141
@@ -183,10 +183,8 @@ static inline int jump_label_apply_nops(struct module *mod)
183 return 0; 183 return 0;
184} 184}
185 185
186#define STATIC_KEY_INIT_TRUE ((struct static_key) \ 186#define STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) }
187 { .enabled = ATOMIC_INIT(1) }) 187#define STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) }
188#define STATIC_KEY_INIT_FALSE ((struct static_key) \
189 { .enabled = ATOMIC_INIT(0) })
190 188
191#endif /* HAVE_JUMP_LABEL */ 189#endif /* HAVE_JUMP_LABEL */
192 190
@@ -218,6 +216,137 @@ static inline void static_key_disable(struct static_key *key)
218 static_key_slow_dec(key); 216 static_key_slow_dec(key);
219} 217}
220 218
219/* -------------------------------------------------------------------------- */
220
221/*
222 * Two type wrappers around static_key, such that we can use compile time
223 * type differentiation to emit the right code.
224 *
225 * All the below code is macros in order to play type games.
226 */
227
228struct static_key_true {
229 struct static_key key;
230};
231
232struct static_key_false {
233 struct static_key key;
234};
235
236#define STATIC_KEY_TRUE_INIT (struct static_key_true) { .key = STATIC_KEY_INIT_TRUE, }
237#define STATIC_KEY_FALSE_INIT (struct static_key_false){ .key = STATIC_KEY_INIT_FALSE, }
238
239#define DEFINE_STATIC_KEY_TRUE(name) \
240 struct static_key_true name = STATIC_KEY_TRUE_INIT
241
242#define DEFINE_STATIC_KEY_FALSE(name) \
243 struct static_key_false name = STATIC_KEY_FALSE_INIT
244
245#ifdef HAVE_JUMP_LABEL
246
247/*
248 * Combine the right initial value (type) with the right branch order
249 * to generate the desired result.
250 *
251 *
252 * type\branch| likely (1) | unlikely (0)
253 * -----------+-----------------------+------------------
254 * | |
255 * true (1) | ... | ...
256 * | NOP | JMP L
257 * | <br-stmts> | 1: ...
258 * | L: ... |
259 * | |
260 * | | L: <br-stmts>
261 * | | jmp 1b
262 * | |
263 * -----------+-----------------------+------------------
264 * | |
265 * false (0) | ... | ...
266 * | JMP L | NOP
267 * | <br-stmts> | 1: ...
268 * | L: ... |
269 * | |
270 * | | L: <br-stmts>
271 * | | jmp 1b
272 * | |
273 * -----------+-----------------------+------------------
274 *
275 * The initial value is encoded in the LSB of static_key::entries,
276 * type: 0 = false, 1 = true.
277 *
278 * The branch type is encoded in the LSB of jump_entry::key,
279 * branch: 0 = unlikely, 1 = likely.
280 *
281 * This gives the following logic table:
282 *
283 * enabled type branch instuction
284 * -----------------------------+-----------
285 * 0 0 0 | NOP
286 * 0 0 1 | JMP
287 * 0 1 0 | NOP
288 * 0 1 1 | JMP
289 *
290 * 1 0 0 | JMP
291 * 1 0 1 | NOP
292 * 1 1 0 | JMP
293 * 1 1 1 | NOP
294 *
295 * Which gives the following functions:
296 *
297 * dynamic: instruction = enabled ^ branch
298 * static: instruction = type ^ branch
299 *
300 * See jump_label_type() / jump_label_init_type().
301 */
302
303extern bool ____wrong_branch_error(void);
304
305#define static_branch_likely(x) \
306({ \
307 bool branch; \
308 if (__builtin_types_compatible_p(typeof(*x), struct static_key_true)) \
309 branch = !arch_static_branch(&(x)->key, true); \
310 else if (__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \
311 branch = !arch_static_branch_jump(&(x)->key, true); \
312 else \
313 branch = ____wrong_branch_error(); \
314 branch; \
315})
316
317#define static_branch_unlikely(x) \
318({ \
319 bool branch; \
320 if (__builtin_types_compatible_p(typeof(*x), struct static_key_true)) \
321 branch = arch_static_branch_jump(&(x)->key, false); \
322 else if (__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \
323 branch = arch_static_branch(&(x)->key, false); \
324 else \
325 branch = ____wrong_branch_error(); \
326 branch; \
327})
328
329#else /* !HAVE_JUMP_LABEL */
330
331#define static_branch_likely(x) likely(static_key_enabled(&(x)->key))
332#define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key))
333
334#endif /* HAVE_JUMP_LABEL */
335
336/*
337 * Advanced usage; refcount, branch is enabled when: count != 0
338 */
339
340#define static_branch_inc(x) static_key_slow_inc(&(x)->key)
341#define static_branch_dec(x) static_key_slow_dec(&(x)->key)
342
343/*
344 * Normal usage; boolean enable/disable.
345 */
346
347#define static_branch_enable(x) static_key_enable(&(x)->key)
348#define static_branch_disable(x) static_key_disable(&(x)->key)
349
221#endif /* _LINUX_JUMP_LABEL_H */ 350#endif /* _LINUX_JUMP_LABEL_H */
222 351
223#endif /* __ASSEMBLY__ */ 352#endif /* __ASSEMBLY__ */
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index 2e7cc1e4b4b5..8fd00d892286 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -165,16 +165,22 @@ static inline bool static_key_type(struct static_key *key)
165 165
166static inline struct static_key *jump_entry_key(struct jump_entry *entry) 166static inline struct static_key *jump_entry_key(struct jump_entry *entry)
167{ 167{
168 return (struct static_key *)((unsigned long)entry->key); 168 return (struct static_key *)((unsigned long)entry->key & ~1UL);
169}
170
171static bool jump_entry_branch(struct jump_entry *entry)
172{
173 return (unsigned long)entry->key & 1UL;
169} 174}
170 175
171static enum jump_label_type jump_label_type(struct jump_entry *entry) 176static enum jump_label_type jump_label_type(struct jump_entry *entry)
172{ 177{
173 struct static_key *key = jump_entry_key(entry); 178 struct static_key *key = jump_entry_key(entry);
174 bool enabled = static_key_enabled(key); 179 bool enabled = static_key_enabled(key);
175 bool type = static_key_type(key); 180 bool branch = jump_entry_branch(entry);
176 181
177 return enabled ^ type; 182 /* See the comment in linux/jump_label.h */
183 return enabled ^ branch;
178} 184}
179 185
180static void __jump_label_update(struct static_key *key, 186static void __jump_label_update(struct static_key *key,
@@ -205,7 +211,10 @@ void __init jump_label_init(void)
205 for (iter = iter_start; iter < iter_stop; iter++) { 211 for (iter = iter_start; iter < iter_stop; iter++) {
206 struct static_key *iterk; 212 struct static_key *iterk;
207 213
208 arch_jump_label_transform_static(iter, jump_label_type(iter)); 214 /* rewrite NOPs */
215 if (jump_label_type(iter) == JUMP_LABEL_NOP)
216 arch_jump_label_transform_static(iter, JUMP_LABEL_NOP);
217
209 iterk = jump_entry_key(iter); 218 iterk = jump_entry_key(iter);
210 if (iterk == key) 219 if (iterk == key)
211 continue; 220 continue;
@@ -225,6 +234,16 @@ void __init jump_label_init(void)
225 234
226#ifdef CONFIG_MODULES 235#ifdef CONFIG_MODULES
227 236
237static enum jump_label_type jump_label_init_type(struct jump_entry *entry)
238{
239 struct static_key *key = jump_entry_key(entry);
240 bool type = static_key_type(key);
241 bool branch = jump_entry_branch(entry);
242
243 /* See the comment in linux/jump_label.h */
244 return type ^ branch;
245}
246
228struct static_key_mod { 247struct static_key_mod {
229 struct static_key_mod *next; 248 struct static_key_mod *next;
230 struct jump_entry *entries; 249 struct jump_entry *entries;
@@ -276,8 +295,11 @@ void jump_label_apply_nops(struct module *mod)
276 if (iter_start == iter_stop) 295 if (iter_start == iter_stop)
277 return; 296 return;
278 297
279 for (iter = iter_start; iter < iter_stop; iter++) 298 for (iter = iter_start; iter < iter_stop; iter++) {
280 arch_jump_label_transform_static(iter, JUMP_LABEL_NOP); 299 /* Only write NOPs for arch_branch_static(). */
300 if (jump_label_init_type(iter) == JUMP_LABEL_NOP)
301 arch_jump_label_transform_static(iter, JUMP_LABEL_NOP);
302 }
281} 303}
282 304
283static int jump_label_add_module(struct module *mod) 305static int jump_label_add_module(struct module *mod)
@@ -318,7 +340,8 @@ static int jump_label_add_module(struct module *mod)
318 jlm->next = key->next; 340 jlm->next = key->next;
319 key->next = jlm; 341 key->next = jlm;
320 342
321 if (jump_label_type(iter) == JUMP_LABEL_JMP) 343 /* Only update if we've changed from our initial state */
344 if (jump_label_type(iter) != jump_label_init_type(iter))
322 __jump_label_update(key, iter, iter_stop); 345 __jump_label_update(key, iter, iter_stop);
323 } 346 }
324 347