Blame view

kernel/jump_label.c 12.5 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>
bf5438fca   Jason Baron   jump label: Base ...
17
18
  
  #ifdef HAVE_JUMP_LABEL
bf5438fca   Jason Baron   jump label: Base ...
19
20
  /* mutex to protect coming/going of the the jump_label table */
  static DEFINE_MUTEX(jump_label_mutex);
91bad2f8d   Jason Baron   jump label: Fix d...
21
22
23
24
25
26
27
28
29
  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 ...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  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...
45
  jump_label_sort_entries(struct jump_entry *start, struct jump_entry *stop)
bf5438fca   Jason Baron   jump label: Base ...
46
47
48
49
50
51
52
  {
  	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...
53
  static void jump_label_update(struct static_key *key);
a1efb01fe   Peter Zijlstra   jump_label, locki...
54

c5905afb0   Ingo Molnar   static keys: Intr...
55
  void static_key_slow_inc(struct static_key *key)
bf5438fca   Jason Baron   jump label: Base ...
56
  {
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
57
  	STATIC_KEY_CHECK_USE();
d430d3d7e   Jason Baron   jump label: Intro...
58
59
  	if (atomic_inc_not_zero(&key->enabled))
  		return;
bf5438fca   Jason Baron   jump label: Base ...
60

d430d3d7e   Jason Baron   jump label: Intro...
61
  	jump_label_lock();
706249c22   Peter Zijlstra   locking/static_ke...
62
63
  	if (atomic_inc_return(&key->enabled) == 1)
  		jump_label_update(key);
d430d3d7e   Jason Baron   jump label: Intro...
64
  	jump_label_unlock();
bf5438fca   Jason Baron   jump label: Base ...
65
  }
c5905afb0   Ingo Molnar   static keys: Intr...
66
  EXPORT_SYMBOL_GPL(static_key_slow_inc);
bf5438fca   Jason Baron   jump label: Base ...
67

c5905afb0   Ingo Molnar   static keys: Intr...
68
  static void __static_key_slow_dec(struct static_key *key,
b20295207   Gleb Natapov   perf, core: Rate ...
69
  		unsigned long rate_limit, struct delayed_work *work)
bf5438fca   Jason Baron   jump label: Base ...
70
  {
fadf0464b   Jason Baron   jump label: Add a...
71
72
73
74
  	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...
75
  		return;
fadf0464b   Jason Baron   jump label: Add a...
76
  	}
bf5438fca   Jason Baron   jump label: Base ...
77

b20295207   Gleb Natapov   perf, core: Rate ...
78
79
80
  	if (rate_limit) {
  		atomic_inc(&key->enabled);
  		schedule_delayed_work(work, rate_limit);
c5905afb0   Ingo Molnar   static keys: Intr...
81
  	} else {
706249c22   Peter Zijlstra   locking/static_ke...
82
  		jump_label_update(key);
c5905afb0   Ingo Molnar   static keys: Intr...
83
  	}
91bad2f8d   Jason Baron   jump label: Fix d...
84
  	jump_label_unlock();
bf5438fca   Jason Baron   jump label: Base ...
85
  }
b20295207   Gleb Natapov   perf, core: Rate ...
86
87
  static void jump_label_update_timeout(struct work_struct *work)
  {
c5905afb0   Ingo Molnar   static keys: Intr...
88
89
90
  	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 ...
91
  }
c5905afb0   Ingo Molnar   static keys: Intr...
92
  void static_key_slow_dec(struct static_key *key)
b20295207   Gleb Natapov   perf, core: Rate ...
93
  {
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
94
  	STATIC_KEY_CHECK_USE();
c5905afb0   Ingo Molnar   static keys: Intr...
95
  	__static_key_slow_dec(key, 0, NULL);
b20295207   Gleb Natapov   perf, core: Rate ...
96
  }
c5905afb0   Ingo Molnar   static keys: Intr...
97
  EXPORT_SYMBOL_GPL(static_key_slow_dec);
b20295207   Gleb Natapov   perf, core: Rate ...
98

c5905afb0   Ingo Molnar   static keys: Intr...
99
  void static_key_slow_dec_deferred(struct static_key_deferred *key)
b20295207   Gleb Natapov   perf, core: Rate ...
100
  {
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
101
  	STATIC_KEY_CHECK_USE();
c5905afb0   Ingo Molnar   static keys: Intr...
102
  	__static_key_slow_dec(&key->key, key->timeout, &key->work);
b20295207   Gleb Natapov   perf, core: Rate ...
103
  }
c5905afb0   Ingo Molnar   static keys: Intr...
104
  EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred);
