Blame view

kernel/jump_label.c 19.3 KB
bf5438fca   Jason Baron   jump label: Base ...
1
2
3
4
  /*
   * jump label support
   *
   * Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
90eec103b   Peter Zijlstra   treewide: Remove ...
5
   * Copyright (C) 2011 Peter Zijlstra
bf5438fca   Jason Baron   jump label: Base ...
6
7
   *
   */
bf5438fca   Jason Baron   jump label: Base ...
8
9
10
11
  #include <linux/memory.h>
  #include <linux/uaccess.h>
  #include <linux/module.h>
  #include <linux/list.h>
bf5438fca   Jason Baron   jump label: Base ...
12
13
14
  #include <linux/slab.h>
  #include <linux/sort.h>
  #include <linux/err.h>
c5905afb0   Ingo Molnar   static keys: Intr...
15
  #include <linux/static_key.h>
851cf6e7d   Andrew Jones   jump_label: Split...
16
  #include <linux/jump_label_ratelimit.h>
1f69bf9c6   Jason Baron   jump_label: remov...
17
  #include <linux/bug.h>
f2545b2d4   Thomas Gleixner   jump_label: Reord...
18
  #include <linux/cpu.h>
bf5438fca   Jason Baron   jump label: Base ...
19
20
  
  #ifdef HAVE_JUMP_LABEL
bf5438fca   Jason Baron   jump label: Base ...
21
22
  /* mutex to protect coming/going of the the jump_label table */
  static DEFINE_MUTEX(jump_label_mutex);
91bad2f8d   Jason Baron   jump label: Fix d...
23
24
25
26
27
28
29
30
31
  void jump_label_lock(void)
  {
  	mutex_lock(&jump_label_mutex);
  }
  
  void jump_label_unlock(void)
  {
  	mutex_unlock(&jump_label_mutex);
  }
bf5438fca   Jason Baron   jump label: Base ...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  static int jump_label_cmp(const void *a, const void *b)
  {
  	const struct jump_entry *jea = a;
  	const struct jump_entry *jeb = b;
  
  	if (jea->key < jeb->key)
  		return -1;
  
  	if (jea->key > jeb->key)
  		return 1;
  
  	return 0;
  }
  
  static void
d430d3d7e   Jason Baron   jump label: Intro...
47
  jump_label_sort_entries(struct jump_entry *start, struct jump_entry *stop)
bf5438fca   Jason Baron   jump label: Base ...
48
49
50
51
52
53
54
  {
  	unsigned long size;
  
  	size = (((unsigned long)stop - (unsigned long)start)
  					/ sizeof(struct jump_entry));
  	sort(start, size, sizeof(struct jump_entry), jump_label_cmp, NULL);
  }
706249c22   Peter Zijlstra   locking/static_ke...
55
  static void jump_label_update(struct static_key *key);
a1efb01fe   Peter Zijlstra   jump_label, locki...
56

1f69bf9c6   Jason Baron   jump_label: remov...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  /*
   * There are similar definitions for the !HAVE_JUMP_LABEL case in jump_label.h.
   * The use of 'atomic_read()' requires atomic.h and its problematic for some
   * kernel headers such as kernel.h and others. Since static_key_count() is not
   * used in the branch statements as it is for the !HAVE_JUMP_LABEL case its ok
   * to have it be a function here. Similarly, for 'static_key_enable()' and
   * 'static_key_disable()', which require bug.h. This should allow jump_label.h
   * to be included from most/all places for HAVE_JUMP_LABEL.
   */
  int static_key_count(struct static_key *key)
  {
  	/*
  	 * -1 means the first static_key_slow_inc() is in progress.
  	 *  static_key_enabled() must return true, so return 1 here.
  	 */
  	int n = atomic_read(&key->enabled);
  
  	return n >= 0 ? n : 1;
  }
  EXPORT_SYMBOL_GPL(static_key_count);
e5d981df9   Peter Zijlstra   sched/core: Fix c...
77
  void static_key_slow_inc_cpuslocked(struct static_key *key)
bf5438fca   Jason Baron   jump label: Base ...
78
  {
4c5ea0a9c   Paolo Bonzini   locking/static_ke...
79
  	int v, v1;
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
80
  	STATIC_KEY_CHECK_USE();
4c5ea0a9c   Paolo Bonzini   locking/static_ke...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  
  	/*
  	 * Careful if we get concurrent static_key_slow_inc() calls;
  	 * later calls must wait for the first one to _finish_ the
  	 * jump_label_update() process.  At the same time, however,
  	 * the jump_label_update() call below wants to see
  	 * static_key_enabled(&key) for jumps to be updated properly.
  	 *
  	 * So give a special meaning to negative key->enabled: it sends
  	 * static_key_slow_inc() down the slow path, and it is non-zero
  	 * so it counts as "enabled" in jump_label_update().  Note that
  	 * atomic_inc_unless_negative() checks >= 0, so roll our own.
  	 */
  	for (v = atomic_read(&key->enabled); v > 0; v = v1) {
  		v1 = atomic_cmpxchg(&key->enabled, v, v + 1);
8b7b41280   Marc Zyngier   jump_label: Split...
96
  		if (likely(v1 == v))
4c5ea0a9c   Paolo Bonzini   locking/static_ke...
97
98
  			return;
  	}
bf5438fca   Jason Baron   jump label: Base ...
99

d430d3d7e   Jason Baron   jump label: Intro...
100
  	jump_label_lock();
4c5ea0a9c   Paolo Bonzini   locking/static_ke...
101
102
  	if (atomic_read(&key->enabled) == 0) {
  		atomic_set(&key->enabled, -1);
706249c22   Peter Zijlstra   locking/static_ke...
103
  		jump_label_update(key);
d0646a6f5   Peter Zijlstra   jump_label: Add R...
104
105
106
107
108
  		/*
  		 * Ensure that if the above cmpxchg loop observes our positive
  		 * value, it must also observe all the text changes.
  		 */
  		atomic_set_release(&key->enabled, 1);
4c5ea0a9c   Paolo Bonzini   locking/static_ke...
109
110
111
  	} else {
  		atomic_inc(&key->enabled);
  	}
d430d3d7e   Jason Baron   jump label: Intro...
112
  	jump_label_unlock();
8b7b41280   Marc Zyngier   jump_label: Split...
113
114
115
116
117
118
  }
  
  void static_key_slow_inc(struct static_key *key)
  {
  	cpus_read_lock();
  	static_key_slow_inc_cpuslocked(key);
f2545b2d4   Thomas Gleixner   jump_label: Reord...
119
  	cpus_read_unlock();
bf5438fca   Jason Baron   jump label: Base ...
120
  }
