summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/jump_label.h46
-rw-r--r--kernel/jump_label.c53
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
81extern bool static_key_initialized; 80extern bool static_key_initialized;
82 81
@@ -115,20 +114,8 @@ enum jump_label_type {
115 114
116struct module; 115struct module;
117 116
118#include <linux/atomic.h>
119
120#ifdef HAVE_JUMP_LABEL 117#ifdef HAVE_JUMP_LABEL
121 118
122static 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);
157extern void static_key_slow_inc(struct static_key *key); 144extern void static_key_slow_inc(struct static_key *key);
158extern void static_key_slow_dec(struct static_key *key); 145extern void static_key_slow_dec(struct static_key *key);
159extern void jump_label_apply_nops(struct module *mod); 146extern void jump_label_apply_nops(struct module *mod);
147extern int static_key_count(struct static_key *key);
148extern void static_key_enable(struct static_key *key);
149extern 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
170static inline int static_key_count(struct static_key *key) 170static 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
227static inline void static_key_enable(struct static_key *key) 219static 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
57static void jump_label_update(struct static_key *key); 58static 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 */
69int 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}
79EXPORT_SYMBOL_GPL(static_key_count);
80
81void 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}
90EXPORT_SYMBOL_GPL(static_key_enable);
91
92void 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}
101EXPORT_SYMBOL_GPL(static_key_disable);
102
59void static_key_slow_inc(struct static_key *key) 103void 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