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 |