c5905afb0   Ingo Molnar   static keys: Intr...
121
  EXPORT_SYMBOL_GPL(static_key_slow_inc);
bf5438fca   Jason Baron   jump label: Base ...
122

5a40527f8   Marc Zyngier   jump_label: Provi...
123
  void static_key_enable_cpuslocked(struct static_key *key)
1dbb6704d   Paolo Bonzini   jump_label: Fix c...
124
125
  {
  	STATIC_KEY_CHECK_USE();
5a40527f8   Marc Zyngier   jump_label: Provi...
126

1dbb6704d   Paolo Bonzini   jump_label: Fix c...
127
128
129
130
  	if (atomic_read(&key->enabled) > 0) {
  		WARN_ON_ONCE(atomic_read(&key->enabled) != 1);
  		return;
  	}
1dbb6704d   Paolo Bonzini   jump_label: Fix c...
131
132
133
134
  	jump_label_lock();
  	if (atomic_read(&key->enabled) == 0) {
  		atomic_set(&key->enabled, -1);
  		jump_label_update(key);
d0646a6f5   Peter Zijlstra   jump_label: Add R...
135
136
137
138
  		/*
  		 * See static_key_slow_inc().
  		 */
  		atomic_set_release(&key->enabled, 1);
1dbb6704d   Paolo Bonzini   jump_label: Fix c...
139
140
  	}
  	jump_label_unlock();
5a40527f8   Marc Zyngier   jump_label: Provi...
141
142
143
144
145
146
147
  }
  EXPORT_SYMBOL_GPL(static_key_enable_cpuslocked);
  
  void static_key_enable(struct static_key *key)
  {
  	cpus_read_lock();
  	static_key_enable_cpuslocked(key);
1dbb6704d   Paolo Bonzini   jump_label: Fix c...
148
149
150
  	cpus_read_unlock();
  }
  EXPORT_SYMBOL_GPL(static_key_enable);
5a40527f8   Marc Zyngier   jump_label: Provi...
151
  void static_key_disable_cpuslocked(struct static_key *key)
1dbb6704d   Paolo Bonzini   jump_label: Fix c...
152
153
  {
  	STATIC_KEY_CHECK_USE();
5a40527f8   Marc Zyngier   jump_label: Provi...
154

1dbb6704d   Paolo Bonzini   jump_label: Fix c...
155
156
157
158
  	if (atomic_read(&key->enabled) != 1) {
  		WARN_ON_ONCE(atomic_read(&key->enabled) != 0);
  		return;
  	}
1dbb6704d   Paolo Bonzini   jump_label: Fix c...
159
160
161
162
  	jump_label_lock();
  	if (atomic_cmpxchg(&key->enabled, 1, 0))
  		jump_label_update(key);
  	jump_label_unlock();
5a40527f8   Marc Zyngier   jump_label: Provi...
163
164
165
166
167
168
169
  }
  EXPORT_SYMBOL_GPL(static_key_disable_cpuslocked);
  
  void static_key_disable(struct static_key *key)
  {
  	cpus_read_lock();
  	static_key_disable_cpuslocked(key);
1dbb6704d   Paolo Bonzini   jump_label: Fix c...
170
171
172
  	cpus_read_unlock();
  }
  EXPORT_SYMBOL_GPL(static_key_disable);
e5d981df9   Peter Zijlstra   sched/core: Fix c...
173
  static void __static_key_slow_dec_cpuslocked(struct static_key *key,
8b7b41280   Marc Zyngier   jump_label: Split...
174
175
  					   unsigned long rate_limit,
  					   struct delayed_work *work)
