1#include <linux/kdebug.h>
2#include <linux/kprobes.h>
3#include <linux/module.h>
4#include <linux/notifier.h>
5#include <linux/rcupdate.h>
6#include <linux/vmalloc.h>
7#include <linux/reboot.h>
8
9
10
11
12
13
14BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
15
16
17
18
19
20
21static int notifier_chain_register(struct notifier_block **nl,
22 struct notifier_block *n)
23{
24 while ((*nl) != NULL) {
25 if (n->priority > (*nl)->priority)
26 break;
27 nl = &((*nl)->next);
28 }
29 n->next = *nl;
30 rcu_assign_pointer(*nl, n);
31 return 0;
32}
33
34static int notifier_chain_cond_register(struct notifier_block **nl,
35 struct notifier_block *n)
36{
37 while ((*nl) != NULL) {
38 if ((*nl) == n)
39 return 0;
40 if (n->priority > (*nl)->priority)
41 break;
42 nl = &((*nl)->next);
43 }
44 n->next = *nl;
45 rcu_assign_pointer(*nl, n);
46 return 0;
47}
48
49static int notifier_chain_unregister(struct notifier_block **nl,
50 struct notifier_block *n)
51{
52 while ((*nl) != NULL) {
53 if ((*nl) == n) {
54 rcu_assign_pointer(*nl, n->next);
55 return 0;
56 }
57 nl = &((*nl)->next);
58 }
59 return -ENOENT;
60}
61
62
63
64
65
66
67
68
69
70
71
72
73
74static int __kprobes notifier_call_chain(struct notifier_block **nl,
75 unsigned long val, void *v,
76 int nr_to_call, int *nr_calls)
77{
78 int ret = NOTIFY_DONE;
79 struct notifier_block *nb, *next_nb;
80
81 nb = rcu_dereference(*nl);
82
83 while (nb && nr_to_call) {
84 next_nb = rcu_dereference(nb->next);
85 ret = nb->notifier_call(nb, val, v);
86
87 if (nr_calls)
88 (*nr_calls)++;
89
90 if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
91 break;
92 nb = next_nb;
93 nr_to_call--;
94 }
95 return ret;
96}
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
113 struct notifier_block *n)
114{
115 unsigned long flags;
116 int ret;
117
118 spin_lock_irqsave(&nh->lock, flags);
119 ret = notifier_chain_register(&nh->head, n);
120 spin_unlock_irqrestore(&nh->lock, flags);
121 return ret;
122}
123EXPORT_SYMBOL_GPL(atomic_notifier_chain_register);
124
125
126
127
128
129
130
131
132
133
134int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
135 struct notifier_block *n)
136{
137 unsigned long flags;
138 int ret;
139
140 spin_lock_irqsave(&nh->lock, flags);
141 ret = notifier_chain_unregister(&nh->head, n);
142 spin_unlock_irqrestore(&nh->lock, flags);
143 synchronize_rcu();
144 return ret;
145}
146EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
168 unsigned long val, void *v,
169 int nr_to_call, int *nr_calls)
170{
171 int ret;
172
173 rcu_read_lock();
174 ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
175 rcu_read_unlock();
176 return ret;
177}
178EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
179
180int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
181 unsigned long val, void *v)
182{
183 return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
184}
185EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
203 struct notifier_block *n)
204{
205 int ret;
206
207
208
209
210
211
212 if (unlikely(system_state == SYSTEM_BOOTING))
213 return notifier_chain_register(&nh->head, n);
214
215 down_write(&nh->rwsem);
216 ret = notifier_chain_register(&nh->head, n);
217 up_write(&nh->rwsem);
218 return ret;
219}
220EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
221
222
223
224
225
226
227
228
229
230
231
232
233int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh,
234 struct notifier_block *n)
235{
236 int ret;
237
238 down_write(&nh->rwsem);
239 ret = notifier_chain_cond_register(&nh->head, n);
240 up_write(&nh->rwsem);
241 return ret;
242}
243EXPORT_SYMBOL_GPL(blocking_notifier_chain_cond_register);
244
245
246
247
248
249
250
251
252
253
254
255int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
256 struct notifier_block *n)
257{
258 int ret;
259
260
261
262
263
264
265 if (unlikely(system_state == SYSTEM_BOOTING))
266 return notifier_chain_unregister(&nh->head, n);
267
268 down_write(&nh->rwsem);
269 ret = notifier_chain_unregister(&nh->head, n);
270 up_write(&nh->rwsem);
271 return ret;
272}
273EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
294 unsigned long val, void *v,
295 int nr_to_call, int *nr_calls)
296{
297 int ret = NOTIFY_DONE;
298
299
300
301
302
303
304 if (rcu_dereference(nh->head)) {
305 down_read(&nh->rwsem);
306 ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
307 nr_calls);
308 up_read(&nh->rwsem);
309 }
310 return ret;
311}
312EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
313
314int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
315 unsigned long val, void *v)
316{
317 return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
318}
319EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336int raw_notifier_chain_register(struct raw_notifier_head *nh,
337 struct notifier_block *n)
338{
339 return notifier_chain_register(&nh->head, n);
340}
341EXPORT_SYMBOL_GPL(raw_notifier_chain_register);
342
343
344
345
346
347
348
349
350
351
352
353int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
354 struct notifier_block *n)
355{
356 return notifier_chain_unregister(&nh->head, n);
357}
358EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379int __raw_notifier_call_chain(struct raw_notifier_head *nh,
380 unsigned long val, void *v,
381 int nr_to_call, int *nr_calls)
382{
383 return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
384}
385EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
386
387int raw_notifier_call_chain(struct raw_notifier_head *nh,
388 unsigned long val, void *v)
389{
390 return __raw_notifier_call_chain(nh, val, v, -1, NULL);
391}
392EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
410 struct notifier_block *n)
411{
412 int ret;
413
414
415
416
417
418
419 if (unlikely(system_state == SYSTEM_BOOTING))
420 return notifier_chain_register(&nh->head, n);
421
422 mutex_lock(&nh->mutex);
423 ret = notifier_chain_register(&nh->head, n);
424 mutex_unlock(&nh->mutex);
425 return ret;
426}
427EXPORT_SYMBOL_GPL(srcu_notifier_chain_register);
428
429
430
431
432
433
434
435
436
437
438
439int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
440 struct notifier_block *n)
441{
442 int ret;
443
444
445
446
447
448
449 if (unlikely(system_state == SYSTEM_BOOTING))
450 return notifier_chain_unregister(&nh->head, n);
451
452 mutex_lock(&nh->mutex);
453 ret = notifier_chain_unregister(&nh->head, n);
454 mutex_unlock(&nh->mutex);
455 synchronize_srcu(&nh->srcu);
456 return ret;
457}
458EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
479 unsigned long val, void *v,
480 int nr_to_call, int *nr_calls)
481{
482 int ret;
483 int idx;
484
485 idx = srcu_read_lock(&nh->srcu);
486 ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
487 srcu_read_unlock(&nh->srcu, idx);
488 return ret;
489}
490EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
491
492int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
493 unsigned long val, void *v)
494{
495 return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
496}
497EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
498
499
500
501
502
503
504
505
506
507
508
509
510
511void srcu_init_notifier_head(struct srcu_notifier_head *nh)
512{
513 mutex_init(&nh->mutex);
514 if (init_srcu_struct(&nh->srcu) < 0)
515 BUG();
516 nh->head = NULL;
517}
518EXPORT_SYMBOL_GPL(srcu_init_notifier_head);
519
520
521
522
523
524
525
526
527
528
529
530int register_reboot_notifier(struct notifier_block *nb)
531{
532 return blocking_notifier_chain_register(&reboot_notifier_list, nb);
533}
534EXPORT_SYMBOL(register_reboot_notifier);
535
536
537
538
539
540
541
542
543
544
545int unregister_reboot_notifier(struct notifier_block *nb)
546{
547 return blocking_notifier_chain_unregister(&reboot_notifier_list, nb);
548}
549EXPORT_SYMBOL(unregister_reboot_notifier);
550
551static ATOMIC_NOTIFIER_HEAD(die_chain);
552
553int notify_die(enum die_val val, const char *str,
554 struct pt_regs *regs, long err, int trap, int sig)
555{
556 struct die_args args = {
557 .regs = regs,
558 .str = str,
559 .err = err,
560 .trapnr = trap,
561 .signr = sig,
562
563 };
564 return atomic_notifier_call_chain(&die_chain, val, &args);
565}
566
567int register_die_notifier(struct notifier_block *nb)
568{
569 vmalloc_sync_all();
570 return atomic_notifier_chain_register(&die_chain, nb);
571}
572EXPORT_SYMBOL_GPL(register_die_notifier);
573
574int unregister_die_notifier(struct notifier_block *nb)
575{
576 return atomic_notifier_chain_unregister(&die_chain, nb);
577}
578EXPORT_SYMBOL_GPL(unregister_die_notifier);
579