b20295207   Gleb Natapov   perf, core: Rate ...
105

c5905afb0   Ingo Molnar   static keys: Intr...
106
  void jump_label_rate_limit(struct static_key_deferred *key,
b20295207   Gleb Natapov   perf, core: Rate ...
107
108
  		unsigned long rl)
  {
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
109
  	STATIC_KEY_CHECK_USE();
b20295207   Gleb Natapov   perf, core: Rate ...
110
111
112
  	key->timeout = rl;
  	INIT_DELAYED_WORK(&key->work, jump_label_update_timeout);
  }
a181dc14e   Gleb Natapov   jump_label: Expor...
113
  EXPORT_SYMBOL_GPL(jump_label_rate_limit);
b20295207   Gleb Natapov   perf, core: Rate ...
114

4c3ef6d79   Jason Baron   jump label: Add j...
115
116
117
118
119
120
121
122
  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...
123
124
  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...
125
  {
4c3ef6d79   Jason Baron   jump label: Add j...
126
  	struct jump_entry *iter;
4c3ef6d79   Jason Baron   jump label: Add j...
127

4c3ef6d79   Jason Baron   jump label: Add j...
128
129
  	iter = iter_start;
  	while (iter < iter_stop) {
d430d3d7e   Jason Baron   jump label: Intro...
130
131
  		if (addr_conflict(iter, start, end))
  			return 1;
4c3ef6d79   Jason Baron   jump label: Add j...
132
133
  		iter++;
  	}
d430d3d7e   Jason Baron   jump label: Intro...
134
135
  	return 0;
  }
706249c22   Peter Zijlstra   locking/static_ke...
136
  /*
20284aa77   Jeremy Fitzhardinge   jump_label: add a...
137
138
139
140
141
   * 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: ...
142
  void __weak __init_or_module arch_jump_label_transform_static(struct jump_entry *entry,
20284aa77   Jeremy Fitzhardinge   jump_label: add a...
143
144
  					    enum jump_label_type type)
  {
706249c22   Peter Zijlstra   locking/static_ke...
145
  	arch_jump_label_transform(entry, type);
20284aa77   Jeremy Fitzhardinge   jump_label: add a...
146
  }
706249c22   Peter Zijlstra   locking/static_ke...
147
  static inline struct jump_entry *static_key_entries(struct static_key *key)
d430d3d7e   Jason Baron   jump label: Intro...
148
  {
706249c22   Peter Zijlstra   locking/static_ke...
149
  	return (struct jump_entry *)((unsigned long)key->entries & ~JUMP_TYPE_MASK);
4c3ef6d79   Jason Baron   jump label: Add j...
150
  }
706249c22   Peter Zijlstra   locking/static_ke...
151
  static inline bool static_key_type(struct static_key *key)
c5905afb0   Ingo Molnar   static keys: Intr...
152
  {
706249c22   Peter Zijlstra   locking/static_ke...
153
  	return (unsigned long)key->entries & JUMP_TYPE_MASK;
a1efb01fe   Peter Zijlstra   jump_label, locki...
154
  }
c5905afb0   Ingo Molnar   static keys: Intr...
155

7dcfd915b   Peter Zijlstra   jump_label: Add j...
156
157
  static inline struct static_key *jump_entry_key(struct jump_entry *entry)
  {
11276d530   Peter Zijlstra   locking/static_ke...
158
159
160
161
162
163
  	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...
164
  }
706249c22   Peter Zijlstra   locking/static_ke...
165
  static enum jump_label_type jump_label_type(struct jump_entry *entry)
a1efb01fe   Peter Zijlstra   jump_label, locki...
166
  {
706249c22   Peter Zijlstra   locking/static_ke...
167
  	struct static_key *key = jump_entry_key(entry);
a1efb01fe   Peter Zijlstra   jump_label, locki...
168
  	bool enabled = static_key_enabled(key);
11276d530   Peter Zijlstra   locking/static_ke...
169
  	bool branch = jump_entry_branch(entry);
c5905afb0   Ingo Molnar   static keys: Intr...
170

11276d530   Peter Zijlstra   locking/static_ke...
171
172
  	/* See the comment in linux/jump_label.h */
  	return enabled ^ branch;
c5905afb0   Ingo Molnar   static keys: Intr...
173
  }
706249c22   Peter Zijlstra   locking/static_ke...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  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...
188
  void __init jump_label_init(void)