bf5438fca   Jason Baron   jump label: Base ...
176
  {
4c5ea0a9c   Paolo Bonzini   locking/static_ke...
177
178
179
180
181
182
183
  	/*
  	 * The negative count check is valid even when a negative
  	 * key->enabled is in use by static_key_slow_inc(); a
  	 * __static_key_slow_dec() before the first static_key_slow_inc()
  	 * returns is unbalanced, because all other static_key_slow_inc()
  	 * instances block while the update is in progress.
  	 */
fadf0464b   Jason Baron   jump label: Add a...
184
185
186
187
  	if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) {
  		WARN(atomic_read(&key->enabled) < 0,
  		     "jump label: negative count!
  ");
d430d3d7e   Jason Baron   jump label: Intro...
188
  		return;
fadf0464b   Jason Baron   jump label: Add a...
189
  	}
bf5438fca   Jason Baron   jump label: Base ...
190

b20295207   Gleb Natapov   perf, core: Rate ...
191
192
193
  	if (rate_limit) {
  		atomic_inc(&key->enabled);
  		schedule_delayed_work(work, rate_limit);
c5905afb0   Ingo Molnar   static keys: Intr...
194
  	} else {
706249c22   Peter Zijlstra   locking/static_ke...
195
  		jump_label_update(key);
c5905afb0   Ingo Molnar   static keys: Intr...
196
  	}
91bad2f8d   Jason Baron   jump label: Fix d...
197
  	jump_label_unlock();
8b7b41280   Marc Zyngier   jump_label: Split...
198
199
200
201
202
203
204
  }
  
  static void __static_key_slow_dec(struct static_key *key,
  				  unsigned long rate_limit,
  				  struct delayed_work *work)
  {
  	cpus_read_lock();
e5d981df9   Peter Zijlstra   sched/core: Fix c...
205
  	__static_key_slow_dec_cpuslocked(key, rate_limit, work);
f2545b2d4   Thomas Gleixner   jump_label: Reord...
206
  	cpus_read_unlock();
bf5438fca   Jason Baron   jump label: Base ...
207
  }
b20295207   Gleb Natapov   perf, core: Rate ...
208
209
  static void jump_label_update_timeout(struct work_struct *work)
  {
c5905afb0   Ingo Molnar   static keys: Intr...
210
211
212
  	struct static_key_deferred *key =
  		container_of(work, struct static_key_deferred, work.work);
  	__static_key_slow_dec(&key->key, 0, NULL);
b20295207   Gleb Natapov   perf, core: Rate ...
213
  }
c5905afb0   Ingo Molnar   static keys: Intr...
214
  void static_key_slow_dec(struct static_key *key)
b20295207   Gleb Natapov   perf, core: Rate ...
215
  {
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
216
  	STATIC_KEY_CHECK_USE();
c5905afb0   Ingo Molnar   static keys: Intr...
217
  	__static_key_slow_dec(key, 0, NULL);
b20295207   Gleb Natapov   perf, core: Rate ...
218
  }
c5905afb0   Ingo Molnar   static keys: Intr...
219
  EXPORT_SYMBOL_GPL(static_key_slow_dec);
b20295207   Gleb Natapov   perf, core: Rate ...
220

e5d981df9   Peter Zijlstra   sched/core: Fix c...
221
222
223
224
225
  void static_key_slow_dec_cpuslocked(struct static_key *key)
  {
  	STATIC_KEY_CHECK_USE();
  	__static_key_slow_dec_cpuslocked(key, 0, NULL);
  }
c5905afb0   Ingo Molnar   static keys: Intr...
226
  void static_key_slow_dec_deferred(struct static_key_deferred *key)
b20295207   Gleb Natapov   perf, core: Rate ...
227
  {
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
228
  	STATIC_KEY_CHECK_USE();
c5905afb0   Ingo Molnar   static keys: Intr...
229
  	__static_key_slow_dec(&key->key, key->timeout, &key->work);
b20295207   Gleb Natapov   perf, core: Rate ...
230
  }
c5905afb0   Ingo Molnar   static keys: Intr...
231
  EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred);
b20295207   Gleb Natapov   perf, core: Rate ...
232

b6416e610   David Matlack   jump_labels: API ...
233
234
235
236
237
238
  void static_key_deferred_flush(struct static_key_deferred *key)
  {
  	STATIC_KEY_CHECK_USE();
  	flush_delayed_work(&key->work);
  }
  EXPORT_SYMBOL_GPL(static_key_deferred_flush);
c5905afb0   Ingo Molnar   static keys: Intr...
239
  void jump_label_rate_limit(struct static_key_deferred *key,
b20295207   Gleb Natapov   perf, core: Rate ...
240
241
  		unsigned long rl)
  {
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
242
  	STATIC_KEY_CHECK_USE();
b20295207   Gleb Natapov   perf, core: Rate ...
243
244
245
  	key->timeout = rl;
  	INIT_DELAYED_WORK(&key->work, jump_label_update_timeout);
  }
a181dc14e   Gleb Natapov   jump_label: Expor...
246
  EXPORT_SYMBOL_GPL(jump_label_rate_limit);
b20295207   Gleb Natapov   perf, core: Rate ...
247

4c3ef6d79   Jason Baron   jump label: Add j...
248
249
250
251
252
253
254
255
  static int addr_conflict(struct jump_entry *entry, void *start, void *end)
  {
  	if (entry->code <= (unsigned long)end &&
  		entry->code + JUMP_LABEL_NOP_SIZE > (unsigned long)start)
  		return 1;
  
  	return 0;
  }
d430d3d7e   Jason Baron   jump label: Intro...
256
257
  static int __jump_label_text_reserved(struct jump_entry *iter_start,
  		struct jump_entry *iter_stop, void *start, void *end)
4c3ef6d79   Jason Baron   jump label: Add j...
258
  {
4c3ef6d79   Jason Baron   jump label: Add j...
259
  	struct jump_entry *iter;
4c3ef6d79   Jason Baron   jump label: Add j...
260

4c3ef6d79   Jason Baron   jump label: Add j...
261
262
  	iter = iter_start;
  	while (iter < iter_stop) {
d430d3d7e   Jason Baron   jump label: Intro...
263
264
  		if (addr_conflict(iter, start, end))
  			return 1;
4c3ef6d79   Jason Baron   jump label: Add j...
265
266
  		iter++;
  	}
d430d3d7e   Jason Baron   jump label: Intro...
267
268
  	return 0;
  }
