diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sys.c | 124 |
1 files changed, 123 insertions, 1 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 2314867ae34f..fd5c71006775 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -153,7 +153,7 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl, | |||
153 | 153 | ||
154 | /* | 154 | /* |
155 | * Atomic notifier chain routines. Registration and unregistration | 155 | * Atomic notifier chain routines. Registration and unregistration |
156 | * use a mutex, and call_chain is synchronized by RCU (no locks). | 156 | * use a spinlock, and call_chain is synchronized by RCU (no locks). |
157 | */ | 157 | */ |
158 | 158 | ||
159 | /** | 159 | /** |
@@ -401,6 +401,128 @@ int raw_notifier_call_chain(struct raw_notifier_head *nh, | |||
401 | 401 | ||
402 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); | 402 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); |
403 | 403 | ||
404 | /* | ||
405 | * SRCU notifier chain routines. Registration and unregistration | ||
406 | * use a mutex, and call_chain is synchronized by SRCU (no locks). | ||
407 | */ | ||
408 | |||
409 | /** | ||
410 | * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain | ||
411 | * @nh: Pointer to head of the SRCU notifier chain | ||
412 | * @n: New entry in notifier chain | ||
413 | * | ||
414 | * Adds a notifier to an SRCU notifier chain. | ||
415 | * Must be called in process context. | ||
416 | * | ||
417 | * Currently always returns zero. | ||
418 | */ | ||
419 | |||
420 | int srcu_notifier_chain_register(struct srcu_notifier_head *nh, | ||
421 | struct notifier_block *n) | ||
422 | { | ||
423 | int ret; | ||
424 | |||
425 | /* | ||
426 | * This code gets used during boot-up, when task switching is | ||
427 | * not yet working and interrupts must remain disabled. At | ||
428 | * such times we must not call mutex_lock(). | ||
429 | */ | ||
430 | if (unlikely(system_state == SYSTEM_BOOTING)) | ||
431 | return notifier_chain_register(&nh->head, n); | ||
432 | |||
433 | mutex_lock(&nh->mutex); | ||
434 | ret = notifier_chain_register(&nh->head, n); | ||
435 | mutex_unlock(&nh->mutex); | ||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_register); | ||
440 | |||
441 | /** | ||
442 | * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain | ||
443 | * @nh: Pointer to head of the SRCU notifier chain | ||
444 | * @n: Entry to remove from notifier chain | ||
445 | * | ||
446 | * Removes a notifier from an SRCU notifier chain. | ||
447 | * Must be called from process context. | ||
448 | * | ||
449 | * Returns zero on success or %-ENOENT on failure. | ||
450 | */ | ||
451 | int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, | ||
452 | struct notifier_block *n) | ||
453 | { | ||
454 | int ret; | ||
455 | |||
456 | /* | ||
457 | * This code gets used during boot-up, when task switching is | ||
458 | * not yet working and interrupts must remain disabled. At | ||
459 | * such times we must not call mutex_lock(). | ||
460 | */ | ||
461 | if (unlikely(system_state == SYSTEM_BOOTING)) | ||
462 | return notifier_chain_unregister(&nh->head, n); | ||
463 | |||
464 | mutex_lock(&nh->mutex); | ||
465 | ret = notifier_chain_unregister(&nh->head, n); | ||
466 | mutex_unlock(&nh->mutex); | ||
467 | synchronize_srcu(&nh->srcu); | ||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); | ||
472 | |||
473 | /** | ||
474 | * srcu_notifier_call_chain - Call functions in an SRCU notifier chain | ||
475 | * @nh: Pointer to head of the SRCU notifier chain | ||
476 | * @val: Value passed unmodified to notifier function | ||
477 | * @v: Pointer passed unmodified to notifier function | ||
478 | * | ||
479 | * Calls each function in a notifier chain in turn. The functions | ||
480 | * run in a process context, so they are allowed to block. | ||
481 | * | ||
482 | * If the return value of the notifier can be and'ed | ||
483 | * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain | ||
484 | * will return immediately, with the return value of | ||
485 | * the notifier function which halted execution. | ||
486 | * Otherwise the return value is the return value | ||
487 | * of the last notifier function called. | ||
488 | */ | ||
489 | |||
490 | int srcu_notifier_call_chain(struct srcu_notifier_head *nh, | ||
491 | unsigned long val, void *v) | ||
492 | { | ||
493 | int ret; | ||
494 | int idx; | ||
495 | |||
496 | idx = srcu_read_lock(&nh->srcu); | ||
497 | ret = notifier_call_chain(&nh->head, val, v); | ||
498 | srcu_read_unlock(&nh->srcu, idx); | ||
499 | return ret; | ||
500 | } | ||
501 | |||
502 | EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); | ||
503 | |||
504 | /** | ||
505 | * srcu_init_notifier_head - Initialize an SRCU notifier head | ||
506 | * @nh: Pointer to head of the srcu notifier chain | ||
507 | * | ||
508 | * Unlike other sorts of notifier heads, SRCU notifier heads require | ||
509 | * dynamic initialization. Be sure to call this routine before | ||
510 | * calling any of the other SRCU notifier routines for this head. | ||
511 | * | ||
512 | * If an SRCU notifier head is deallocated, it must first be cleaned | ||
513 | * up by calling srcu_cleanup_notifier_head(). Otherwise the head's | ||
514 | * per-cpu data (used by the SRCU mechanism) will leak. | ||
515 | */ | ||
516 | |||
517 | void srcu_init_notifier_head(struct srcu_notifier_head *nh) | ||
518 | { | ||
519 | mutex_init(&nh->mutex); | ||
520 | init_srcu_struct(&nh->srcu); | ||
521 | nh->head = NULL; | ||
522 | } | ||
523 | |||
524 | EXPORT_SYMBOL_GPL(srcu_init_notifier_head); | ||
525 | |||
404 | /** | 526 | /** |
405 | * register_reboot_notifier - Register function to be called at reboot time | 527 | * register_reboot_notifier - Register function to be called at reboot time |
406 | * @nb: Info about notifier function to be called | 528 | * @nb: Info about notifier function to be called |