diff options
| author | Ingo Molnar <mingo@elte.hu> | 2011-04-27 04:38:30 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2011-04-27 04:40:21 -0400 |
| commit | 32673822e440eb92eb334631eb0a199d0c532d13 (patch) | |
| tree | c1e55c1793fa17937d9b8e0a9a2946583f1948d5 /kernel/trace | |
| parent | fa7b69475a6c192853949ba496dd9c37b497b548 (diff) | |
| parent | 5373db886b791b2bc7811e2c115377916c409a5d (diff) | |
Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into perf/core
Conflicts:
include/linux/perf_event.h
Merge reason: pick up the latest jump-label enhancements, they are cooked ready.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/trace.c | 15 | ||||
| -rw-r--r-- | kernel/trace/trace_output.c | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_printk.c | 120 |
3 files changed, 123 insertions, 15 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index d38c16a06a6f..e0e14ce0caab 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -2013,9 +2013,10 @@ enum print_line_t print_trace_line(struct trace_iterator *iter) | |||
| 2013 | { | 2013 | { |
| 2014 | enum print_line_t ret; | 2014 | enum print_line_t ret; |
| 2015 | 2015 | ||
| 2016 | if (iter->lost_events) | 2016 | if (iter->lost_events && |
| 2017 | trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n", | 2017 | !trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n", |
| 2018 | iter->cpu, iter->lost_events); | 2018 | iter->cpu, iter->lost_events)) |
| 2019 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 2019 | 2020 | ||
| 2020 | if (iter->trace && iter->trace->print_line) { | 2021 | if (iter->trace && iter->trace->print_line) { |
| 2021 | ret = iter->trace->print_line(iter); | 2022 | ret = iter->trace->print_line(iter); |
| @@ -3229,6 +3230,14 @@ waitagain: | |||
| 3229 | 3230 | ||
| 3230 | if (iter->seq.len >= cnt) | 3231 | if (iter->seq.len >= cnt) |
| 3231 | break; | 3232 | break; |
| 3233 | |||
| 3234 | /* | ||
| 3235 | * Setting the full flag means we reached the trace_seq buffer | ||
| 3236 | * size and we should leave by partial output condition above. | ||
| 3237 | * One of the trace_seq_* functions is not used properly. | ||
| 3238 | */ | ||
| 3239 | WARN_ONCE(iter->seq.full, "full flag set for trace type %d", | ||
| 3240 | iter->ent->type); | ||
| 3232 | } | 3241 | } |
| 3233 | trace_access_unlock(iter->cpu_file); | 3242 | trace_access_unlock(iter->cpu_file); |
| 3234 | trace_event_read_unlock(); | 3243 | trace_event_read_unlock(); |
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 456be9063c2d..cf535ccedc86 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
| @@ -830,6 +830,9 @@ EXPORT_SYMBOL_GPL(unregister_ftrace_event); | |||
| 830 | enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags, | 830 | enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags, |
| 831 | struct trace_event *event) | 831 | struct trace_event *event) |
| 832 | { | 832 | { |
| 833 | if (!trace_seq_printf(&iter->seq, "type: %d\n", iter->ent->type)) | ||
| 834 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 835 | |||
| 833 | return TRACE_TYPE_HANDLED; | 836 | return TRACE_TYPE_HANDLED; |
| 834 | } | 837 | } |
| 835 | 838 | ||
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index 2547d8813cf0..dff763b7baf1 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c | |||
| @@ -32,7 +32,7 @@ static DEFINE_MUTEX(btrace_mutex); | |||
| 32 | 32 | ||
| 33 | struct trace_bprintk_fmt { | 33 | struct trace_bprintk_fmt { |
| 34 | struct list_head list; | 34 | struct list_head list; |
| 35 | char fmt[0]; | 35 | const char *fmt; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | static inline struct trace_bprintk_fmt *lookup_format(const char *fmt) | 38 | static inline struct trace_bprintk_fmt *lookup_format(const char *fmt) |
| @@ -49,6 +49,7 @@ static | |||
| 49 | void hold_module_trace_bprintk_format(const char **start, const char **end) | 49 | void hold_module_trace_bprintk_format(const char **start, const char **end) |
| 50 | { | 50 | { |
| 51 | const char **iter; | 51 | const char **iter; |
| 52 | char *fmt; | ||
| 52 | 53 | ||
| 53 | mutex_lock(&btrace_mutex); | 54 | mutex_lock(&btrace_mutex); |
| 54 | for (iter = start; iter < end; iter++) { | 55 | for (iter = start; iter < end; iter++) { |
| @@ -58,14 +59,18 @@ void hold_module_trace_bprintk_format(const char **start, const char **end) | |||
| 58 | continue; | 59 | continue; |
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | tb_fmt = kmalloc(offsetof(struct trace_bprintk_fmt, fmt) | 62 | tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL); |
| 62 | + strlen(*iter) + 1, GFP_KERNEL); | 63 | if (tb_fmt) |
| 63 | if (tb_fmt) { | 64 | fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL); |
| 65 | if (tb_fmt && fmt) { | ||
| 64 | list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list); | 66 | list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list); |
| 65 | strcpy(tb_fmt->fmt, *iter); | 67 | strcpy(fmt, *iter); |
| 68 | tb_fmt->fmt = fmt; | ||
| 66 | *iter = tb_fmt->fmt; | 69 | *iter = tb_fmt->fmt; |
| 67 | } else | 70 | } else { |
| 71 | kfree(tb_fmt); | ||
| 68 | *iter = NULL; | 72 | *iter = NULL; |
| 73 | } | ||
| 69 | } | 74 | } |
| 70 | mutex_unlock(&btrace_mutex); | 75 | mutex_unlock(&btrace_mutex); |
| 71 | } | 76 | } |
| @@ -84,6 +89,76 @@ static int module_trace_bprintk_format_notify(struct notifier_block *self, | |||
| 84 | return 0; | 89 | return 0; |
| 85 | } | 90 | } |
| 86 | 91 | ||
| 92 | /* | ||
| 93 | * The debugfs/tracing/printk_formats file maps the addresses with | ||
| 94 | * the ASCII formats that are used in the bprintk events in the | ||
| 95 | * buffer. For userspace tools to be able to decode the events from | ||
| 96 | * the buffer, they need to be able to map the address with the format. | ||
| 97 | * | ||
| 98 | * The addresses of the bprintk formats are in their own section | ||
| 99 | * __trace_printk_fmt. But for modules we copy them into a link list. | ||
| 100 | * The code to print the formats and their addresses passes around the | ||
| 101 | * address of the fmt string. If the fmt address passed into the seq | ||
| 102 | * functions is within the kernel core __trace_printk_fmt section, then | ||
| 103 | * it simply uses the next pointer in the list. | ||
| 104 | * | ||
| 105 | * When the fmt pointer is outside the kernel core __trace_printk_fmt | ||
| 106 | * section, then we need to read the link list pointers. The trick is | ||
| 107 | * we pass the address of the string to the seq function just like | ||
| 108 | * we do for the kernel core formats. To get back the structure that | ||
| 109 | * holds the format, we simply use containerof() and then go to the | ||
| 110 | * next format in the list. | ||
| 111 | */ | ||
| 112 | static const char ** | ||
| 113 | find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos) | ||
| 114 | { | ||
| 115 | struct trace_bprintk_fmt *mod_fmt; | ||
| 116 | |||
| 117 | if (list_empty(&trace_bprintk_fmt_list)) | ||
| 118 | return NULL; | ||
| 119 | |||
| 120 | /* | ||
| 121 | * v will point to the address of the fmt record from t_next | ||
| 122 | * v will be NULL from t_start. | ||
| 123 | * If this is the first pointer or called from start | ||
| 124 | * then we need to walk the list. | ||
| 125 | */ | ||
| 126 | if (!v || start_index == *pos) { | ||
| 127 | struct trace_bprintk_fmt *p; | ||
| 128 | |||
| 129 | /* search the module list */ | ||
| 130 | list_for_each_entry(p, &trace_bprintk_fmt_list, list) { | ||
| 131 | if (start_index == *pos) | ||
| 132 | return &p->fmt; | ||
| 133 | start_index++; | ||
| 134 | } | ||
| 135 | /* pos > index */ | ||
| 136 | return NULL; | ||
| 137 | } | ||
| 138 | |||
| 139 | /* | ||
| 140 | * v points to the address of the fmt field in the mod list | ||
| 141 | * structure that holds the module print format. | ||
| 142 | */ | ||
| 143 | mod_fmt = container_of(v, typeof(*mod_fmt), fmt); | ||
| 144 | if (mod_fmt->list.next == &trace_bprintk_fmt_list) | ||
| 145 | return NULL; | ||
| 146 | |||
| 147 | mod_fmt = container_of(mod_fmt->list.next, typeof(*mod_fmt), list); | ||
| 148 | |||
| 149 | return &mod_fmt->fmt; | ||
| 150 | } | ||
| 151 | |||
| 152 | static void format_mod_start(void) | ||
| 153 | { | ||
| 154 | mutex_lock(&btrace_mutex); | ||
| 155 | } | ||
| 156 | |||
| 157 | static void format_mod_stop(void) | ||
| 158 | { | ||
| 159 | mutex_unlock(&btrace_mutex); | ||
| 160 | } | ||
| 161 | |||
| 87 | #else /* !CONFIG_MODULES */ | 162 | #else /* !CONFIG_MODULES */ |
| 88 | __init static int | 163 | __init static int |
| 89 | module_trace_bprintk_format_notify(struct notifier_block *self, | 164 | module_trace_bprintk_format_notify(struct notifier_block *self, |
| @@ -91,6 +166,13 @@ module_trace_bprintk_format_notify(struct notifier_block *self, | |||
| 91 | { | 166 | { |
| 92 | return 0; | 167 | return 0; |
| 93 | } | 168 | } |
| 169 | static inline const char ** | ||
| 170 | find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos) | ||
| 171 | { | ||
| 172 | return NULL; | ||
| 173 | } | ||
| 174 | static inline void format_mod_start(void) { } | ||
| 175 | static inline void format_mod_stop(void) { } | ||
| 94 | #endif /* CONFIG_MODULES */ | 176 | #endif /* CONFIG_MODULES */ |
| 95 | 177 | ||
| 96 | 178 | ||
| @@ -153,20 +235,33 @@ int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap) | |||
| 153 | } | 235 | } |
| 154 | EXPORT_SYMBOL_GPL(__ftrace_vprintk); | 236 | EXPORT_SYMBOL_GPL(__ftrace_vprintk); |
| 155 | 237 | ||
| 238 | static const char **find_next(void *v, loff_t *pos) | ||
| 239 | { | ||
| 240 | const char **fmt = v; | ||
| 241 | int start_index; | ||
| 242 | |||
| 243 | if (!fmt) | ||
| 244 | fmt = __start___trace_bprintk_fmt + *pos; | ||
| 245 | |||
| 246 | start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt; | ||
| 247 | |||
| 248 | if (*pos < start_index) | ||
| 249 | return fmt; | ||
| 250 | |||
| 251 | return find_next_mod_format(start_index, v, fmt, pos); | ||
| 252 | } | ||
| 253 | |||
| 156 | static void * | 254 | static void * |
| 157 | t_start(struct seq_file *m, loff_t *pos) | 255 | t_start(struct seq_file *m, loff_t *pos) |
| 158 | { | 256 | { |
| 159 | const char **fmt = __start___trace_bprintk_fmt + *pos; | 257 | format_mod_start(); |
| 160 | 258 | return find_next(NULL, pos); | |
| 161 | if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt) | ||
| 162 | return NULL; | ||
| 163 | return fmt; | ||
| 164 | } | 259 | } |
| 165 | 260 | ||
| 166 | static void *t_next(struct seq_file *m, void * v, loff_t *pos) | 261 | static void *t_next(struct seq_file *m, void * v, loff_t *pos) |
| 167 | { | 262 | { |
| 168 | (*pos)++; | 263 | (*pos)++; |
| 169 | return t_start(m, pos); | 264 | return find_next(v, pos); |
| 170 | } | 265 | } |
| 171 | 266 | ||
| 172 | static int t_show(struct seq_file *m, void *v) | 267 | static int t_show(struct seq_file *m, void *v) |
| @@ -205,6 +300,7 @@ static int t_show(struct seq_file *m, void *v) | |||
| 205 | 300 | ||
| 206 | static void t_stop(struct seq_file *m, void *p) | 301 | static void t_stop(struct seq_file *m, void *p) |
| 207 | { | 302 | { |
| 303 | format_mod_stop(); | ||
| 208 | } | 304 | } |
| 209 | 305 | ||
| 210 | static const struct seq_operations show_format_seq_ops = { | 306 | static const struct seq_operations show_format_seq_ops = { |