706249c22   Peter Zijlstra   locking/static_ke...
269
  /*
20284aa77   Jeremy Fitzhardinge   jump_label: add a...
270
271
272
273
274
   * Update code which is definitely not currently executing.
   * Architectures which need heavyweight synchronization to modify
   * running code can override this to make the non-live update case
   * cheaper.
   */
9cdbe1cba   Peter Zijlstra   jump_label, x86: ...
275
  void __weak __init_or_module arch_jump_label_transform_static(struct jump_entry *entry,
20284aa77   Jeremy Fitzhardinge   jump_label: add a...
276
277
  					    enum jump_label_type type)
  {
706249c22   Peter Zijlstra   locking/static_ke...
278
  	arch_jump_label_transform(entry, type);
20284aa77   Jeremy Fitzhardinge   jump_label: add a...
279
  }
706249c22   Peter Zijlstra   locking/static_ke...
280
  static inline struct jump_entry *static_key_entries(struct static_key *key)
d430d3d7e   Jason Baron   jump label: Intro...
281
  {
3821fd35b   Jason Baron   jump_label: Reduc...
282
283
  	WARN_ON_ONCE(key->type & JUMP_TYPE_LINKED);
  	return (struct jump_entry *)(key->type & ~JUMP_TYPE_MASK);
4c3ef6d79   Jason Baron   jump label: Add j...
284
  }
706249c22   Peter Zijlstra   locking/static_ke...
285
  static inline bool static_key_type(struct static_key *key)
c5905afb0   Ingo Molnar   static keys: Intr...
286
  {
3821fd35b   Jason Baron   jump_label: Reduc...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  	return key->type & JUMP_TYPE_TRUE;
  }
  
  static inline bool static_key_linked(struct static_key *key)
  {
  	return key->type & JUMP_TYPE_LINKED;
  }
  
  static inline void static_key_clear_linked(struct static_key *key)
  {
  	key->type &= ~JUMP_TYPE_LINKED;
  }
  
  static inline void static_key_set_linked(struct static_key *key)
  {
  	key->type |= JUMP_TYPE_LINKED;
a1efb01fe   Peter Zijlstra   jump_label, locki...
303
  }
c5905afb0   Ingo Molnar   static keys: Intr...
304

7dcfd915b   Peter Zijlstra   jump_label: Add j...
305
306
  static inline struct static_key *jump_entry_key(struct jump_entry *entry)
  {
11276d530   Peter Zijlstra   locking/static_ke...
307
308
309
310
311
312
  	return (struct static_key *)((unsigned long)entry->key & ~1UL);
  }
  
  static bool jump_entry_branch(struct jump_entry *entry)
  {
  	return (unsigned long)entry->key & 1UL;
7dcfd915b   Peter Zijlstra   jump_label: Add j...
313
  }
3821fd35b   Jason Baron   jump_label: Reduc...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  /***
   * A 'struct static_key' uses a union such that it either points directly
   * to a table of 'struct jump_entry' or to a linked list of modules which in
   * turn point to 'struct jump_entry' tables.
   *
   * The two lower bits of the pointer are used to keep track of which pointer
   * type is in use and to store the initial branch direction, we use an access
   * function which preserves these bits.
   */
  static void static_key_set_entries(struct static_key *key,
  				   struct jump_entry *entries)
  {
  	unsigned long type;
  
  	WARN_ON_ONCE((unsigned long)entries & JUMP_TYPE_MASK);
  	type = key->type & JUMP_TYPE_MASK;
  	key->entries = entries;
  	key->type |= type;
  }
706249c22   Peter Zijlstra   locking/static_ke...
333
  static enum jump_label_type jump_label_type(struct jump_entry *entry)
a1efb01fe   Peter Zijlstra   jump_label, locki...
334
  {
706249c22   Peter Zijlstra   locking/static_ke...
335
  	struct static_key *key = jump_entry_key(entry);
a1efb01fe   Peter Zijlstra   jump_label, locki...
336
  	bool enabled = static_key_enabled(key);
11276d530   Peter Zijlstra   locking/static_ke...
337
  	bool branch = jump_entry_branch(entry);
c5905afb0   Ingo Molnar   static keys: Intr...
338

11276d530   Peter Zijlstra   locking/static_ke...
339
340
  	/* See the comment in linux/jump_label.h */
  	return enabled ^ branch;
c5905afb0   Ingo Molnar   static keys: Intr...
341
  }
706249c22   Peter Zijlstra   locking/static_ke...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  static void __jump_label_update(struct static_key *key,
  				struct jump_entry *entry,
  				struct jump_entry *stop)
  {
  	for (; (entry < stop) && (jump_entry_key(entry) == key); entry++) {
  		/*
  		 * entry->code set to 0 invalidates module init text sections
  		 * kernel_text_address() verifies we are not in core kernel
  		 * init code, see jump_label_invalidate_module_init().
  		 */
  		if (entry->code && kernel_text_address(entry->code))
  			arch_jump_label_transform(entry, jump_label_type(entry));
  	}
  }
97ce2c88f   Jeremy Fitzhardinge   jump-label: initi...
356
  void __init jump_label_init(void)
