diff options
author | Peter Zijlstra <peterz@infradead.org> | 2015-07-24 09:09:55 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-08-03 05:34:15 -0400 |
commit | 11276d5306b8e5b438a36bbff855fe792d7eaa61 (patch) | |
tree | 9ddfc5e1bec6174e838cce8eb67af9e911c4e5f8 /arch | |
parent | 706249c222f68471b6f8e9e8e9b77665c404b226 (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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/jump_label.h | 25 | ||||
-rw-r--r-- | arch/arm64/include/asm/jump_label.h | 18 | ||||
-rw-r--r-- | arch/mips/include/asm/jump_label.h | 19 | ||||
-rw-r--r-- | arch/powerpc/include/asm/jump_label.h | 19 | ||||
-rw-r--r-- | arch/s390/include/asm/jump_label.h | 19 | ||||
-rw-r--r-- | arch/sparc/include/asm/jump_label.h | 35 | ||||
-rw-r--r-- | arch/x86/include/asm/jump_label.h | 21 |
7 files changed, 129 insertions, 27 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 | 11 | static __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; | ||
21 | l_yes: | ||
22 | return true; | ||
23 | } | ||
15 | 24 | ||
16 | static __always_inline bool arch_static_branch(struct static_key *key) | 25 | static __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; |
26 | l_yes: | 35 | l_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 | ||
29 | static __always_inline bool arch_static_branch(struct static_key *key) | 29 | static __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; | ||
39 | l_yes: | ||
40 | return true; | ||
41 | } | ||
42 | |||
43 | static __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; |
39 | l_yes: | 53 | l_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 | ||
29 | static __always_inline bool arch_static_branch(struct static_key *key) | 29 | static __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; | ||
39 | l_yes: | ||
40 | return true; | ||
41 | } | ||
42 | |||
43 | static __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; |
38 | l_yes: | 53 | l_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 | ||
21 | static __always_inline bool arch_static_branch(struct static_key *key) | 21 | static __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; | ||
31 | l_yes: | ||
32 | return true; | ||
33 | } | ||
34 | |||
35 | static __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; |
30 | l_yes: | 45 | l_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 | */ |
15 | static __always_inline bool arch_static_branch(struct static_key *key) | 15 | static __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; | ||
25 | label: | ||
26 | return true; | ||
27 | } | ||
28 | |||
29 | static __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; |
24 | label: | 39 | label: |
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 | ||
10 | static __always_inline bool arch_static_branch(struct static_key *key) | 10 | static __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; | ||
22 | l_yes: | ||
23 | return true; | ||
24 | } | ||
25 | |||
26 | static __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; |
21 | l_yes: | 38 | l_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 | ||
19 | static __always_inline bool arch_static_branch(struct static_key *key) | 19 | static __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; | ||
30 | l_yes: | ||
31 | return true; | ||
32 | } | ||
33 | |||
34 | static __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; |
29 | l_yes: | 46 | l_yes: |
30 | return true; | 47 | return true; |