bf5438fca   Jason Baron   jump label: Base ...
189
  {
bf5438fca   Jason Baron   jump label: Base ...
190
191
  	struct jump_entry *iter_start = __start___jump_table;
  	struct jump_entry *iter_stop = __stop___jump_table;
c5905afb0   Ingo Molnar   static keys: Intr...
192
  	struct static_key *key = NULL;
bf5438fca   Jason Baron   jump label: Base ...
193
  	struct jump_entry *iter;
91bad2f8d   Jason Baron   jump label: Fix d...
194
  	jump_label_lock();
d430d3d7e   Jason Baron   jump label: Intro...
195
196
197
  	jump_label_sort_entries(iter_start, iter_stop);
  
  	for (iter = iter_start; iter < iter_stop; iter++) {
c5905afb0   Ingo Molnar   static keys: Intr...
198
  		struct static_key *iterk;
37348804e   Jeremy Fitzhardinge   jump_label: if a ...
199

11276d530   Peter Zijlstra   locking/static_ke...
200
201
202
  		/* 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...
203
  		iterk = jump_entry_key(iter);
37348804e   Jeremy Fitzhardinge   jump_label: if a ...
204
  		if (iterk == key)
d430d3d7e   Jason Baron   jump label: Intro...
205
  			continue;
37348804e   Jeremy Fitzhardinge   jump_label: if a ...
206
  		key = iterk;
c5905afb0   Ingo Molnar   static keys: Intr...
207
208
209
210
  		/*
  		 * Set key->entries to iter, but preserve JUMP_LABEL_TRUE_BRANCH.
  		 */
  		*((unsigned long *)&key->entries) += (unsigned long)iter;
d430d3d7e   Jason Baron   jump label: Intro...
211
212
213
  #ifdef CONFIG_MODULES
  		key->next = NULL;
  #endif
bf5438fca   Jason Baron   jump label: Base ...
214
  	}
c4b2c0c5f   Hannes Frederic Sowa   static_key: WARN ...
215
  	static_key_initialized = true;
91bad2f8d   Jason Baron   jump label: Fix d...
216
  	jump_label_unlock();
bf5438fca   Jason Baron   jump label: Base ...
217
  }
bf5438fca   Jason Baron   jump label: Base ...
218
219
  
  #ifdef CONFIG_MODULES
11276d530   Peter Zijlstra   locking/static_ke...
220
221
222
223
224
225
226
227
228
  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...
229
230
  struct static_key_mod {
  	struct static_key_mod *next;
d430d3d7e   Jason Baron   jump label: Intro...
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  	struct jump_entry *entries;
  	struct module *mod;
  };
  
  static int __jump_label_mod_text_reserved(void *start, void *end)
  {
  	struct module *mod;
  
  	mod = __module_text_address((unsigned long)start);
  	if (!mod)
  		return 0;
  
  	WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
  
  	return __jump_label_text_reserved(mod->jump_entries,
  				mod->jump_entries + mod->num_jump_entries,
  				start, end);
  }
706249c22   Peter Zijlstra   locking/static_ke...
249
  static void __jump_label_mod_update(struct static_key *key)
d430d3d7e   Jason Baron   jump label: Intro...
250
  {
706249c22   Peter Zijlstra   locking/static_ke...
251
  	struct static_key_mod *mod;
d430d3d7e   Jason Baron   jump label: Intro...
252

706249c22   Peter Zijlstra   locking/static_ke...
253
  	for (mod = key->next; mod; mod = mod->next) {
7cbc5b8d4   Jiri Olsa   jump_label: Check...
254
255
256
  		struct module *m = mod->mod;
  
  		__jump_label_update(key, mod->entries,
706249c22   Peter Zijlstra   locking/static_ke...
257
  				    m->jump_entries + m->num_jump_entries);
d430d3d7e   Jason Baron   jump label: Intro...
258
259
260
261
262
263
264
265
266
267
268
269
  	}
  }
  
  /***
   * 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 ...
270
  {
d430d3d7e   Jason Baron   jump label: Intro...
271
272
273
274
275
276
277
  	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...
278
279
280
281
282
  	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 ...
283
  }
d430d3d7e   Jason Baron   jump label: Intro...
284
  static int jump_label_add_module(struct module *mod)
bf5438fca   Jason Baron   jump label: Base ...
285
  {
d430d3d7e   Jason Baron   jump label: Intro...
286
287
288
  	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...
289
290
  	struct static_key *key = NULL;
  	struct static_key_mod *jlm;
bf5438fca   Jason Baron   jump label: Base ...
291
292
  
  	/* if the module doesn't have jump label entries, just return */
d430d3d7e   Jason Baron   jump label: Intro...
293
  	if (iter_start == iter_stop)
bf5438fca   Jason Baron   jump label: Base ...
294
  		return 0;