bf5438fca   Jason Baron   jump label: Base ...
357
  {
bf5438fca   Jason Baron   jump label: Base ...
358
359
  	struct jump_entry *iter_start = __start___jump_table;
  	struct jump_entry *iter_stop = __stop___jump_table;
c5905afb0   Ingo Molnar   static keys: Intr...
360
  	struct static_key *key = NULL;
bf5438fca   Jason Baron   jump label: Base ...
361
  	struct jump_entry *iter;
1f69bf9c6   Jason Baron   jump_label: remov...
362
363
364
365
366
367
368
369
  	/*
  	 * Since we are initializing the static_key.enabled field with
  	 * with the 'raw' int values (to avoid pulling in atomic.h) in
  	 * jump_label.h, let's make sure that is safe. There are only two
  	 * cases to check since we initialize to 0 or 1.
  	 */
  	BUILD_BUG_ON((int)ATOMIC_INIT(0) != 0);
  	BUILD_BUG_ON((int)ATOMIC_INIT(1) != 1);
e3f91083f   Kevin Hao   jump_label: Make ...
370
371
  	if (static_key_initialized)
  		return;
f2545b2d4   Thomas Gleixner   jump_label: Reord...
372
  	cpus_read_lock();
91bad2f8d   Jason Baron   jump label: Fix d...
373
  	jump_label_lock();
d430d3d7e   Jason Baron   jump label: Intro...
374
375
376
  	jump_label_sort_entries(iter_start, iter_stop);
  
  	for (iter = iter_start; iter < iter_stop; iter++) {
c5905afb0   Ingo Molnar   static keys: Intr...
377
  		struct static_key *iterk;
37348804e   Jeremy Fitzhardinge   jump_label: if a ...
378

11276d530   Peter Zijlstra   locking/static_ke...
379
380
381
  		/* rewrite NOPs */
  		if (jump_label_type(iter) == JUMP_LABEL_NOP)
  			arch_jump_label_transform_static(iter, JUMP_LABEL_NOP);
7dcfd915b   Peter Zijlstra   jump_label: Add j...
382
  		iterk = jump_entry_key(iter);
37348804e   Jeremy Fitzhardinge   jump_label: if a ...
383
  		if (iterk == key)
d430d3d7e   Jason Baron   jump label: Intro...
384
  			continue;
37348804e   Jeremy Fitzhardinge   jump_label: if a ...
385
  		key = iterk;
3821fd35b   Jason Baron   jump_label: Reduc...
386
  		static_key_set_entries(key, iter);
bf5438fca   Jason Baron   jump label: Base ...
387
  	}
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
388
  	static_key_initialized = true;
91bad2f8d   Jason Baron   jump label: Fix d...
389
  	jump_label_unlock();
f2545b2d4   Thomas Gleixner   jump_label: Reord...
390
  	cpus_read_unlock();
bf5438fca   Jason Baron   jump label: Base ...
391
  }
bf5438fca   Jason Baron   jump label: Base ...
392
393
  
  #ifdef CONFIG_MODULES
11276d530   Peter Zijlstra   locking/static_ke...
394
395
396
397
398
399
400
401
402
  static enum jump_label_type jump_label_init_type(struct jump_entry *entry)
  {
  	struct static_key *key = jump_entry_key(entry);
  	bool type = static_key_type(key);
  	bool branch = jump_entry_branch(entry);
  
  	/* See the comment in linux/jump_label.h */
  	return type ^ branch;
  }
c5905afb0   Ingo Molnar   static keys: Intr...
403
404
  struct static_key_mod {
  	struct static_key_mod *next;
d430d3d7e   Jason Baron   jump label: Intro...
405
406
407
  	struct jump_entry *entries;
  	struct module *mod;
  };
3821fd35b   Jason Baron   jump_label: Reduc...
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  static inline struct static_key_mod *static_key_mod(struct static_key *key)
  {
  	WARN_ON_ONCE(!(key->type & JUMP_TYPE_LINKED));
  	return (struct static_key_mod *)(key->type & ~JUMP_TYPE_MASK);
  }
  
  /***
   * key->type and key->next are the same via union.
   * This sets key->next and preserves the type bits.
   *
   * See additional comments above static_key_set_entries().
   */
  static void static_key_set_mod(struct static_key *key,
  			       struct static_key_mod *mod)
  {
  	unsigned long type;
  
  	WARN_ON_ONCE((unsigned long)mod & JUMP_TYPE_MASK);
  	type = key->type & JUMP_TYPE_MASK;
  	key->next = mod;
  	key->type |= type;
  }
d430d3d7e   Jason Baron   jump label: Intro...
430
431
432
  static int __jump_label_mod_text_reserved(void *start, void *end)
  {
  	struct module *mod;
bdc9f3735   Rusty Russell   jump_label: disab...
433
  	preempt_disable();
d430d3d7e   Jason Baron   jump label: Intro...
434
  	mod = __module_text_address((unsigned long)start);
bdc9f3735   Rusty Russell   jump_label: disab...
435
436
  	WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
  	preempt_enable();
d430d3d7e   Jason Baron   jump label: Intro...
437
438
  	if (!mod)
  		return 0;
d430d3d7e   Jason Baron   jump label: Intro...
439
440
441
442
443
  
  	return __jump_label_text_reserved(mod->jump_entries,
  				mod->jump_entries + mod->num_jump_entries,
  				start, end);
  }
706249c22   Peter Zijlstra   locking/static_ke...
444
  static void __jump_label_mod_update(struct static_key *key)
