diff options
-rw-r--r-- | include/linux/jump_label.h | 46 | ||||
-rw-r--r-- | kernel/jump_label.c | 53 |
2 files changed, 76 insertions, 23 deletions
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index 68904469fba1..661af564fae8 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h | |||
@@ -76,7 +76,6 @@ | |||
76 | 76 | ||
77 | #include <linux/types.h> | 77 | #include <linux/types.h> |
78 | #include <linux/compiler.h> | 78 | #include <linux/compiler.h> |
79 | #include <linux/bug.h> | ||
80 | 79 | ||
81 | extern bool static_key_initialized; | 80 | extern bool static_key_initialized; |
82 | 81 | ||
@@ -115,20 +114,8 @@ enum jump_label_type { | |||
115 | 114 | ||
116 | struct module; | 115 | struct module; |
117 | 116 | ||
118 | #include <linux/atomic.h> | ||
119 | |||
120 | #ifdef HAVE_JUMP_LABEL | 117 | #ifdef HAVE_JUMP_LABEL |
121 | 118 | ||
122 | static inline int static_key_count(struct static_key *key) | ||
123 | { | ||
124 | /* | ||
125 | * -1 means the first static_key_slow_inc() is in progress. | ||
126 | * static_key_enabled() must return true, so return 1 here. | ||
127 | */ | ||
128 | int n = atomic_read(&key->enabled); | ||
129 | return n >= 0 ? n : 1; | ||
130 | } | ||
131 | |||
132 | #define JUMP_TYPE_FALSE 0UL | 119 | #define JUMP_TYPE_FALSE 0UL |
133 | #define JUMP_TYPE_TRUE 1UL | 120 | #define JUMP_TYPE_TRUE 1UL |
134 | #define JUMP_TYPE_MASK 1UL | 121 | #define JUMP_TYPE_MASK 1UL |
@@ -157,16 +144,29 @@ extern int jump_label_text_reserved(void *start, void *end); | |||
157 | extern void static_key_slow_inc(struct static_key *key); | 144 | extern void static_key_slow_inc(struct static_key *key); |
158 | extern void static_key_slow_dec(struct static_key *key); | 145 | extern void static_key_slow_dec(struct static_key *key); |
159 | extern void jump_label_apply_nops(struct module *mod); | 146 | extern void jump_label_apply_nops(struct module *mod); |
147 | extern int static_key_count(struct static_key *key); | ||
148 | extern void static_key_enable(struct static_key *key); | ||
149 | extern void static_key_disable(struct static_key *key); | ||
160 | 150 | ||
151 | /* | ||
152 | * We should be using ATOMIC_INIT() for initializing .enabled, but | ||
153 | * the inclusion of atomic.h is problematic for inclusion of jump_label.h | ||
154 | * in 'low-level' headers. Thus, we are initializing .enabled with a | ||
155 | * raw value, but have added a BUILD_BUG_ON() to catch any issues in | ||
156 | * jump_label_init() see: kernel/jump_label.c. | ||
157 | */ | ||
161 | #define STATIC_KEY_INIT_TRUE \ | 158 | #define STATIC_KEY_INIT_TRUE \ |
162 | { .enabled = ATOMIC_INIT(1), \ | 159 | { .enabled = { 1 }, \ |
163 | .entries = (void *)JUMP_TYPE_TRUE } | 160 | .entries = (void *)JUMP_TYPE_TRUE } |
164 | #define STATIC_KEY_INIT_FALSE \ | 161 | #define STATIC_KEY_INIT_FALSE \ |
165 | { .enabled = ATOMIC_INIT(0), \ | 162 | { .enabled = { 0 }, \ |
166 | .entries = (void *)JUMP_TYPE_FALSE } | 163 | .entries = (void *)JUMP_TYPE_FALSE } |
167 | 164 | ||
168 | #else /* !HAVE_JUMP_LABEL */ | 165 | #else /* !HAVE_JUMP_LABEL */ |
169 | 166 | ||
167 | #include <linux/atomic.h> | ||
168 | #include <linux/bug.h> | ||
169 | |||
170 | static inline int static_key_count(struct static_key *key) | 170 | static inline int static_key_count(struct static_key *key) |
171 | { | 171 | { |
172 | return atomic_read(&key->enabled); | 172 | return atomic_read(&key->enabled); |
@@ -216,14 +216,6 @@ static inline int jump_label_apply_nops(struct module *mod) | |||
216 | return 0; | 216 | return 0; |
217 | } | 217 | } |
218 | 218 | ||
219 | #define STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) } | ||
220 | #define STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) } | ||
221 | |||
222 | #endif /* HAVE_JUMP_LABEL */ | ||
223 | |||
224 | #define STATIC_KEY_INIT STATIC_KEY_INIT_FALSE | ||
225 | #define jump_label_enabled static_key_enabled | ||
226 | |||
227 | static inline void static_key_enable(struct static_key *key) | 219 | static inline void static_key_enable(struct static_key *key) |
228 | { | 220 | { |
229 | int count = static_key_count(key); | 221 | int count = static_key_count(key); |
@@ -244,6 +236,14 @@ static inline void static_key_disable(struct static_key *key) | |||
244 | static_key_slow_dec(key); | 236 | static_key_slow_dec(key); |
245 | } | 237 | } |
246 | 238 | ||
239 | #define STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) } | ||
240 | #define STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) } | ||
241 | |||
242 | #endif /* HAVE_JUMP_LABEL */ | ||
243 | |||
244 | #define STATIC_KEY_INIT STATIC_KEY_INIT_FALSE | ||
245 | #define jump_label_enabled static_key_enabled | ||
246 | |||
247 | /* -------------------------------------------------------------------------- */ | 247 | /* -------------------------------------------------------------------------- */ |
248 | 248 | ||
249 | /* | 249 | /* |
diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 0dbea887d625..f19aa02a8f48 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/static_key.h> | 15 | #include <linux/static_key.h> |
16 | #include <linux/jump_label_ratelimit.h> | 16 | #include <linux/jump_label_ratelimit.h> |
17 | #include <linux/bug.h> | ||
17 | 18 | ||
18 | #ifdef HAVE_JUMP_LABEL | 19 | #ifdef HAVE_JUMP_LABEL |
19 | 20 | ||
@@ -56,6 +57,49 @@ jump_label_sort_entries(struct jump_entry *start, struct jump_entry *stop) | |||
56 | 57 | ||
57 | static void jump_label_update(struct static_key *key); | 58 | static void jump_label_update(struct static_key *key); |
58 | 59 | ||
60 | /* | ||
61 | * There are similar definitions for the !HAVE_JUMP_LABEL case in jump_label.h. | ||
62 | * The use of 'atomic_read()' requires atomic.h and its problematic for some | ||
63 | * kernel headers such as kernel.h and others. Since static_key_count() is not | ||
64 | * used in the branch statements as it is for the !HAVE_JUMP_LABEL case its ok | ||
65 | * to have it be a function here. Similarly, for 'static_key_enable()' and | ||
66 | * 'static_key_disable()', which require bug.h. This should allow jump_label.h | ||
67 | * to be included from most/all places for HAVE_JUMP_LABEL. | ||
68 | */ | ||
69 | int static_key_count(struct static_key *key) | ||
70 | { | ||
71 | /* | ||
72 | * -1 means the first static_key_slow_inc() is in progress. | ||
73 | * static_key_enabled() must return true, so return 1 here. | ||
74 | */ | ||
75 | int n = atomic_read(&key->enabled); | ||
76 | |||
77 | return n >= 0 ? n : 1; | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(static_key_count); | ||
80 | |||
81 | void static_key_enable(struct static_key *key) | ||
82 | { | ||
83 | int count = static_key_count(key); | ||
84 | |||
85 | WARN_ON_ONCE(count < 0 || count > 1); | ||
86 | |||
87 | if (!count) | ||
88 | static_key_slow_inc(key); | ||
89 | } | ||
90 | EXPORT_SYMBOL_GPL(static_key_enable); | ||
91 | |||
92 | void static_key_disable(struct static_key *key) | ||
93 | { | ||
94 | int count = static_key_count(key); | ||
95 | |||
96 | WARN_ON_ONCE(count < 0 || count > 1); | ||
97 | |||
98 | if (count) | ||
99 | static_key_slow_dec(key); | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(static_key_disable); | ||
102 | |||
59 | void static_key_slow_inc(struct static_key *key) | 103 | void static_key_slow_inc(struct static_key *key) |
60 | { | 104 | { |
61 | int v, v1; | 105 | int v, v1; |
@@ -235,6 +279,15 @@ void __init jump_label_init(void) | |||
235 | struct static_key *key = NULL; | 279 | struct static_key *key = NULL; |
236 | struct jump_entry *iter; | 280 | struct jump_entry *iter; |
237 | 281 | ||
282 | /* | ||
283 | * Since we are initializing the static_key.enabled field with | ||
284 | * with the 'raw' int values (to avoid pulling in atomic.h) in | ||
285 | * jump_label.h, let's make sure that is safe. There are only two | ||
286 | * cases to check since we initialize to 0 or 1. | ||
287 | */ | ||
288 | BUILD_BUG_ON((int)ATOMIC_INIT(0) != 0); | ||
289 | BUILD_BUG_ON((int)ATOMIC_INIT(1) != 1); | ||
290 | |||
238 | jump_label_lock(); | 291 | jump_label_lock(); |
239 | jump_label_sort_entries(iter_start, iter_stop); | 292 | jump_label_sort_entries(iter_start, iter_stop); |
240 | 293 | ||