d430d3d7e   Jason Baron   jump label: Intro...
295
296
297
  	jump_label_sort_entries(iter_start, iter_stop);
  
  	for (iter = iter_start; iter < iter_stop; iter++) {
c5905afb0   Ingo Molnar   static keys: Intr...
298
  		struct static_key *iterk;
d430d3d7e   Jason Baron   jump label: Intro...
299

7dcfd915b   Peter Zijlstra   jump_label: Add j...
300
  		iterk = jump_entry_key(iter);
c5905afb0   Ingo Molnar   static keys: Intr...
301
302
  		if (iterk == key)
  			continue;
d430d3d7e   Jason Baron   jump label: Intro...
303

c5905afb0   Ingo Molnar   static keys: Intr...
304
  		key = iterk;
bed831f9a   Peter Zijlstra   module, jump_labe...
305
  		if (within_module(iter->key, mod)) {
c5905afb0   Ingo Molnar   static keys: Intr...
306
307
308
309
  			/*
  			 * Set key->entries to iter, but preserve JUMP_LABEL_TRUE_BRANCH.
  			 */
  			*((unsigned long *)&key->entries) += (unsigned long)iter;
d430d3d7e   Jason Baron   jump label: Intro...
310
311
  			key->next = NULL;
  			continue;
bf5438fca   Jason Baron   jump label: Base ...
312
  		}
c5905afb0   Ingo Molnar   static keys: Intr...
313
  		jlm = kzalloc(sizeof(struct static_key_mod), GFP_KERNEL);
d430d3d7e   Jason Baron   jump label: Intro...
314
315
  		if (!jlm)
  			return -ENOMEM;
d430d3d7e   Jason Baron   jump label: Intro...
316
317
318
319
  		jlm->mod = mod;
  		jlm->entries = iter;
  		jlm->next = key->next;
  		key->next = jlm;
11276d530   Peter Zijlstra   locking/static_ke...
320
321
  		/* 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...
322
  			__jump_label_update(key, iter, iter_stop);
bf5438fca   Jason Baron   jump label: Base ...
323
  	}
d430d3d7e   Jason Baron   jump label: Intro...
324

bf5438fca   Jason Baron   jump label: Base ...
325
326
  	return 0;
  }
d430d3d7e   Jason Baron   jump label: Intro...
327
  static void jump_label_del_module(struct module *mod)
bf5438fca   Jason Baron   jump label: Base ...
328
  {
d430d3d7e   Jason Baron   jump label: Intro...
329
330
331
  	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...
332
333
  	struct static_key *key = NULL;
  	struct static_key_mod *jlm, **prev;
bf5438fca   Jason Baron   jump label: Base ...
334

d430d3d7e   Jason Baron   jump label: Intro...
335
  	for (iter = iter_start; iter < iter_stop; iter++) {
7dcfd915b   Peter Zijlstra   jump_label: Add j...
336
  		if (jump_entry_key(iter) == key)
d430d3d7e   Jason Baron   jump label: Intro...
337
  			continue;
7dcfd915b   Peter Zijlstra   jump_label: Add j...
338
  		key = jump_entry_key(iter);
d430d3d7e   Jason Baron   jump label: Intro...
339

bed831f9a   Peter Zijlstra   module, jump_labe...
340
  		if (within_module(iter->key, mod))
d430d3d7e   Jason Baron   jump label: Intro...
341
342
343
344
  			continue;
  
  		prev = &key->next;
  		jlm = key->next;
bf5438fca   Jason Baron   jump label: Base ...
345

d430d3d7e   Jason Baron   jump label: Intro...
346
347
348
349
350
351
352
353
  		while (jlm && jlm->mod != mod) {
  			prev = &jlm->next;
  			jlm = jlm->next;
  		}
  
  		if (jlm) {
  			*prev = jlm->next;
  			kfree(jlm);
bf5438fca   Jason Baron   jump label: Base ...
354
355
356
  		}
  	}
  }
d430d3d7e   Jason Baron   jump label: Intro...
357
  static void jump_label_invalidate_module_init(struct module *mod)
b842f8faf   Jason Baron   jump label: Fix m...
358
  {
d430d3d7e   Jason Baron   jump label: Intro...
359
360
  	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...
361
  	struct jump_entry *iter;
b842f8faf   Jason Baron   jump label: Fix m...
362

d430d3d7e   Jason Baron   jump label: Intro...
363
364
365
  	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...
366
367
  	}
  }
bf5438fca   Jason Baron   jump label: Base ...
368
369
370
371
372
373
374
375
376
  static int
  jump_label_module_notify(struct notifier_block *self, unsigned long val,
  			 void *data)
  {
  	struct module *mod = data;
  	int ret = 0;
  
  	switch (val) {
  	case MODULE_STATE_COMING:
91bad2f8d   Jason Baron   jump label: Fix d...
377
  		jump_label_lock();
d430d3d7e   Jason Baron   jump label: Intro...
378
  		ret = jump_label_add_module(mod);
bf5438fca   Jason Baron   jump label: Base ...
379
  		if (ret)
d430d3d7e   Jason Baron   jump label: Intro...
380
  			jump_label_del_module(mod);
91bad2f8d   Jason Baron   jump label: Fix d...
381
  		jump_label_unlock();
bf5438fca   Jason Baron   jump label: Base ...
382
383
  		break;
  	case MODULE_STATE_GOING:
91bad2f8d   Jason Baron   jump label: Fix d...
384
  		jump_label_lock();
d430d3d7e   Jason Baron   jump label: Intro...
385
  		jump_label_del_module(mod);
91bad2f8d   Jason Baron   jump label: Fix d...
386
  		jump_label_unlock();
bf5438fca   Jason Baron   jump label: Base ...
387
  		break;
b842f8faf   Jason Baron   jump label: Fix m...
388
  	case MODULE_STATE_LIVE:
91bad2f8d   Jason Baron   jump label: Fix d...
389
  		jump_label_lock();
d430d3d7e   Jason Baron   jump label: Intro...
390
  		jump_label_invalidate_module_init(mod);
91bad2f8d   Jason Baron   jump label: Fix d...
391
  		jump_label_unlock();
b842f8faf   Jason Baron   jump label: Fix m...
392
  		break;
bf5438fca   Jason Baron   jump label: Base ...
393
  	}
bf5438fca   Jason Baron   jump label: Base ...
394

d430d3d7e   Jason Baron   jump label: Intro...
395
  	return notifier_from_errno(ret);
bf5438fca   Jason Baron   jump label: Base ...
396
397
398
399
  }
  
  struct notifier_block jump_label_module_nb = {
  	.notifier_call = jump_label_module_notify,
d430d3d7e   Jason Baron   jump label: Intro...
400
  	.priority = 1, /* higher than tracepoints */
bf5438fca   Jason Baron   jump label: Base ...
401
  };
