diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-12-29 03:45:15 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-12-29 03:45:15 -0500 |
| commit | e1df957670aef74ffd9a4ad93e6d2c90bf6b4845 (patch) | |
| tree | bca1fcfef55b3e3e82c9a822b4ac6428fce2b419 /kernel/marker.c | |
| parent | 2b583d8bc8d7105b58d7481a4a0ceb718dac49c6 (diff) | |
| parent | 3c92ec8ae91ecf59d88c798301833d7cf83f2179 (diff) | |
Merge branch 'linus' into perfcounters/core
Conflicts:
fs/exec.c
include/linux/init_task.h
Simple context conflicts.
Diffstat (limited to 'kernel/marker.c')
| -rw-r--r-- | kernel/marker.c | 192 |
1 files changed, 127 insertions, 65 deletions
diff --git a/kernel/marker.c b/kernel/marker.c index e9c6b2bc9400..ea54f2647868 100644 --- a/kernel/marker.c +++ b/kernel/marker.c | |||
| @@ -43,6 +43,7 @@ static DEFINE_MUTEX(markers_mutex); | |||
| 43 | */ | 43 | */ |
| 44 | #define MARKER_HASH_BITS 6 | 44 | #define MARKER_HASH_BITS 6 |
| 45 | #define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS) | 45 | #define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS) |
| 46 | static struct hlist_head marker_table[MARKER_TABLE_SIZE]; | ||
| 46 | 47 | ||
| 47 | /* | 48 | /* |
| 48 | * Note about RCU : | 49 | * Note about RCU : |
| @@ -64,11 +65,10 @@ struct marker_entry { | |||
| 64 | void *oldptr; | 65 | void *oldptr; |
| 65 | int rcu_pending; | 66 | int rcu_pending; |
| 66 | unsigned char ptype:1; | 67 | unsigned char ptype:1; |
| 68 | unsigned char format_allocated:1; | ||
| 67 | char name[0]; /* Contains name'\0'format'\0' */ | 69 | char name[0]; /* Contains name'\0'format'\0' */ |
| 68 | }; | 70 | }; |
| 69 | 71 | ||
| 70 | static struct hlist_head marker_table[MARKER_TABLE_SIZE]; | ||
| 71 | |||
| 72 | /** | 72 | /** |
| 73 | * __mark_empty_function - Empty probe callback | 73 | * __mark_empty_function - Empty probe callback |
| 74 | * @probe_private: probe private data | 74 | * @probe_private: probe private data |
| @@ -81,7 +81,7 @@ static struct hlist_head marker_table[MARKER_TABLE_SIZE]; | |||
| 81 | * though the function pointer change and the marker enabling are two distinct | 81 | * though the function pointer change and the marker enabling are two distinct |
| 82 | * operations that modifies the execution flow of preemptible code. | 82 | * operations that modifies the execution flow of preemptible code. |
| 83 | */ | 83 | */ |
| 84 | void __mark_empty_function(void *probe_private, void *call_private, | 84 | notrace void __mark_empty_function(void *probe_private, void *call_private, |
| 85 | const char *fmt, va_list *args) | 85 | const char *fmt, va_list *args) |
| 86 | { | 86 | { |
| 87 | } | 87 | } |
| @@ -97,7 +97,8 @@ EXPORT_SYMBOL_GPL(__mark_empty_function); | |||
| 97 | * need to put a full smp_rmb() in this branch. This is why we do not use | 97 | * need to put a full smp_rmb() in this branch. This is why we do not use |
| 98 | * rcu_dereference() for the pointer read. | 98 | * rcu_dereference() for the pointer read. |
| 99 | */ | 99 | */ |
| 100 | void marker_probe_cb(const struct marker *mdata, void *call_private, ...) | 100 | notrace void marker_probe_cb(const struct marker *mdata, |
| 101 | void *call_private, ...) | ||
| 101 | { | 102 | { |
| 102 | va_list args; | 103 | va_list args; |
| 103 | char ptype; | 104 | char ptype; |
| @@ -107,7 +108,7 @@ void marker_probe_cb(const struct marker *mdata, void *call_private, ...) | |||
| 107 | * sure the teardown of the callbacks can be done correctly when they | 108 | * sure the teardown of the callbacks can be done correctly when they |
| 108 | * are in modules and they insure RCU read coherency. | 109 | * are in modules and they insure RCU read coherency. |
| 109 | */ | 110 | */ |
| 110 | rcu_read_lock_sched(); | 111 | rcu_read_lock_sched_notrace(); |
| 111 | ptype = mdata->ptype; | 112 | ptype = mdata->ptype; |
| 112 | if (likely(!ptype)) { | 113 | if (likely(!ptype)) { |
| 113 | marker_probe_func *func; | 114 | marker_probe_func *func; |
| @@ -145,7 +146,7 @@ void marker_probe_cb(const struct marker *mdata, void *call_private, ...) | |||
| 145 | va_end(args); | 146 | va_end(args); |
| 146 | } | 147 | } |
| 147 | } | 148 | } |
| 148 | rcu_read_unlock_sched(); | 149 | rcu_read_unlock_sched_notrace(); |
| 149 | } | 150 | } |
| 150 | EXPORT_SYMBOL_GPL(marker_probe_cb); | 151 | EXPORT_SYMBOL_GPL(marker_probe_cb); |
| 151 | 152 | ||
| @@ -157,12 +158,13 @@ EXPORT_SYMBOL_GPL(marker_probe_cb); | |||
| 157 | * | 158 | * |
| 158 | * Should be connected to markers "MARK_NOARGS". | 159 | * Should be connected to markers "MARK_NOARGS". |
| 159 | */ | 160 | */ |
| 160 | void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) | 161 | static notrace void marker_probe_cb_noarg(const struct marker *mdata, |
| 162 | void *call_private, ...) | ||
| 161 | { | 163 | { |
| 162 | va_list args; /* not initialized */ | 164 | va_list args; /* not initialized */ |
| 163 | char ptype; | 165 | char ptype; |
| 164 | 166 | ||
| 165 | rcu_read_lock_sched(); | 167 | rcu_read_lock_sched_notrace(); |
| 166 | ptype = mdata->ptype; | 168 | ptype = mdata->ptype; |
| 167 | if (likely(!ptype)) { | 169 | if (likely(!ptype)) { |
| 168 | marker_probe_func *func; | 170 | marker_probe_func *func; |
| @@ -195,9 +197,8 @@ void marker_probe_cb_noarg(const struct marker *mdata, void *call_private, ...) | |||
| 195 | multi[i].func(multi[i].probe_private, call_private, | 197 | multi[i].func(multi[i].probe_private, call_private, |
| 196 | mdata->format, &args); | 198 | mdata->format, &args); |
| 197 | } | 199 | } |
| 198 | rcu_read_unlock_sched(); | 200 | rcu_read_unlock_sched_notrace(); |
| 199 | } | 201 | } |
| 200 | EXPORT_SYMBOL_GPL(marker_probe_cb_noarg); | ||
| 201 | 202 | ||
| 202 | static void free_old_closure(struct rcu_head *head) | 203 | static void free_old_closure(struct rcu_head *head) |
| 203 | { | 204 | { |
| @@ -416,6 +417,7 @@ static struct marker_entry *add_marker(const char *name, const char *format) | |||
| 416 | e->single.probe_private = NULL; | 417 | e->single.probe_private = NULL; |
| 417 | e->multi = NULL; | 418 | e->multi = NULL; |
| 418 | e->ptype = 0; | 419 | e->ptype = 0; |
| 420 | e->format_allocated = 0; | ||
| 419 | e->refcount = 0; | 421 | e->refcount = 0; |
| 420 | e->rcu_pending = 0; | 422 | e->rcu_pending = 0; |
| 421 | hlist_add_head(&e->hlist, head); | 423 | hlist_add_head(&e->hlist, head); |
| @@ -447,6 +449,8 @@ static int remove_marker(const char *name) | |||
| 447 | if (e->single.func != __mark_empty_function) | 449 | if (e->single.func != __mark_empty_function) |
| 448 | return -EBUSY; | 450 | return -EBUSY; |
| 449 | hlist_del(&e->hlist); | 451 | hlist_del(&e->hlist); |
| 452 | if (e->format_allocated) | ||
| 453 | kfree(e->format); | ||
| 450 | /* Make sure the call_rcu has been executed */ | 454 | /* Make sure the call_rcu has been executed */ |
| 451 | if (e->rcu_pending) | 455 | if (e->rcu_pending) |
| 452 | rcu_barrier_sched(); | 456 | rcu_barrier_sched(); |
| @@ -457,57 +461,34 @@ static int remove_marker(const char *name) | |||
| 457 | /* | 461 | /* |
| 458 | * Set the mark_entry format to the format found in the element. | 462 | * Set the mark_entry format to the format found in the element. |
| 459 | */ | 463 | */ |
| 460 | static int marker_set_format(struct marker_entry **entry, const char *format) | 464 | static int marker_set_format(struct marker_entry *entry, const char *format) |
| 461 | { | 465 | { |
| 462 | struct marker_entry *e; | 466 | entry->format = kstrdup(format, GFP_KERNEL); |
| 463 | size_t name_len = strlen((*entry)->name) + 1; | 467 | if (!entry->format) |
| 464 | size_t format_len = strlen(format) + 1; | ||
| 465 | |||
| 466 | |||
| 467 | e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, | ||
| 468 | GFP_KERNEL); | ||
| 469 | if (!e) | ||
| 470 | return -ENOMEM; | 468 | return -ENOMEM; |
| 471 | memcpy(&e->name[0], (*entry)->name, name_len); | 469 | entry->format_allocated = 1; |
| 472 | e->format = &e->name[name_len]; | 470 | |
| 473 | memcpy(e->format, format, format_len); | ||
| 474 | if (strcmp(e->format, MARK_NOARGS) == 0) | ||
| 475 | e->call = marker_probe_cb_noarg; | ||
| 476 | else | ||
| 477 | e->call = marker_probe_cb; | ||
| 478 | e->single = (*entry)->single; | ||
| 479 | e->multi = (*entry)->multi; | ||
| 480 | e->ptype = (*entry)->ptype; | ||
| 481 | e->refcount = (*entry)->refcount; | ||
| 482 | e->rcu_pending = 0; | ||
| 483 | hlist_add_before(&e->hlist, &(*entry)->hlist); | ||
| 484 | hlist_del(&(*entry)->hlist); | ||
| 485 | /* Make sure the call_rcu has been executed */ | ||
| 486 | if ((*entry)->rcu_pending) | ||
| 487 | rcu_barrier_sched(); | ||
| 488 | kfree(*entry); | ||
| 489 | *entry = e; | ||
| 490 | trace_mark(core_marker_format, "name %s format %s", | 471 | trace_mark(core_marker_format, "name %s format %s", |
| 491 | e->name, e->format); | 472 | entry->name, entry->format); |
| 492 | return 0; | 473 | return 0; |
| 493 | } | 474 | } |
| 494 | 475 | ||
| 495 | /* | 476 | /* |
| 496 | * Sets the probe callback corresponding to one marker. | 477 | * Sets the probe callback corresponding to one marker. |
| 497 | */ | 478 | */ |
| 498 | static int set_marker(struct marker_entry **entry, struct marker *elem, | 479 | static int set_marker(struct marker_entry *entry, struct marker *elem, |
| 499 | int active) | 480 | int active) |
| 500 | { | 481 | { |
| 501 | int ret; | 482 | int ret = 0; |
| 502 | WARN_ON(strcmp((*entry)->name, elem->name) != 0); | 483 | WARN_ON(strcmp(entry->name, elem->name) != 0); |
| 503 | 484 | ||
| 504 | if ((*entry)->format) { | 485 | if (entry->format) { |
| 505 | if (strcmp((*entry)->format, elem->format) != 0) { | 486 | if (strcmp(entry->format, elem->format) != 0) { |
| 506 | printk(KERN_NOTICE | 487 | printk(KERN_NOTICE |
| 507 | "Format mismatch for probe %s " | 488 | "Format mismatch for probe %s " |
| 508 | "(%s), marker (%s)\n", | 489 | "(%s), marker (%s)\n", |
| 509 | (*entry)->name, | 490 | entry->name, |
| 510 | (*entry)->format, | 491 | entry->format, |
| 511 | elem->format); | 492 | elem->format); |
| 512 | return -EPERM; | 493 | return -EPERM; |
| 513 | } | 494 | } |
| @@ -523,37 +504,67 @@ static int set_marker(struct marker_entry **entry, struct marker *elem, | |||
| 523 | * pass from a "safe" callback (with argument) to an "unsafe" | 504 | * pass from a "safe" callback (with argument) to an "unsafe" |
| 524 | * callback (does not set arguments). | 505 | * callback (does not set arguments). |
| 525 | */ | 506 | */ |
| 526 | elem->call = (*entry)->call; | 507 | elem->call = entry->call; |
| 527 | /* | 508 | /* |
| 528 | * Sanity check : | 509 | * Sanity check : |
| 529 | * We only update the single probe private data when the ptr is | 510 | * We only update the single probe private data when the ptr is |
| 530 | * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1) | 511 | * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1) |
| 531 | */ | 512 | */ |
| 532 | WARN_ON(elem->single.func != __mark_empty_function | 513 | WARN_ON(elem->single.func != __mark_empty_function |
| 533 | && elem->single.probe_private | 514 | && elem->single.probe_private != entry->single.probe_private |
| 534 | != (*entry)->single.probe_private && | 515 | && !elem->ptype); |
| 535 | !elem->ptype); | 516 | elem->single.probe_private = entry->single.probe_private; |
| 536 | elem->single.probe_private = (*entry)->single.probe_private; | ||
| 537 | /* | 517 | /* |
| 538 | * Make sure the private data is valid when we update the | 518 | * Make sure the private data is valid when we update the |
| 539 | * single probe ptr. | 519 | * single probe ptr. |
| 540 | */ | 520 | */ |
| 541 | smp_wmb(); | 521 | smp_wmb(); |
| 542 | elem->single.func = (*entry)->single.func; | 522 | elem->single.func = entry->single.func; |
| 543 | /* | 523 | /* |
| 544 | * We also make sure that the new probe callbacks array is consistent | 524 | * We also make sure that the new probe callbacks array is consistent |
| 545 | * before setting a pointer to it. | 525 | * before setting a pointer to it. |
| 546 | */ | 526 | */ |
| 547 | rcu_assign_pointer(elem->multi, (*entry)->multi); | 527 | rcu_assign_pointer(elem->multi, entry->multi); |
| 548 | /* | 528 | /* |
| 549 | * Update the function or multi probe array pointer before setting the | 529 | * Update the function or multi probe array pointer before setting the |
| 550 | * ptype. | 530 | * ptype. |
| 551 | */ | 531 | */ |
| 552 | smp_wmb(); | 532 | smp_wmb(); |
| 553 | elem->ptype = (*entry)->ptype; | 533 | elem->ptype = entry->ptype; |
| 534 | |||
| 535 | if (elem->tp_name && (active ^ elem->state)) { | ||
| 536 | WARN_ON(!elem->tp_cb); | ||
| 537 | /* | ||
| 538 | * It is ok to directly call the probe registration because type | ||
| 539 | * checking has been done in the __trace_mark_tp() macro. | ||
| 540 | */ | ||
| 541 | |||
| 542 | if (active) { | ||
| 543 | /* | ||
| 544 | * try_module_get should always succeed because we hold | ||
| 545 | * lock_module() to get the tp_cb address. | ||
| 546 | */ | ||
| 547 | ret = try_module_get(__module_text_address( | ||
| 548 | (unsigned long)elem->tp_cb)); | ||
| 549 | BUG_ON(!ret); | ||
| 550 | ret = tracepoint_probe_register_noupdate( | ||
| 551 | elem->tp_name, | ||
| 552 | elem->tp_cb); | ||
| 553 | } else { | ||
| 554 | ret = tracepoint_probe_unregister_noupdate( | ||
| 555 | elem->tp_name, | ||
| 556 | elem->tp_cb); | ||
| 557 | /* | ||
| 558 | * tracepoint_probe_update_all() must be called | ||
| 559 | * before the module containing tp_cb is unloaded. | ||
| 560 | */ | ||
| 561 | module_put(__module_text_address( | ||
| 562 | (unsigned long)elem->tp_cb)); | ||
| 563 | } | ||
| 564 | } | ||
| 554 | elem->state = active; | 565 | elem->state = active; |
| 555 | 566 | ||
| 556 | return 0; | 567 | return ret; |
| 557 | } | 568 | } |
| 558 | 569 | ||
| 559 | /* | 570 | /* |
| @@ -564,7 +575,24 @@ static int set_marker(struct marker_entry **entry, struct marker *elem, | |||
| 564 | */ | 575 | */ |
| 565 | static void disable_marker(struct marker *elem) | 576 | static void disable_marker(struct marker *elem) |
| 566 | { | 577 | { |
| 578 | int ret; | ||
| 579 | |||
| 567 | /* leave "call" as is. It is known statically. */ | 580 | /* leave "call" as is. It is known statically. */ |
| 581 | if (elem->tp_name && elem->state) { | ||
| 582 | WARN_ON(!elem->tp_cb); | ||
| 583 | /* | ||
| 584 | * It is ok to directly call the probe registration because type | ||
| 585 | * checking has been done in the __trace_mark_tp() macro. | ||
| 586 | */ | ||
| 587 | ret = tracepoint_probe_unregister_noupdate(elem->tp_name, | ||
| 588 | elem->tp_cb); | ||
| 589 | WARN_ON(ret); | ||
| 590 | /* | ||
| 591 | * tracepoint_probe_update_all() must be called | ||
| 592 | * before the module containing tp_cb is unloaded. | ||
| 593 | */ | ||
| 594 | module_put(__module_text_address((unsigned long)elem->tp_cb)); | ||
| 595 | } | ||
| 568 | elem->state = 0; | 596 | elem->state = 0; |
| 569 | elem->single.func = __mark_empty_function; | 597 | elem->single.func = __mark_empty_function; |
| 570 | /* Update the function before setting the ptype */ | 598 | /* Update the function before setting the ptype */ |
| @@ -594,8 +622,7 @@ void marker_update_probe_range(struct marker *begin, | |||
| 594 | for (iter = begin; iter < end; iter++) { | 622 | for (iter = begin; iter < end; iter++) { |
| 595 | mark_entry = get_marker(iter->name); | 623 | mark_entry = get_marker(iter->name); |
| 596 | if (mark_entry) { | 624 | if (mark_entry) { |
| 597 | set_marker(&mark_entry, iter, | 625 | set_marker(mark_entry, iter, !!mark_entry->refcount); |
| 598 | !!mark_entry->refcount); | ||
| 599 | /* | 626 | /* |
| 600 | * ignore error, continue | 627 | * ignore error, continue |
| 601 | */ | 628 | */ |
| @@ -629,6 +656,7 @@ static void marker_update_probes(void) | |||
| 629 | marker_update_probe_range(__start___markers, __stop___markers); | 656 | marker_update_probe_range(__start___markers, __stop___markers); |
| 630 | /* Markers in modules. */ | 657 | /* Markers in modules. */ |
| 631 | module_update_markers(); | 658 | module_update_markers(); |
| 659 | tracepoint_probe_update_all(); | ||
| 632 | } | 660 | } |
| 633 | 661 | ||
| 634 | /** | 662 | /** |
| @@ -657,7 +685,7 @@ int marker_probe_register(const char *name, const char *format, | |||
| 657 | ret = PTR_ERR(entry); | 685 | ret = PTR_ERR(entry); |
| 658 | } else if (format) { | 686 | } else if (format) { |
| 659 | if (!entry->format) | 687 | if (!entry->format) |
| 660 | ret = marker_set_format(&entry, format); | 688 | ret = marker_set_format(entry, format); |
| 661 | else if (strcmp(entry->format, format)) | 689 | else if (strcmp(entry->format, format)) |
| 662 | ret = -EPERM; | 690 | ret = -EPERM; |
| 663 | } | 691 | } |
| @@ -676,10 +704,11 @@ int marker_probe_register(const char *name, const char *format, | |||
| 676 | goto end; | 704 | goto end; |
| 677 | } | 705 | } |
| 678 | mutex_unlock(&markers_mutex); | 706 | mutex_unlock(&markers_mutex); |
| 679 | marker_update_probes(); /* may update entry */ | 707 | marker_update_probes(); |
| 680 | mutex_lock(&markers_mutex); | 708 | mutex_lock(&markers_mutex); |
| 681 | entry = get_marker(name); | 709 | entry = get_marker(name); |
| 682 | WARN_ON(!entry); | 710 | if (!entry) |
| 711 | goto end; | ||
| 683 | if (entry->rcu_pending) | 712 | if (entry->rcu_pending) |
| 684 | rcu_barrier_sched(); | 713 | rcu_barrier_sched(); |
| 685 | entry->oldptr = old; | 714 | entry->oldptr = old; |
| @@ -720,7 +749,7 @@ int marker_probe_unregister(const char *name, | |||
| 720 | rcu_barrier_sched(); | 749 | rcu_barrier_sched(); |
| 721 | old = marker_entry_remove_probe(entry, probe, probe_private); | 750 | old = marker_entry_remove_probe(entry, probe, probe_private); |
| 722 | mutex_unlock(&markers_mutex); | 751 | mutex_unlock(&markers_mutex); |
| 723 | marker_update_probes(); /* may update entry */ | 752 | marker_update_probes(); |
| 724 | mutex_lock(&markers_mutex); | 753 | mutex_lock(&markers_mutex); |
| 725 | entry = get_marker(name); | 754 | entry = get_marker(name); |
| 726 | if (!entry) | 755 | if (!entry) |
| @@ -801,10 +830,11 @@ int marker_probe_unregister_private_data(marker_probe_func *probe, | |||
| 801 | rcu_barrier_sched(); | 830 | rcu_barrier_sched(); |
| 802 | old = marker_entry_remove_probe(entry, NULL, probe_private); | 831 | old = marker_entry_remove_probe(entry, NULL, probe_private); |
| 803 | mutex_unlock(&markers_mutex); | 832 | mutex_unlock(&markers_mutex); |
| 804 | marker_update_probes(); /* may update entry */ | 833 | marker_update_probes(); |
| 805 | mutex_lock(&markers_mutex); | 834 | mutex_lock(&markers_mutex); |
| 806 | entry = get_marker_from_private_data(probe, probe_private); | 835 | entry = get_marker_from_private_data(probe, probe_private); |
| 807 | WARN_ON(!entry); | 836 | if (!entry) |
| 837 | goto end; | ||
| 808 | if (entry->rcu_pending) | 838 | if (entry->rcu_pending) |
| 809 | rcu_barrier_sched(); | 839 | rcu_barrier_sched(); |
| 810 | entry->oldptr = old; | 840 | entry->oldptr = old; |
| @@ -848,8 +878,6 @@ void *marker_get_private_data(const char *name, marker_probe_func *probe, | |||
| 848 | if (!e->ptype) { | 878 | if (!e->ptype) { |
| 849 | if (num == 0 && e->single.func == probe) | 879 | if (num == 0 && e->single.func == probe) |
| 850 | return e->single.probe_private; | 880 | return e->single.probe_private; |
| 851 | else | ||
| 852 | break; | ||
| 853 | } else { | 881 | } else { |
| 854 | struct marker_probe_closure *closure; | 882 | struct marker_probe_closure *closure; |
| 855 | int match = 0; | 883 | int match = 0; |
| @@ -861,8 +889,42 @@ void *marker_get_private_data(const char *name, marker_probe_func *probe, | |||
| 861 | return closure[i].probe_private; | 889 | return closure[i].probe_private; |
| 862 | } | 890 | } |
| 863 | } | 891 | } |
| 892 | break; | ||
| 864 | } | 893 | } |
| 865 | } | 894 | } |
| 866 | return ERR_PTR(-ENOENT); | 895 | return ERR_PTR(-ENOENT); |
| 867 | } | 896 | } |
| 868 | EXPORT_SYMBOL_GPL(marker_get_private_data); | 897 | EXPORT_SYMBOL_GPL(marker_get_private_data); |
| 898 | |||
| 899 | #ifdef CONFIG_MODULES | ||
| 900 | |||
| 901 | int marker_module_notify(struct notifier_block *self, | ||
| 902 | unsigned long val, void *data) | ||
| 903 | { | ||
| 904 | struct module *mod = data; | ||
| 905 | |||
| 906 | switch (val) { | ||
| 907 | case MODULE_STATE_COMING: | ||
| 908 | marker_update_probe_range(mod->markers, | ||
| 909 | mod->markers + mod->num_markers); | ||
| 910 | break; | ||
| 911 | case MODULE_STATE_GOING: | ||
| 912 | marker_update_probe_range(mod->markers, | ||
| 913 | mod->markers + mod->num_markers); | ||
| 914 | break; | ||
| 915 | } | ||
| 916 | return 0; | ||
| 917 | } | ||
| 918 | |||
| 919 | struct notifier_block marker_module_nb = { | ||
| 920 | .notifier_call = marker_module_notify, | ||
| 921 | .priority = 0, | ||
| 922 | }; | ||
| 923 | |||
| 924 | static int init_markers(void) | ||
| 925 | { | ||
| 926 | return register_module_notifier(&marker_module_nb); | ||
| 927 | } | ||
| 928 | __initcall(init_markers); | ||
| 929 | |||
| 930 | #endif /* CONFIG_MODULES */ | ||
