diff options
-rw-r--r-- | include/linux/marker.h | 45 | ||||
-rw-r--r-- | init/Kconfig | 1 | ||||
-rw-r--r-- | kernel/marker.c | 53 |
3 files changed, 96 insertions, 3 deletions
diff --git a/include/linux/marker.h b/include/linux/marker.h index 05ec0df37089..57a307018ceb 100644 --- a/include/linux/marker.h +++ b/include/linux/marker.h | |||
@@ -49,6 +49,8 @@ struct marker { | |||
49 | void (*call)(const struct marker *mdata, void *call_private, ...); | 49 | void (*call)(const struct marker *mdata, void *call_private, ...); |
50 | struct marker_probe_closure single; | 50 | struct marker_probe_closure single; |
51 | struct marker_probe_closure *multi; | 51 | struct marker_probe_closure *multi; |
52 | const char *tp_name; /* Optional tracepoint name */ | ||
53 | void *tp_cb; /* Optional tracepoint callback */ | ||
52 | } __attribute__((aligned(8))); | 54 | } __attribute__((aligned(8))); |
53 | 55 | ||
54 | #ifdef CONFIG_MARKERS | 56 | #ifdef CONFIG_MARKERS |
@@ -73,7 +75,7 @@ struct marker { | |||
73 | __attribute__((section("__markers"), aligned(8))) = \ | 75 | __attribute__((section("__markers"), aligned(8))) = \ |
74 | { __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \ | 76 | { __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \ |
75 | 0, 0, marker_probe_cb, \ | 77 | 0, 0, marker_probe_cb, \ |
76 | { __mark_empty_function, NULL}, NULL }; \ | 78 | { __mark_empty_function, NULL}, NULL, NULL, NULL }; \ |
77 | __mark_check_format(format, ## args); \ | 79 | __mark_check_format(format, ## args); \ |
78 | if (unlikely(__mark_##name.state)) { \ | 80 | if (unlikely(__mark_##name.state)) { \ |
79 | (*__mark_##name.call) \ | 81 | (*__mark_##name.call) \ |
@@ -81,11 +83,38 @@ struct marker { | |||
81 | } \ | 83 | } \ |
82 | } while (0) | 84 | } while (0) |
83 | 85 | ||
86 | #define __trace_mark_tp(name, call_private, tp_name, tp_cb, format, args...) \ | ||
87 | do { \ | ||
88 | void __check_tp_type(void) \ | ||
89 | { \ | ||
90 | register_trace_##tp_name(tp_cb); \ | ||
91 | } \ | ||
92 | static const char __mstrtab_##name[] \ | ||
93 | __attribute__((section("__markers_strings"))) \ | ||
94 | = #name "\0" format; \ | ||
95 | static struct marker __mark_##name \ | ||
96 | __attribute__((section("__markers"), aligned(8))) = \ | ||
97 | { __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \ | ||
98 | 0, 0, marker_probe_cb, \ | ||
99 | { __mark_empty_function, NULL}, NULL, #tp_name, tp_cb };\ | ||
100 | __mark_check_format(format, ## args); \ | ||
101 | (*__mark_##name.call)(&__mark_##name, call_private, \ | ||
102 | ## args); \ | ||
103 | } while (0) | ||
104 | |||
84 | extern void marker_update_probe_range(struct marker *begin, | 105 | extern void marker_update_probe_range(struct marker *begin, |
85 | struct marker *end); | 106 | struct marker *end); |
86 | #else /* !CONFIG_MARKERS */ | 107 | #else /* !CONFIG_MARKERS */ |
87 | #define __trace_mark(generic, name, call_private, format, args...) \ | 108 | #define __trace_mark(generic, name, call_private, format, args...) \ |
88 | __mark_check_format(format, ## args) | 109 | __mark_check_format(format, ## args) |
110 | #define __trace_mark_tp(name, call_private, tp_name, tp_cb, format, args...) \ | ||
111 | do { \ | ||
112 | void __check_tp_type(void) \ | ||
113 | { \ | ||
114 | register_trace_##tp_name(tp_cb); \ | ||
115 | } \ | ||
116 | __mark_check_format(format, ## args); \ | ||
117 | } while (0) | ||
89 | static inline void marker_update_probe_range(struct marker *begin, | 118 | static inline void marker_update_probe_range(struct marker *begin, |
90 | struct marker *end) | 119 | struct marker *end) |
91 | { } | 120 | { } |
@@ -118,6 +147,20 @@ static inline void marker_update_probe_range(struct marker *begin, | |||
118 | __trace_mark(1, name, NULL, format, ## args) | 147 | __trace_mark(1, name, NULL, format, ## args) |
119 | 148 | ||
120 | /** | 149 | /** |
150 | * trace_mark_tp - Marker in a tracepoint callback | ||
151 | * @name: marker name, not quoted. | ||
152 | * @tp_name: tracepoint name, not quoted. | ||
153 | * @tp_cb: tracepoint callback. Should have an associated global symbol so it | ||
154 | * is not optimized away by the compiler (should not be static). | ||
155 | * @format: format string | ||
156 | * @args...: variable argument list | ||
157 | * | ||
158 | * Places a marker in a tracepoint callback. | ||
159 | */ | ||
160 | #define trace_mark_tp(name, tp_name, tp_cb, format, args...) \ | ||
161 | __trace_mark_tp(name, NULL, tp_name, tp_cb, format, ## args) | ||
162 | |||
163 | /** | ||
121 | * MARK_NOARGS - Format string for a marker with no argument. | 164 | * MARK_NOARGS - Format string for a marker with no argument. |
122 | */ | 165 | */ |
123 | #define MARK_NOARGS " " | 166 | #define MARK_NOARGS " " |
diff --git a/init/Kconfig b/init/Kconfig index 86b00c53fade..f5bacb438711 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -808,6 +808,7 @@ config TRACEPOINTS | |||
808 | 808 | ||
809 | config MARKERS | 809 | config MARKERS |
810 | bool "Activate markers" | 810 | bool "Activate markers" |
811 | depends on TRACEPOINTS | ||
811 | help | 812 | help |
812 | Place an empty function call at each marker site. Can be | 813 | Place an empty function call at each marker site. Can be |
813 | dynamically changed for a probe function. | 814 | dynamically changed for a probe function. |
diff --git a/kernel/marker.c b/kernel/marker.c index 348e70cc355a..c14ec26a9b9f 100644 --- a/kernel/marker.c +++ b/kernel/marker.c | |||
@@ -479,7 +479,7 @@ static int marker_set_format(struct marker_entry *entry, const char *format) | |||
479 | static int set_marker(struct marker_entry *entry, struct marker *elem, | 479 | static int set_marker(struct marker_entry *entry, struct marker *elem, |
480 | int active) | 480 | int active) |
481 | { | 481 | { |
482 | int ret; | 482 | int ret = 0; |
483 | WARN_ON(strcmp(entry->name, elem->name) != 0); | 483 | WARN_ON(strcmp(entry->name, elem->name) != 0); |
484 | 484 | ||
485 | if (entry->format) { | 485 | if (entry->format) { |
@@ -531,9 +531,40 @@ static int set_marker(struct marker_entry *entry, struct marker *elem, | |||
531 | */ | 531 | */ |
532 | smp_wmb(); | 532 | smp_wmb(); |
533 | 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 | } | ||
534 | elem->state = active; | 565 | elem->state = active; |
535 | 566 | ||
536 | return 0; | 567 | return ret; |
537 | } | 568 | } |
538 | 569 | ||
539 | /* | 570 | /* |
@@ -544,7 +575,24 @@ static int set_marker(struct marker_entry *entry, struct marker *elem, | |||
544 | */ | 575 | */ |
545 | static void disable_marker(struct marker *elem) | 576 | static void disable_marker(struct marker *elem) |
546 | { | 577 | { |
578 | int ret; | ||
579 | |||
547 | /* 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 | } | ||
548 | elem->state = 0; | 596 | elem->state = 0; |
549 | elem->single.func = __mark_empty_function; | 597 | elem->single.func = __mark_empty_function; |
550 | /* Update the function before setting the ptype */ | 598 | /* Update the function before setting the ptype */ |
@@ -608,6 +656,7 @@ static void marker_update_probes(void) | |||
608 | marker_update_probe_range(__start___markers, __stop___markers); | 656 | marker_update_probe_range(__start___markers, __stop___markers); |
609 | /* Markers in modules. */ | 657 | /* Markers in modules. */ |
610 | module_update_markers(); | 658 | module_update_markers(); |
659 | tracepoint_probe_update_all(); | ||
611 | } | 660 | } |
612 | 661 | ||
613 | /** | 662 | /** |