d430d3d7e   Jason Baron   jump label: Intro...
445
  {
706249c22   Peter Zijlstra   locking/static_ke...
446
  	struct static_key_mod *mod;
d430d3d7e   Jason Baron   jump label: Intro...
447

3821fd35b   Jason Baron   jump_label: Reduc...
448
449
450
451
452
453
454
455
456
457
  	for (mod = static_key_mod(key); mod; mod = mod->next) {
  		struct jump_entry *stop;
  		struct module *m;
  
  		/*
  		 * NULL if the static_key is defined in a module
  		 * that does not use it
  		 */
  		if (!mod->entries)
  			continue;
7cbc5b8d4   Jiri Olsa   jump_label: Check...
458

3821fd35b   Jason Baron   jump_label: Reduc...
459
460
461
462
463
464
  		m = mod->mod;
  		if (!m)
  			stop = __stop___jump_table;
  		else
  			stop = m->jump_entries + m->num_jump_entries;
  		__jump_label_update(key, mod->entries, stop);
d430d3d7e   Jason Baron   jump label: Intro...
465
466
467
468
469
470
471
472
473
474
475
476
  	}
  }
  
  /***
   * apply_jump_label_nops - patch module jump labels with arch_get_jump_label_nop()
   * @mod: module to patch
   *
   * Allow for run-time selection of the optimal nops. Before the module
   * loads patch these with arch_get_jump_label_nop(), which is specified by
   * the arch specific jump label code.
   */
  void jump_label_apply_nops(struct module *mod)
bf5438fca   Jason Baron   jump label: Base ...
477
  {
d430d3d7e   Jason Baron   jump label: Intro...
478
479
480
481
482
483
484
  	struct jump_entry *iter_start = mod->jump_entries;
  	struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
  	struct jump_entry *iter;
  
  	/* if the module doesn't have jump label entries, just return */
  	if (iter_start == iter_stop)
  		return;
11276d530   Peter Zijlstra   locking/static_ke...
485
486
487
488
489
  	for (iter = iter_start; iter < iter_stop; iter++) {
  		/* Only write NOPs for arch_branch_static(). */
  		if (jump_label_init_type(iter) == JUMP_LABEL_NOP)
  			arch_jump_label_transform_static(iter, JUMP_LABEL_NOP);
  	}
bf5438fca   Jason Baron   jump label: Base ...
490
  }
d430d3d7e   Jason Baron   jump label: Intro...
491
  static int jump_label_add_module(struct module *mod)
bf5438fca   Jason Baron   jump label: Base ...
492
  {
d430d3d7e   Jason Baron   jump label: Intro...
493
494
495
  	struct jump_entry *iter_start = mod->jump_entries;
  	struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
  	struct jump_entry *iter;
c5905afb0   Ingo Molnar   static keys: Intr...
496
  	struct static_key *key = NULL;
3821fd35b   Jason Baron   jump_label: Reduc...
497
  	struct static_key_mod *jlm, *jlm2;
bf5438fca   Jason Baron   jump label: Base ...
498
499
  
  	/* if the module doesn't have jump label entries, just return */
d430d3d7e   Jason Baron   jump label: Intro...
500
  	if (iter_start == iter_stop)
bf5438fca   Jason Baron   jump label: Base ...
501
  		return 0;
d430d3d7e   Jason Baron   jump label: Intro...
502
503
504
  	jump_label_sort_entries(iter_start, iter_stop);
  
  	for (iter = iter_start; iter < iter_stop; iter++) {
c5905afb0   Ingo Molnar   static keys: Intr...
505
  		struct static_key *iterk;
d430d3d7e   Jason Baron   jump label: Intro...
506

7dcfd915b   Peter Zijlstra   jump_label: Add j...
507
  		iterk = jump_entry_key(iter);
c5905afb0   Ingo Molnar   static keys: Intr...
508
509
  		if (iterk == key)
  			continue;
d430d3d7e   Jason Baron   jump label: Intro...
510

c5905afb0   Ingo Molnar   static keys: Intr...
511
  		key = iterk;
bed831f9a   Peter Zijlstra   module, jump_labe...
512
  		if (within_module(iter->key, mod)) {
3821fd35b   Jason Baron   jump_label: Reduc...
513
  			static_key_set_entries(key, iter);
d430d3d7e   Jason Baron   jump label: Intro...
514
  			continue;
bf5438fca   Jason Baron   jump label: Base ...
515
  		}
c5905afb0   Ingo Molnar   static keys: Intr...
516
  		jlm = kzalloc(sizeof(struct static_key_mod), GFP_KERNEL);
d430d3d7e   Jason Baron   jump label: Intro...
517
518
  		if (!jlm)
  			return -ENOMEM;
3821fd35b   Jason Baron   jump_label: Reduc...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
  		if (!static_key_linked(key)) {
  			jlm2 = kzalloc(sizeof(struct static_key_mod),
  				       GFP_KERNEL);
  			if (!jlm2) {
  				kfree(jlm);
  				return -ENOMEM;
  			}
  			preempt_disable();
  			jlm2->mod = __module_address((unsigned long)key);
  			preempt_enable();
  			jlm2->entries = static_key_entries(key);
  			jlm2->next = NULL;
  			static_key_set_mod(key, jlm2);
  			static_key_set_linked(key);
  		}
d430d3d7e   Jason Baron   jump label: Intro...
534
535
  		jlm->mod = mod;
  		jlm->entries = iter;
3821fd35b   Jason Baron   jump_label: Reduc...
536
537
538
  		jlm->next = static_key_mod(key);
  		static_key_set_mod(key, jlm);
  		static_key_set_linked(key);
d430d3d7e   Jason Baron   jump label: Intro...
539

11276d530   Peter Zijlstra   locking/static_ke...
540
541
  		/* Only update if we've changed from our initial state */
  		if (jump_label_type(iter) != jump_label_init_type(iter))
706249c22   Peter Zijlstra   locking/static_ke...
542
  			__jump_label_update(key, iter, iter_stop);
bf5438fca   Jason Baron   jump label: Base ...
543
  	}
d430d3d7e   Jason Baron   jump label: Intro...
544

bf5438fca   Jason Baron   jump label: Base ...
545
546
  	return 0;
  }
