Commit | Line | Data |
---|---|---|
fe9d4f57 AD |
1 | #include <linux/kdebug.h> |
2 | #include <linux/kprobes.h> | |
9984de1a | 3 | #include <linux/export.h> |
fe9d4f57 AD |
4 | #include <linux/notifier.h> |
5 | #include <linux/rcupdate.h> | |
6 | #include <linux/vmalloc.h> | |
c166f23c | 7 | #include <linux/reboot.h> |
6fa3eb70 S |
8 | /******************************************************************************* |
9 | * 20131225 marc.huang * | |
10 | * CPU Hotplug debug mechanism * | |
11 | *******************************************************************************/ | |
12 | #include <linux/mtk_ram_console.h> | |
13 | /******************************************************************************/ | |
fe9d4f57 AD |
14 | |
15 | /* | |
16 | * Notifier list for kernel code which wants to be called | |
17 | * at shutdown. This is used to stop any idling DMA operations | |
18 | * and the like. | |
19 | */ | |
20 | BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); | |
21 | ||
22 | /* | |
23 | * Notifier chain core routines. The exported routines below | |
24 | * are layered on top of these, with appropriate locking added. | |
25 | */ | |
26 | ||
27 | static int notifier_chain_register(struct notifier_block **nl, | |
28 | struct notifier_block *n) | |
29 | { | |
30 | while ((*nl) != NULL) { | |
31 | if (n->priority > (*nl)->priority) | |
32 | break; | |
33 | nl = &((*nl)->next); | |
34 | } | |
35 | n->next = *nl; | |
36 | rcu_assign_pointer(*nl, n); | |
37 | return 0; | |
38 | } | |
39 | ||
6546bc42 ND |
40 | static int notifier_chain_cond_register(struct notifier_block **nl, |
41 | struct notifier_block *n) | |
42 | { | |
43 | while ((*nl) != NULL) { | |
44 | if ((*nl) == n) | |
45 | return 0; | |
46 | if (n->priority > (*nl)->priority) | |
47 | break; | |
48 | nl = &((*nl)->next); | |
49 | } | |
50 | n->next = *nl; | |
51 | rcu_assign_pointer(*nl, n); | |
52 | return 0; | |
53 | } | |
54 | ||
fe9d4f57 AD |
55 | static int notifier_chain_unregister(struct notifier_block **nl, |
56 | struct notifier_block *n) | |
57 | { | |
58 | while ((*nl) != NULL) { | |
59 | if ((*nl) == n) { | |
60 | rcu_assign_pointer(*nl, n->next); | |
61 | return 0; | |
62 | } | |
63 | nl = &((*nl)->next); | |
64 | } | |
65 | return -ENOENT; | |
66 | } | |
67 | ||
68 | /** | |
69 | * notifier_call_chain - Informs the registered notifiers about an event. | |
70 | * @nl: Pointer to head of the blocking notifier chain | |
71 | * @val: Value passed unmodified to notifier function | |
72 | * @v: Pointer passed unmodified to notifier function | |
73 | * @nr_to_call: Number of notifier functions to be called. Don't care | |
74 | * value of this parameter is -1. | |
75 | * @nr_calls: Records the number of notifications sent. Don't care | |
76 | * value of this field is NULL. | |
77 | * @returns: notifier_call_chain returns the value returned by the | |
78 | * last notifier function called. | |
79 | */ | |
80 | static int __kprobes notifier_call_chain(struct notifier_block **nl, | |
81 | unsigned long val, void *v, | |
82 | int nr_to_call, int *nr_calls) | |
83 | { | |
84 | int ret = NOTIFY_DONE; | |
85 | struct notifier_block *nb, *next_nb; | |
6fa3eb70 S |
86 | /******************************************************************************* |
87 | * 20131225 marc.huang * | |
88 | * CPU Hotplug debug mechanism * | |
89 | *******************************************************************************/ | |
90 | #if defined(CONFIG_SMP) && (defined(MTK_CPU_HOTPLUG_DEBUG_1) || defined(MTK_CPU_HOTPLUG_DEBUG_2)) | |
91 | int index = 0; | |
92 | extern struct raw_notifier_head cpu_chain; | |
93 | #endif //#if defined(CONFIG_SMP) && (defined(MTK_CPU_HOTPLUG_DEBUG_1) || defined(MTK_CPU_HOTPLUG_DEBUG_2)) | |
94 | /******************************************************************************/ | |
fe9d4f57 | 95 | |
d11c563d | 96 | nb = rcu_dereference_raw(*nl); |
fe9d4f57 AD |
97 | |
98 | while (nb && nr_to_call) { | |
d11c563d | 99 | next_nb = rcu_dereference_raw(nb->next); |
1b2439db AV |
100 | |
101 | #ifdef CONFIG_DEBUG_NOTIFIERS | |
ab7476cf | 102 | if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) { |
1b2439db AV |
103 | WARN(1, "Invalid notifier called!"); |
104 | nb = next_nb; | |
105 | continue; | |
106 | } | |
107 | #endif | |
6fa3eb70 S |
108 | |
109 | /******************************************************************************* | |
110 | * 20131225 marc.huang * | |
111 | * CPU Hotplug debug mechanism * | |
112 | *******************************************************************************/ | |
113 | #if defined(CONFIG_SMP) && (defined(MTK_CPU_HOTPLUG_DEBUG_1) || defined(MTK_CPU_HOTPLUG_DEBUG_2)) | |
114 | if (nl == &cpu_chain.head) | |
115 | { | |
116 | #if defined(MTK_CPU_HOTPLUG_DEBUG_1) | |
117 | printk(KERN_DEBUG "[cpu_ntf] %02lx_%02d, %p\n", val, index, nb->notifier_call); | |
118 | #endif //#if defined(MTK_CPU_HOTPLUG_DEBUG_1) | |
119 | #if defined(MTK_CPU_HOTPLUG_DEBUG_2) | |
120 | aee_rr_rec_hotplug(0, val & 0xff, index & 0xff, (unsigned long)nb->notifier_call); | |
121 | #endif //#if defined(MTK_CPU_HOTPLUG_DEBUG_2) | |
122 | ++index; | |
123 | } | |
124 | #endif //#if defined(CONFIG_SMP) && (defined(MTK_CPU_HOTPLUG_DEBUG_1) || defined(MTK_CPU_HOTPLUG_DEBUG_2)) | |
125 | /******************************************************************************/ | |
126 | ||
fe9d4f57 AD |
127 | ret = nb->notifier_call(nb, val, v); |
128 | ||
129 | if (nr_calls) | |
130 | (*nr_calls)++; | |
131 | ||
132 | if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) | |
133 | break; | |
134 | nb = next_nb; | |
135 | nr_to_call--; | |
136 | } | |
6fa3eb70 S |
137 | /******************************************************************************* |
138 | * 20131225 marc.huang * | |
139 | * CPU Hotplug debug mechanism * | |
140 | *******************************************************************************/ | |
141 | #if defined(CONFIG_SMP) && (defined(MTK_CPU_HOTPLUG_DEBUG_1) || defined(MTK_CPU_HOTPLUG_DEBUG_2)) | |
142 | if (nl == &cpu_chain.head) | |
143 | { | |
144 | #if defined(MTK_CPU_HOTPLUG_DEBUG_1) | |
145 | printk(KERN_DEBUG "[cpu_ntf] %02lx_%02d, %p\n", val, index, 0); | |
146 | #endif //#if defined(MTK_CPU_HOTPLUG_DEBUG_1) | |
147 | #if defined(MTK_CPU_HOTPLUG_DEBUG_2) | |
148 | //aee_rr_rec_hoplug(0, val & 0xff, index & 0xff); | |
149 | aee_rr_rec_hotplug(0, val & 0xff, index & 0xff, 0); | |
150 | #endif //#if defined(MTK_CPU_HOTPLUG_DEBUG_2) | |
151 | } | |
152 | #endif //#if defined(CONFIG_SMP) && (defined(MTK_CPU_HOTPLUG_DEBUG_1) || defined(MTK_CPU_HOTPLUG_DEBUG_2)) | |
153 | /******************************************************************************/ | |
fe9d4f57 AD |
154 | return ret; |
155 | } | |
156 | ||
157 | /* | |
158 | * Atomic notifier chain routines. Registration and unregistration | |
159 | * use a spinlock, and call_chain is synchronized by RCU (no locks). | |
160 | */ | |
161 | ||
162 | /** | |
163 | * atomic_notifier_chain_register - Add notifier to an atomic notifier chain | |
164 | * @nh: Pointer to head of the atomic notifier chain | |
165 | * @n: New entry in notifier chain | |
166 | * | |
167 | * Adds a notifier to an atomic notifier chain. | |
168 | * | |
169 | * Currently always returns zero. | |
170 | */ | |
171 | int atomic_notifier_chain_register(struct atomic_notifier_head *nh, | |
172 | struct notifier_block *n) | |
173 | { | |
174 | unsigned long flags; | |
175 | int ret; | |
176 | ||
177 | spin_lock_irqsave(&nh->lock, flags); | |
178 | ret = notifier_chain_register(&nh->head, n); | |
179 | spin_unlock_irqrestore(&nh->lock, flags); | |
180 | return ret; | |
181 | } | |
182 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); | |
183 | ||
184 | /** | |
185 | * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain | |
186 | * @nh: Pointer to head of the atomic notifier chain | |
187 | * @n: Entry to remove from notifier chain | |
188 | * | |
189 | * Removes a notifier from an atomic notifier chain. | |
190 | * | |
191 | * Returns zero on success or %-ENOENT on failure. | |
192 | */ | |
193 | int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, | |
194 | struct notifier_block *n) | |
195 | { | |
196 | unsigned long flags; | |
197 | int ret; | |
198 | ||
199 | spin_lock_irqsave(&nh->lock, flags); | |
200 | ret = notifier_chain_unregister(&nh->head, n); | |
201 | spin_unlock_irqrestore(&nh->lock, flags); | |
202 | synchronize_rcu(); | |
203 | return ret; | |
204 | } | |
205 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); | |
206 | ||
207 | /** | |
208 | * __atomic_notifier_call_chain - Call functions in an atomic notifier chain | |
209 | * @nh: Pointer to head of the atomic notifier chain | |
210 | * @val: Value passed unmodified to notifier function | |
211 | * @v: Pointer passed unmodified to notifier function | |
212 | * @nr_to_call: See the comment for notifier_call_chain. | |
213 | * @nr_calls: See the comment for notifier_call_chain. | |
214 | * | |
215 | * Calls each function in a notifier chain in turn. The functions | |
216 | * run in an atomic context, so they must not block. | |
217 | * This routine uses RCU to synchronize with changes to the chain. | |
218 | * | |
219 | * If the return value of the notifier can be and'ed | |
220 | * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain() | |
221 | * will return immediately, with the return value of | |
222 | * the notifier function which halted execution. | |
223 | * Otherwise the return value is the return value | |
224 | * of the last notifier function called. | |
225 | */ | |
226 | int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh, | |
227 | unsigned long val, void *v, | |
228 | int nr_to_call, int *nr_calls) | |
229 | { | |
230 | int ret; | |
231 | ||
232 | rcu_read_lock(); | |
233 | ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); | |
234 | rcu_read_unlock(); | |
235 | return ret; | |
236 | } | |
237 | EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain); | |
238 | ||
239 | int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh, | |
240 | unsigned long val, void *v) | |
241 | { | |
242 | return __atomic_notifier_call_chain(nh, val, v, -1, NULL); | |
243 | } | |
244 | EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); | |
245 | ||
246 | /* | |
247 | * Blocking notifier chain routines. All access to the chain is | |
248 | * synchronized by an rwsem. | |
249 | */ | |
250 | ||
251 | /** | |
252 | * blocking_notifier_chain_register - Add notifier to a blocking notifier chain | |
253 | * @nh: Pointer to head of the blocking notifier chain | |
254 | * @n: New entry in notifier chain | |
255 | * | |
256 | * Adds a notifier to a blocking notifier chain. | |
257 | * Must be called in process context. | |
258 | * | |
259 | * Currently always returns zero. | |
260 | */ | |
261 | int blocking_notifier_chain_register(struct blocking_notifier_head *nh, | |
262 | struct notifier_block *n) | |
263 | { | |
264 | int ret; | |
265 | ||
266 | /* | |
267 | * This code gets used during boot-up, when task switching is | |
268 | * not yet working and interrupts must remain disabled. At | |
269 | * such times we must not call down_write(). | |
270 | */ | |
271 | if (unlikely(system_state == SYSTEM_BOOTING)) | |
272 | return notifier_chain_register(&nh->head, n); | |
273 | ||
274 | down_write(&nh->rwsem); | |
275 | ret = notifier_chain_register(&nh->head, n); | |
276 | up_write(&nh->rwsem); | |
277 | return ret; | |
278 | } | |
279 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); | |
280 | ||
6546bc42 ND |
281 | /** |
282 | * blocking_notifier_chain_cond_register - Cond add notifier to a blocking notifier chain | |
283 | * @nh: Pointer to head of the blocking notifier chain | |
284 | * @n: New entry in notifier chain | |
285 | * | |
286 | * Adds a notifier to a blocking notifier chain, only if not already | |
287 | * present in the chain. | |
288 | * Must be called in process context. | |
289 | * | |
290 | * Currently always returns zero. | |
291 | */ | |
292 | int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh, | |
293 | struct notifier_block *n) | |
294 | { | |
295 | int ret; | |
296 | ||
297 | down_write(&nh->rwsem); | |
298 | ret = notifier_chain_cond_register(&nh->head, n); | |
299 | up_write(&nh->rwsem); | |
300 | return ret; | |
301 | } | |
302 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_cond_register); | |
303 | ||
fe9d4f57 AD |
304 | /** |
305 | * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain | |
306 | * @nh: Pointer to head of the blocking notifier chain | |
307 | * @n: Entry to remove from notifier chain | |
308 | * | |
309 | * Removes a notifier from a blocking notifier chain. | |
310 | * Must be called from process context. | |
311 | * | |
312 | * Returns zero on success or %-ENOENT on failure. | |
313 | */ | |
314 | int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, | |
315 | struct notifier_block *n) | |
316 | { | |
317 | int ret; | |
318 | ||
319 | /* | |
320 | * This code gets used during boot-up, when task switching is | |
321 | * not yet working and interrupts must remain disabled. At | |
322 | * such times we must not call down_write(). | |
323 | */ | |
324 | if (unlikely(system_state == SYSTEM_BOOTING)) | |
325 | return notifier_chain_unregister(&nh->head, n); | |
326 | ||
327 | down_write(&nh->rwsem); | |
328 | ret = notifier_chain_unregister(&nh->head, n); | |
329 | up_write(&nh->rwsem); | |
330 | return ret; | |
331 | } | |
332 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); | |
333 | ||
334 | /** | |
335 | * __blocking_notifier_call_chain - Call functions in a blocking notifier chain | |
336 | * @nh: Pointer to head of the blocking notifier chain | |
337 | * @val: Value passed unmodified to notifier function | |
338 | * @v: Pointer passed unmodified to notifier function | |
339 | * @nr_to_call: See comment for notifier_call_chain. | |
340 | * @nr_calls: See comment for notifier_call_chain. | |
341 | * | |
342 | * Calls each function in a notifier chain in turn. The functions | |
343 | * run in a process context, so they are allowed to block. | |
344 | * | |
345 | * If the return value of the notifier can be and'ed | |
346 | * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain() | |
347 | * will return immediately, with the return value of | |
348 | * the notifier function which halted execution. | |
349 | * Otherwise the return value is the return value | |
350 | * of the last notifier function called. | |
351 | */ | |
352 | int __blocking_notifier_call_chain(struct blocking_notifier_head *nh, | |
353 | unsigned long val, void *v, | |
354 | int nr_to_call, int *nr_calls) | |
355 | { | |
356 | int ret = NOTIFY_DONE; | |
357 | ||
358 | /* | |
359 | * We check the head outside the lock, but if this access is | |
360 | * racy then it does not matter what the result of the test | |
361 | * is, we re-check the list after having taken the lock anyway: | |
362 | */ | |
d11c563d | 363 | if (rcu_dereference_raw(nh->head)) { |
fe9d4f57 AD |
364 | down_read(&nh->rwsem); |
365 | ret = notifier_call_chain(&nh->head, val, v, nr_to_call, | |
366 | nr_calls); | |
367 | up_read(&nh->rwsem); | |
368 | } | |
369 | return ret; | |
370 | } | |
371 | EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain); | |
372 | ||
373 | int blocking_notifier_call_chain(struct blocking_notifier_head *nh, | |
374 | unsigned long val, void *v) | |
375 | { | |
376 | return __blocking_notifier_call_chain(nh, val, v, -1, NULL); | |
377 | } | |
378 | EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); | |
379 | ||
380 | /* | |
381 | * Raw notifier chain routines. There is no protection; | |
382 | * the caller must provide it. Use at your own risk! | |
383 | */ | |
384 | ||
385 | /** | |
386 | * raw_notifier_chain_register - Add notifier to a raw notifier chain | |
387 | * @nh: Pointer to head of the raw notifier chain | |
388 | * @n: New entry in notifier chain | |
389 | * | |
390 | * Adds a notifier to a raw notifier chain. | |
391 | * All locking must be provided by the caller. | |
392 | * | |
393 | * Currently always returns zero. | |
394 | */ | |
395 | int raw_notifier_chain_register(struct raw_notifier_head *nh, | |
396 | struct notifier_block *n) | |
397 | { | |
398 | return notifier_chain_register(&nh->head, n); | |
399 | } | |
400 | EXPORT_SYMBOL_GPL(raw_notifier_chain_register); | |
401 | ||
402 | /** | |
403 | * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain | |
404 | * @nh: Pointer to head of the raw notifier chain | |
405 | * @n: Entry to remove from notifier chain | |
406 | * | |
407 | * Removes a notifier from a raw notifier chain. | |
408 | * All locking must be provided by the caller. | |
409 | * | |
410 | * Returns zero on success or %-ENOENT on failure. | |
411 | */ | |
412 | int raw_notifier_chain_unregister(struct raw_notifier_head *nh, | |
413 | struct notifier_block *n) | |
414 | { | |
415 | return notifier_chain_unregister(&nh->head, n); | |
416 | } | |
417 | EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); | |
418 | ||
419 | /** | |
420 | * __raw_notifier_call_chain - Call functions in a raw notifier chain | |
421 | * @nh: Pointer to head of the raw notifier chain | |
422 | * @val: Value passed unmodified to notifier function | |
423 | * @v: Pointer passed unmodified to notifier function | |
424 | * @nr_to_call: See comment for notifier_call_chain. | |
425 | * @nr_calls: See comment for notifier_call_chain | |
426 | * | |
427 | * Calls each function in a notifier chain in turn. The functions | |
428 | * run in an undefined context. | |
429 | * All locking must be provided by the caller. | |
430 | * | |
431 | * If the return value of the notifier can be and'ed | |
432 | * with %NOTIFY_STOP_MASK then raw_notifier_call_chain() | |
433 | * will return immediately, with the return value of | |
434 | * the notifier function which halted execution. | |
435 | * Otherwise the return value is the return value | |
436 | * of the last notifier function called. | |
437 | */ | |
438 | int __raw_notifier_call_chain(struct raw_notifier_head *nh, | |
439 | unsigned long val, void *v, | |
440 | int nr_to_call, int *nr_calls) | |
441 | { | |
442 | return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); | |
443 | } | |
444 | EXPORT_SYMBOL_GPL(__raw_notifier_call_chain); | |
445 | ||
446 | int raw_notifier_call_chain(struct raw_notifier_head *nh, | |
447 | unsigned long val, void *v) | |
448 | { | |
449 | return __raw_notifier_call_chain(nh, val, v, -1, NULL); | |
450 | } | |
451 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); | |
452 | ||
453 | /* | |
454 | * SRCU notifier chain routines. Registration and unregistration | |
455 | * use a mutex, and call_chain is synchronized by SRCU (no locks). | |
456 | */ | |
457 | ||
458 | /** | |
459 | * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain | |
460 | * @nh: Pointer to head of the SRCU notifier chain | |
461 | * @n: New entry in notifier chain | |
462 | * | |
463 | * Adds a notifier to an SRCU notifier chain. | |
464 | * Must be called in process context. | |
465 | * | |
466 | * Currently always returns zero. | |
467 | */ | |
468 | int srcu_notifier_chain_register(struct srcu_notifier_head *nh, | |
469 | struct notifier_block *n) | |
470 | { | |
471 | int ret; | |
472 | ||
473 | /* | |
474 | * This code gets used during boot-up, when task switching is | |
475 | * not yet working and interrupts must remain disabled. At | |
476 | * such times we must not call mutex_lock(). | |
477 | */ | |
478 | if (unlikely(system_state == SYSTEM_BOOTING)) | |
479 | return notifier_chain_register(&nh->head, n); | |
480 | ||
481 | mutex_lock(&nh->mutex); | |
482 | ret = notifier_chain_register(&nh->head, n); | |
483 | mutex_unlock(&nh->mutex); | |
484 | return ret; | |
485 | } | |
486 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_register); | |
487 | ||
488 | /** | |
489 | * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain | |
490 | * @nh: Pointer to head of the SRCU notifier chain | |
491 | * @n: Entry to remove from notifier chain | |
492 | * | |
493 | * Removes a notifier from an SRCU notifier chain. | |
494 | * Must be called from process context. | |
495 | * | |
496 | * Returns zero on success or %-ENOENT on failure. | |
497 | */ | |
498 | int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, | |
499 | struct notifier_block *n) | |
500 | { | |
501 | int ret; | |
502 | ||
503 | /* | |
504 | * This code gets used during boot-up, when task switching is | |
505 | * not yet working and interrupts must remain disabled. At | |
506 | * such times we must not call mutex_lock(). | |
507 | */ | |
508 | if (unlikely(system_state == SYSTEM_BOOTING)) | |
509 | return notifier_chain_unregister(&nh->head, n); | |
510 | ||
511 | mutex_lock(&nh->mutex); | |
512 | ret = notifier_chain_unregister(&nh->head, n); | |
513 | mutex_unlock(&nh->mutex); | |
514 | synchronize_srcu(&nh->srcu); | |
515 | return ret; | |
516 | } | |
517 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); | |
518 | ||
519 | /** | |
520 | * __srcu_notifier_call_chain - Call functions in an SRCU notifier chain | |
521 | * @nh: Pointer to head of the SRCU notifier chain | |
522 | * @val: Value passed unmodified to notifier function | |
523 | * @v: Pointer passed unmodified to notifier function | |
524 | * @nr_to_call: See comment for notifier_call_chain. | |
525 | * @nr_calls: See comment for notifier_call_chain | |
526 | * | |
527 | * Calls each function in a notifier chain in turn. The functions | |
528 | * run in a process context, so they are allowed to block. | |
529 | * | |
530 | * If the return value of the notifier can be and'ed | |
531 | * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain() | |
532 | * will return immediately, with the return value of | |
533 | * the notifier function which halted execution. | |
534 | * Otherwise the return value is the return value | |
535 | * of the last notifier function called. | |
536 | */ | |
537 | int __srcu_notifier_call_chain(struct srcu_notifier_head *nh, | |
538 | unsigned long val, void *v, | |
539 | int nr_to_call, int *nr_calls) | |
540 | { | |
541 | int ret; | |
542 | int idx; | |
543 | ||
544 | idx = srcu_read_lock(&nh->srcu); | |
545 | ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); | |
546 | srcu_read_unlock(&nh->srcu, idx); | |
547 | return ret; | |
548 | } | |
549 | EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain); | |
550 | ||
551 | int srcu_notifier_call_chain(struct srcu_notifier_head *nh, | |
552 | unsigned long val, void *v) | |
553 | { | |
554 | return __srcu_notifier_call_chain(nh, val, v, -1, NULL); | |
555 | } | |
556 | EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); | |
557 | ||
558 | /** | |
559 | * srcu_init_notifier_head - Initialize an SRCU notifier head | |
560 | * @nh: Pointer to head of the srcu notifier chain | |
561 | * | |
562 | * Unlike other sorts of notifier heads, SRCU notifier heads require | |
563 | * dynamic initialization. Be sure to call this routine before | |
564 | * calling any of the other SRCU notifier routines for this head. | |
565 | * | |
566 | * If an SRCU notifier head is deallocated, it must first be cleaned | |
567 | * up by calling srcu_cleanup_notifier_head(). Otherwise the head's | |
568 | * per-cpu data (used by the SRCU mechanism) will leak. | |
569 | */ | |
570 | void srcu_init_notifier_head(struct srcu_notifier_head *nh) | |
571 | { | |
572 | mutex_init(&nh->mutex); | |
573 | if (init_srcu_struct(&nh->srcu) < 0) | |
574 | BUG(); | |
575 | nh->head = NULL; | |
576 | } | |
577 | EXPORT_SYMBOL_GPL(srcu_init_notifier_head); | |
578 | ||
fe9d4f57 AD |
579 | static ATOMIC_NOTIFIER_HEAD(die_chain); |
580 | ||
8f270083 | 581 | int notrace __kprobes notify_die(enum die_val val, const char *str, |
fe9d4f57 AD |
582 | struct pt_regs *regs, long err, int trap, int sig) |
583 | { | |
584 | struct die_args args = { | |
585 | .regs = regs, | |
586 | .str = str, | |
587 | .err = err, | |
588 | .trapnr = trap, | |
589 | .signr = sig, | |
590 | ||
591 | }; | |
592 | return atomic_notifier_call_chain(&die_chain, val, &args); | |
593 | } | |
594 | ||
595 | int register_die_notifier(struct notifier_block *nb) | |
596 | { | |
597 | vmalloc_sync_all(); | |
598 | return atomic_notifier_chain_register(&die_chain, nb); | |
599 | } | |
600 | EXPORT_SYMBOL_GPL(register_die_notifier); | |
601 | ||
602 | int unregister_die_notifier(struct notifier_block *nb) | |
603 | { | |
604 | return atomic_notifier_chain_unregister(&die_chain, nb); | |
605 | } | |
606 | EXPORT_SYMBOL_GPL(unregister_die_notifier); |