d430d3d7e   Jason Baron   jump label: Intro...
402
  static __init int jump_label_init_module(void)
bf5438fca   Jason Baron   jump label: Base ...
403
404
405
  {
  	return register_module_notifier(&jump_label_module_nb);
  }
d430d3d7e   Jason Baron   jump label: Intro...
406
  early_initcall(jump_label_init_module);
bf5438fca   Jason Baron   jump label: Base ...
407
408
  
  #endif /* CONFIG_MODULES */
d430d3d7e   Jason Baron   jump label: Intro...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  /***
   * 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...
435
  static void jump_label_update(struct static_key *key)
d430d3d7e   Jason Baron   jump label: Intro...
436
  {
c5905afb0   Ingo Molnar   static keys: Intr...
437
  	struct jump_entry *stop = __stop___jump_table;
a1efb01fe   Peter Zijlstra   jump_label, locki...
438
  	struct jump_entry *entry = static_key_entries(key);
d430d3d7e   Jason Baron   jump label: Intro...
439
  #ifdef CONFIG_MODULES
bed831f9a   Peter Zijlstra   module, jump_labe...
440
  	struct module *mod;
140fe3b1a   Xiao Guangrong   jump_label: Fix j...
441

706249c22   Peter Zijlstra   locking/static_ke...
442
  	__jump_label_mod_update(key);
140fe3b1a   Xiao Guangrong   jump_label: Fix j...
443

bed831f9a   Peter Zijlstra   module, jump_labe...
444
445
  	preempt_disable();
  	mod = __module_address((unsigned long)key);
140fe3b1a   Xiao Guangrong   jump_label: Fix j...
446
447
  	if (mod)
  		stop = mod->jump_entries + mod->num_jump_entries;
bed831f9a   Peter Zijlstra   module, jump_labe...
448
  	preempt_enable();
d430d3d7e   Jason Baron   jump label: Intro...
449
  #endif
140fe3b1a   Xiao Guangrong   jump_label: Fix j...
450
451
  	/* if there are no users, entry can be NULL */
  	if (entry)
706249c22   Peter Zijlstra   locking/static_ke...
452
  		__jump_label_update(key, entry, stop);
d430d3d7e   Jason Baron   jump label: Intro...
453
  }
1987c947d   Peter Zijlstra   locking/static_ke...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  #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;
  }
  late_initcall(jump_label_test);
  #endif /* STATIC_KEYS_SELFTEST */
  
  #endif /* HAVE_JUMP_LABEL */