aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2017-08-01 04:02:56 -0400
committerIngo Molnar <mingo@kernel.org>2017-08-10 06:28:59 -0400
commit5a40527f8f0798553764fc8db4111d7d9c33ea51 (patch)
tree8147a2345202a3e7d5b1d3b14ca1c804d660f300
parent8b7b412807053ab5f059ffae426a280e769a5bda (diff)
jump_label: Provide hotplug context variants
As using the normal static key API under the hotplug lock is pretty much impossible, let's provide a variant of some of them that require the hotplug lock to have already been taken. These function are only meant to be used in CPU hotplug callbacks. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Leo Yan <leo.yan@linaro.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/20170801080257.5056-4-marc.zyngier@arm.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--Documentation/static-keys.txt15
-rw-r--r--include/linux/jump_label.h11
-rw-r--r--kernel/jump_label.c22
3 files changed, 42 insertions, 6 deletions
diff --git a/Documentation/static-keys.txt b/Documentation/static-keys.txt
index 870b4be3cb11..ab16efe0c79d 100644
--- a/Documentation/static-keys.txt
+++ b/Documentation/static-keys.txt
@@ -154,6 +154,21 @@ and 'static_key_count()'. In general, if you use these functions, they
154should be protected with the same mutex used around the enable/disable 154should be protected with the same mutex used around the enable/disable
155or increment/decrement function. 155or increment/decrement function.
156 156
157Note that switching branches results in some locks being taken,
158particularly the CPU hotplug lock (in order to avoid races against
159CPUs being brought in the kernel whilst the kernel is getting
160patched). Calling the static key API from within a hotplug notifier is
161thus a sure deadlock recipe. In order to still allow use of the
162functionnality, the following functions are provided:
163
164 static_key_enable_cpuslocked()
165 static_key_disable_cpuslocked()
166 static_branch_enable_cpuslocked()
167 static_branch_disable_cpuslocked()
168
169These functions are *not* general purpose, and must only be used when
170you really know that you're in the above context, and no other.
171
157Where an array of keys is required, it can be defined as:: 172Where an array of keys is required, it can be defined as::
158 173
159 DEFINE_STATIC_KEY_ARRAY_TRUE(keys, count); 174 DEFINE_STATIC_KEY_ARRAY_TRUE(keys, count);
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
index 740a42ea7f7f..cd5861651b17 100644
--- a/include/linux/jump_label.h
+++ b/include/linux/jump_label.h
@@ -163,6 +163,8 @@ extern void jump_label_apply_nops(struct module *mod);
163extern int static_key_count(struct static_key *key); 163extern int static_key_count(struct static_key *key);
164extern void static_key_enable(struct static_key *key); 164extern void static_key_enable(struct static_key *key);
165extern void static_key_disable(struct static_key *key); 165extern void static_key_disable(struct static_key *key);
166extern void static_key_enable_cpuslocked(struct static_key *key);
167extern void static_key_disable_cpuslocked(struct static_key *key);
166 168
167/* 169/*
168 * We should be using ATOMIC_INIT() for initializing .enabled, but 170 * We should be using ATOMIC_INIT() for initializing .enabled, but
@@ -254,6 +256,9 @@ static inline void static_key_disable(struct static_key *key)
254 atomic_set(&key->enabled, 0); 256 atomic_set(&key->enabled, 0);
255} 257}
256 258
259#define static_key_enable_cpuslocked(k) static_key_enable((k))
260#define static_key_disable_cpuslocked(k) static_key_disable((k))
261
257#define STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) } 262#define STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) }
258#define STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) } 263#define STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) }
259 264
@@ -415,8 +420,10 @@ extern bool ____wrong_branch_error(void);
415 * Normal usage; boolean enable/disable. 420 * Normal usage; boolean enable/disable.
416 */ 421 */
417 422
418#define static_branch_enable(x) static_key_enable(&(x)->key) 423#define static_branch_enable(x) static_key_enable(&(x)->key)
419#define static_branch_disable(x) static_key_disable(&(x)->key) 424#define static_branch_disable(x) static_key_disable(&(x)->key)
425#define static_branch_enable_cpuslocked(x) static_key_enable_cpuslocked(&(x)->key)
426#define static_branch_disable_cpuslocked(x) static_key_disable_cpuslocked(&(x)->key)
420 427
421#endif /* __ASSEMBLY__ */ 428#endif /* __ASSEMBLY__ */
422 429
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index cc6d815c75ed..0bf2e8f5244a 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -126,15 +126,15 @@ void static_key_slow_inc(struct static_key *key)
126} 126}
127EXPORT_SYMBOL_GPL(static_key_slow_inc); 127EXPORT_SYMBOL_GPL(static_key_slow_inc);
128 128
129void static_key_enable(struct static_key *key) 129void static_key_enable_cpuslocked(struct static_key *key)
130{ 130{
131 STATIC_KEY_CHECK_USE(); 131 STATIC_KEY_CHECK_USE();
132
132 if (atomic_read(&key->enabled) > 0) { 133 if (atomic_read(&key->enabled) > 0) {
133 WARN_ON_ONCE(atomic_read(&key->enabled) != 1); 134 WARN_ON_ONCE(atomic_read(&key->enabled) != 1);
134 return; 135 return;
135 } 136 }
136 137
137 cpus_read_lock();
138 jump_label_lock(); 138 jump_label_lock();
139 if (atomic_read(&key->enabled) == 0) { 139 if (atomic_read(&key->enabled) == 0) {
140 atomic_set(&key->enabled, -1); 140 atomic_set(&key->enabled, -1);
@@ -145,23 +145,37 @@ void static_key_enable(struct static_key *key)
145 atomic_set_release(&key->enabled, 1); 145 atomic_set_release(&key->enabled, 1);
146 } 146 }
147 jump_label_unlock(); 147 jump_label_unlock();
148}
149EXPORT_SYMBOL_GPL(static_key_enable_cpuslocked);
150
151void static_key_enable(struct static_key *key)
152{
153 cpus_read_lock();
154 static_key_enable_cpuslocked(key);
148 cpus_read_unlock(); 155 cpus_read_unlock();
149} 156}
150EXPORT_SYMBOL_GPL(static_key_enable); 157EXPORT_SYMBOL_GPL(static_key_enable);
151 158
152void static_key_disable(struct static_key *key) 159void static_key_disable_cpuslocked(struct static_key *key)
153{ 160{
154 STATIC_KEY_CHECK_USE(); 161 STATIC_KEY_CHECK_USE();
162
155 if (atomic_read(&key->enabled) != 1) { 163 if (atomic_read(&key->enabled) != 1) {
156 WARN_ON_ONCE(atomic_read(&key->enabled) != 0); 164 WARN_ON_ONCE(atomic_read(&key->enabled) != 0);
157 return; 165 return;
158 } 166 }
159 167
160 cpus_read_lock();
161 jump_label_lock(); 168 jump_label_lock();
162 if (atomic_cmpxchg(&key->enabled, 1, 0)) 169 if (atomic_cmpxchg(&key->enabled, 1, 0))
163 jump_label_update(key); 170 jump_label_update(key);
164 jump_label_unlock(); 171 jump_label_unlock();
172}
173EXPORT_SYMBOL_GPL(static_key_disable_cpuslocked);
174
175void static_key_disable(struct static_key *key)
176{
177 cpus_read_lock();
178 static_key_disable_cpuslocked(key);
165 cpus_read_unlock(); 179 cpus_read_unlock();
166} 180}
167EXPORT_SYMBOL_GPL(static_key_disable); 181EXPORT_SYMBOL_GPL(static_key_disable);