summaryrefslogtreecommitdiffstats
path: root/kernel/jump_label.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2017-08-01 11:24:04 -0400
committerIngo Molnar <mingo@kernel.org>2017-08-10 06:28:56 -0400
commit1dbb6704de91b169a58d0c8221624afd6a95cfc7 (patch)
tree46273515a9b79413d2f00629b7e253189e903219 /kernel/jump_label.c
parent83ced169d9a01f22eb39f1fcc1f89ad9d223238f (diff)
jump_label: Fix concurrent static_key_enable/disable()
static_key_enable/disable are trying to cap the static key count to 0/1. However, their use of key->enabled is outside jump_label_lock so they do not really ensure that. Rewrite them to do a quick check for an already enabled (respectively, already disabled), and then recheck under the jump label lock. Unlike static_key_slow_inc/dec, a failed check under the jump label lock does not modify key->enabled. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Jason Baron <jbaron@akamai.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1501601046-35683-2-git-send-email-pbonzini@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/jump_label.c')
-rw-r--r--kernel/jump_label.c59
1 files changed, 37 insertions, 22 deletions
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index d11c506a6ac3..833eecae825e 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -79,28 +79,6 @@ int static_key_count(struct static_key *key)
79} 79}
80EXPORT_SYMBOL_GPL(static_key_count); 80EXPORT_SYMBOL_GPL(static_key_count);
81 81
82void static_key_enable(struct static_key *key)
83{
84 int count = static_key_count(key);
85
86 WARN_ON_ONCE(count < 0 || count > 1);
87
88 if (!count)
89 static_key_slow_inc(key);
90}
91EXPORT_SYMBOL_GPL(static_key_enable);
92
93void static_key_disable(struct static_key *key)
94{
95 int count = static_key_count(key);
96
97 WARN_ON_ONCE(count < 0 || count > 1);
98
99 if (count)
100 static_key_slow_dec(key);
101}
102EXPORT_SYMBOL_GPL(static_key_disable);
103
104void static_key_slow_inc(struct static_key *key) 82void static_key_slow_inc(struct static_key *key)
105{ 83{
106 int v, v1; 84 int v, v1;
@@ -139,6 +117,43 @@ void static_key_slow_inc(struct static_key *key)
139} 117}
140EXPORT_SYMBOL_GPL(static_key_slow_inc); 118EXPORT_SYMBOL_GPL(static_key_slow_inc);
141 119
120void static_key_enable(struct static_key *key)
121{
122 STATIC_KEY_CHECK_USE();
123 if (atomic_read(&key->enabled) > 0) {
124 WARN_ON_ONCE(atomic_read(&key->enabled) != 1);
125 return;
126 }
127
128 cpus_read_lock();
129 jump_label_lock();
130 if (atomic_read(&key->enabled) == 0) {
131 atomic_set(&key->enabled, -1);
132 jump_label_update(key);
133 atomic_set(&key->enabled, 1);
134 }
135 jump_label_unlock();
136 cpus_read_unlock();
137}
138EXPORT_SYMBOL_GPL(static_key_enable);
139
140void static_key_disable(struct static_key *key)
141{
142 STATIC_KEY_CHECK_USE();
143 if (atomic_read(&key->enabled) != 1) {
144 WARN_ON_ONCE(atomic_read(&key->enabled) != 0);
145 return;
146 }
147
148 cpus_read_lock();
149 jump_label_lock();
150 if (atomic_cmpxchg(&key->enabled, 1, 0))
151 jump_label_update(key);
152 jump_label_unlock();
153 cpus_read_unlock();
154}
155EXPORT_SYMBOL_GPL(static_key_disable);
156
142static void __static_key_slow_dec(struct static_key *key, 157static void __static_key_slow_dec(struct static_key *key,
143 unsigned long rate_limit, struct delayed_work *work) 158 unsigned long rate_limit, struct delayed_work *work)
144{ 159{