d430d3d7e   Jason Baron   jump label: Intro...
547
  static void jump_label_del_module(struct module *mod)
bf5438fca   Jason Baron   jump label: Base ...
548
  {
d430d3d7e   Jason Baron   jump label: Intro...
549
550
551
  	struct jump_entry *iter_start = mod->jump_entries;
  	struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
  	struct jump_entry *iter;
c5905afb0   Ingo Molnar   static keys: Intr...
552
553
  	struct static_key *key = NULL;
  	struct static_key_mod *jlm, **prev;
bf5438fca   Jason Baron   jump label: Base ...
554

d430d3d7e   Jason Baron   jump label: Intro...
555
  	for (iter = iter_start; iter < iter_stop; iter++) {
7dcfd915b   Peter Zijlstra   jump_label: Add j...
556
  		if (jump_entry_key(iter) == key)
d430d3d7e   Jason Baron   jump label: Intro...
557
  			continue;
7dcfd915b   Peter Zijlstra   jump_label: Add j...
558
  		key = jump_entry_key(iter);
d430d3d7e   Jason Baron   jump label: Intro...
559

bed831f9a   Peter Zijlstra   module, jump_labe...
560
  		if (within_module(iter->key, mod))
d430d3d7e   Jason Baron   jump label: Intro...
561
  			continue;
3821fd35b   Jason Baron   jump_label: Reduc...
562
563
564
  		/* No memory during module load */
  		if (WARN_ON(!static_key_linked(key)))
  			continue;
d430d3d7e   Jason Baron   jump label: Intro...
565
  		prev = &key->next;
3821fd35b   Jason Baron   jump_label: Reduc...
566
  		jlm = static_key_mod(key);
bf5438fca   Jason Baron   jump label: Base ...
567

d430d3d7e   Jason Baron   jump label: Intro...
568
569
570
571
  		while (jlm && jlm->mod != mod) {
  			prev = &jlm->next;
  			jlm = jlm->next;
  		}
3821fd35b   Jason Baron   jump_label: Reduc...
572
573
574
575
576
577
578
  		/* No memory during module load */
  		if (WARN_ON(!jlm))
  			continue;
  
  		if (prev == &key->next)
  			static_key_set_mod(key, jlm->next);
  		else
d430d3d7e   Jason Baron   jump label: Intro...
579
  			*prev = jlm->next;
3821fd35b   Jason Baron   jump_label: Reduc...
580
581
582
583
584
585
586
587
  
  		kfree(jlm);
  
  		jlm = static_key_mod(key);
  		/* if only one etry is left, fold it back into the static_key */
  		if (jlm->next == NULL) {
  			static_key_set_entries(key, jlm->entries);
  			static_key_clear_linked(key);
d430d3d7e   Jason Baron   jump label: Intro...
588
  			kfree(jlm);
bf5438fca   Jason Baron   jump label: Base ...
589
590
591
  		}
  	}
  }
d430d3d7e   Jason Baron   jump label: Intro...
592
  static void jump_label_invalidate_module_init(struct module *mod)
b842f8faf   Jason Baron   jump label: Fix m...
593
  {
d430d3d7e   Jason Baron   jump label: Intro...
594
595
  	struct jump_entry *iter_start = mod->jump_entries;
  	struct jump_entry *iter_stop = iter_start + mod->num_jump_entries;
b842f8faf   Jason Baron   jump label: Fix m...
596
  	struct jump_entry *iter;
b842f8faf   Jason Baron   jump label: Fix m...
597

d430d3d7e   Jason Baron   jump label: Intro...
598
599
600
  	for (iter = iter_start; iter < iter_stop; iter++) {
  		if (within_module_init(iter->code, mod))
  			iter->code = 0;
b842f8faf   Jason Baron   jump label: Fix m...
601
602
  	}
  }
bf5438fca   Jason Baron   jump label: Base ...
603
604
605
606
607
608
  static int
  jump_label_module_notify(struct notifier_block *self, unsigned long val,
  			 void *data)
  {
  	struct module *mod = data;
  	int ret = 0;
f2545b2d4   Thomas Gleixner   jump_label: Reord...
609
610
  	cpus_read_lock();
  	jump_label_lock();
bf5438fca   Jason Baron   jump label: Base ...
611
612
  	switch (val) {
  	case MODULE_STATE_COMING:
d430d3d7e   Jason Baron   jump label: Intro...
613
  		ret = jump_label_add_module(mod);
3821fd35b   Jason Baron   jump_label: Reduc...
614
615
616
  		if (ret) {
  			WARN(1, "Failed to allocatote memory: jump_label may not work properly.
  ");
d430d3d7e   Jason Baron   jump label: Intro...
617
  			jump_label_del_module(mod);
3821fd35b   Jason Baron   jump_label: Reduc...
618
  		}
bf5438fca   Jason Baron   jump label: Base ...
619
620
  		break;
  	case MODULE_STATE_GOING:
d430d3d7e   Jason Baron   jump label: Intro...
621
  		jump_label_del_module(mod);
bf5438fca   Jason Baron   jump label: Base ...
622
  		break;
b842f8faf   Jason Baron   jump label: Fix m...
623
  	case MODULE_STATE_LIVE:
d430d3d7e   Jason Baron   jump label: Intro...
624
  		jump_label_invalidate_module_init(mod);
b842f8faf   Jason Baron   jump label: Fix m...
625
  		break;
bf5438fca   Jason Baron   jump label: Base ...
626
  	}
bf5438fca   Jason Baron   jump label: Base ...
627

f2545b2d4   Thomas Gleixner   jump_label: Reord...
628
629
  	jump_label_unlock();
  	cpus_read_unlock();
d430d3d7e   Jason Baron   jump label: Intro...
630
  	return notifier_from_errno(ret);
bf5438fca   Jason Baron   jump label: Base ...
631
  }
885885f6b   Wei Yongjun   locking/static_ke...
632
  static struct notifier_block jump_label_module_nb = {
bf5438fca   Jason Baron   jump label: Base ...
633
  	.notifier_call = jump_label_module_notify,
d430d3d7e   Jason Baron   jump label: Intro...
634
  	.priority = 1, /* higher than tracepoints */
bf5438fca   Jason Baron   jump label: Base ...
635
  };
d430d3d7e   Jason Baron   jump label: Intro...
636
  static __init int jump_label_init_module(void)
bf5438fca   Jason Baron   jump label: Base ...
637
638
639
  {
  	return register_module_notifier(&jump_label_module_nb);
  }
d430d3d7e   Jason Baron   jump label: Intro...
640
  early_initcall(jump_label_init_module);
bf5438fca   Jason Baron   jump label: Base ...
641
642
  
  #endif /* CONFIG_MODULES */
d430d3d7e   Jason Baron   jump label: Intro...
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  /***
   * jump_label_text_reserved - check if addr range is reserved
   * @start: start text addr
   * @end: end text addr
   *
   * checks if the text addr located between @start and @end
   * overlaps with any of the jump label patch addresses. Code
   * that wants to modify kernel text should first verify that
   * it does not overlap with any of the jump label addresses.
   * Caller must hold jump_label_mutex.
   *
   * returns 1 if there is an overlap, 0 otherwise
   */
  int jump_label_text_reserved(void *start, void *end)
  {
  	int ret = __jump_label_text_reserved(__start___jump_table,
  			__stop___jump_table, start, end);
  
  	if (ret)
  		return ret;
  
  #ifdef CONFIG_MODULES
  	ret = __jump_label_mod_text_reserved(start, end);
  #endif
  	return ret;
  }
706249c22   Peter Zijlstra   locking/static_ke...
669
  static void jump_label_update(struct static_key *key)
d430d3d7e   Jason Baron   jump label: Intro...
670
  {
c5905afb0   Ingo Molnar   static keys: Intr...
671
  	struct jump_entry *stop = __stop___jump_table;
3821fd35b   Jason Baron   jump_label: Reduc...
672
  	struct jump_entry *entry;
d430d3d7e   Jason Baron   jump label: Intro...
673
  #ifdef CONFIG_MODULES
bed831f9a   Peter Zijlstra   module, jump_labe...
674
  	struct module *mod;
140fe3b1a   Xiao Guangrong   jump_label: Fix j...
675

3821fd35b   Jason Baron   jump_label: Reduc...
676
677
678
679
  	if (static_key_linked(key)) {
  		__jump_label_mod_update(key);
  		return;
  	}
140fe3b1a   Xiao Guangrong   jump_label: Fix j...
680

bed831f9a   Peter Zijlstra   module, jump_labe...
681
682
  	preempt_disable();
  	mod = __module_address((unsigned long)key);
140fe3b1a   Xiao Guangrong   jump_label: Fix j...
683
684
  	if (mod)
  		stop = mod->jump_entries + mod->num_jump_entries;
bed831f9a   Peter Zijlstra   module, jump_labe...
685
  	preempt_enable();
d430d3d7e   Jason Baron   jump label: Intro...
686
  #endif
3821fd35b   Jason Baron   jump_label: Reduc...
687
  	entry = static_key_entries(key);
140fe3b1a   Xiao Guangrong   jump_label: Fix j...
688
689
  	/* if there are no users, entry can be NULL */
  	if (entry)
706249c22   Peter Zijlstra   locking/static_ke...
690
  		__jump_label_update(key, entry, stop);
d430d3d7e   Jason Baron   jump label: Intro...
691
  }
1987c947d   Peter Zijlstra   locking/static_ke...
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  #ifdef CONFIG_STATIC_KEYS_SELFTEST
  static DEFINE_STATIC_KEY_TRUE(sk_true);
  static DEFINE_STATIC_KEY_FALSE(sk_false);
  
  static __init int jump_label_test(void)
  {
  	int i;
  
  	for (i = 0; i < 2; i++) {
  		WARN_ON(static_key_enabled(&sk_true.key) != true);
  		WARN_ON(static_key_enabled(&sk_false.key) != false);
  
  		WARN_ON(!static_branch_likely(&sk_true));
  		WARN_ON(!static_branch_unlikely(&sk_true));
  		WARN_ON(static_branch_likely(&sk_false));
  		WARN_ON(static_branch_unlikely(&sk_false));
  
  		static_branch_disable(&sk_true);
  		static_branch_enable(&sk_false);
  
  		WARN_ON(static_key_enabled(&sk_true.key) == true);
  		WARN_ON(static_key_enabled(&sk_false.key) == false);
  
  		WARN_ON(static_branch_likely(&sk_true));
  		WARN_ON(static_branch_unlikely(&sk_true));
  		WARN_ON(!static_branch_likely(&sk_false));
  		WARN_ON(!static_branch_unlikely(&sk_false));
  
  		static_branch_enable(&sk_true);
  		static_branch_disable(&sk_false);
  	}
  
  	return 0;
  }
2de359062   Jason Baron   jump_label: Invok...
726
  early_initcall(jump_label_test);
1987c947d   Peter Zijlstra   locking/static_ke...
727
728
729
  #endif /* STATIC_KEYS_SELFTEST */
  
  #endif /* HAVE_JUMP_LABEL */