diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/Kconfig | 2 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 19 | ||||
-rw-r--r-- | kernel/trace/ring_buffer.c | 2 | ||||
-rw-r--r-- | kernel/trace/trace_event_perf.c | 3 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 43 |
5 files changed, 43 insertions, 26 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 538501c6ea50..6329d063b5e4 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
@@ -121,7 +121,7 @@ if FTRACE | |||
121 | config FUNCTION_TRACER | 121 | config FUNCTION_TRACER |
122 | bool "Kernel Function Tracer" | 122 | bool "Kernel Function Tracer" |
123 | depends on HAVE_FUNCTION_TRACER | 123 | depends on HAVE_FUNCTION_TRACER |
124 | select FRAME_POINTER | 124 | select FRAME_POINTER if (!ARM_UNWIND) |
125 | select KALLSYMS | 125 | select KALLSYMS |
126 | select GENERIC_TRACER | 126 | select GENERIC_TRACER |
127 | select CONTEXT_SWITCH_TRACER | 127 | select CONTEXT_SWITCH_TRACER |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0d88ce9b9fb8..fa7ece649fe1 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -381,12 +381,19 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
381 | { | 381 | { |
382 | struct ftrace_profile *rec = v; | 382 | struct ftrace_profile *rec = v; |
383 | char str[KSYM_SYMBOL_LEN]; | 383 | char str[KSYM_SYMBOL_LEN]; |
384 | int ret = 0; | ||
384 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 385 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
385 | static DEFINE_MUTEX(mutex); | ||
386 | static struct trace_seq s; | 386 | static struct trace_seq s; |
387 | unsigned long long avg; | 387 | unsigned long long avg; |
388 | unsigned long long stddev; | 388 | unsigned long long stddev; |
389 | #endif | 389 | #endif |
390 | mutex_lock(&ftrace_profile_lock); | ||
391 | |||
392 | /* we raced with function_profile_reset() */ | ||
393 | if (unlikely(rec->counter == 0)) { | ||
394 | ret = -EBUSY; | ||
395 | goto out; | ||
396 | } | ||
390 | 397 | ||
391 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | 398 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); |
392 | seq_printf(m, " %-30.30s %10lu", str, rec->counter); | 399 | seq_printf(m, " %-30.30s %10lu", str, rec->counter); |
@@ -408,7 +415,6 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
408 | do_div(stddev, (rec->counter - 1) * 1000); | 415 | do_div(stddev, (rec->counter - 1) * 1000); |
409 | } | 416 | } |
410 | 417 | ||
411 | mutex_lock(&mutex); | ||
412 | trace_seq_init(&s); | 418 | trace_seq_init(&s); |
413 | trace_print_graph_duration(rec->time, &s); | 419 | trace_print_graph_duration(rec->time, &s); |
414 | trace_seq_puts(&s, " "); | 420 | trace_seq_puts(&s, " "); |
@@ -416,11 +422,12 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
416 | trace_seq_puts(&s, " "); | 422 | trace_seq_puts(&s, " "); |
417 | trace_print_graph_duration(stddev, &s); | 423 | trace_print_graph_duration(stddev, &s); |
418 | trace_print_seq(m, &s); | 424 | trace_print_seq(m, &s); |
419 | mutex_unlock(&mutex); | ||
420 | #endif | 425 | #endif |
421 | seq_putc(m, '\n'); | 426 | seq_putc(m, '\n'); |
427 | out: | ||
428 | mutex_unlock(&ftrace_profile_lock); | ||
422 | 429 | ||
423 | return 0; | 430 | return ret; |
424 | } | 431 | } |
425 | 432 | ||
426 | static void ftrace_profile_reset(struct ftrace_profile_stat *stat) | 433 | static void ftrace_profile_reset(struct ftrace_profile_stat *stat) |
@@ -1503,6 +1510,8 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
1503 | if (*pos > 0) | 1510 | if (*pos > 0) |
1504 | return t_hash_start(m, pos); | 1511 | return t_hash_start(m, pos); |
1505 | iter->flags |= FTRACE_ITER_PRINTALL; | 1512 | iter->flags |= FTRACE_ITER_PRINTALL; |
1513 | /* reset in case of seek/pread */ | ||
1514 | iter->flags &= ~FTRACE_ITER_HASH; | ||
1506 | return iter; | 1515 | return iter; |
1507 | } | 1516 | } |
1508 | 1517 | ||
@@ -2409,7 +2418,7 @@ static const struct file_operations ftrace_filter_fops = { | |||
2409 | .open = ftrace_filter_open, | 2418 | .open = ftrace_filter_open, |
2410 | .read = seq_read, | 2419 | .read = seq_read, |
2411 | .write = ftrace_filter_write, | 2420 | .write = ftrace_filter_write, |
2412 | .llseek = ftrace_regex_lseek, | 2421 | .llseek = no_llseek, |
2413 | .release = ftrace_filter_release, | 2422 | .release = ftrace_filter_release, |
2414 | }; | 2423 | }; |
2415 | 2424 | ||
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 19cccc3c3028..492197e2f86c 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
@@ -2985,13 +2985,11 @@ static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer) | |||
2985 | 2985 | ||
2986 | static void rb_advance_iter(struct ring_buffer_iter *iter) | 2986 | static void rb_advance_iter(struct ring_buffer_iter *iter) |
2987 | { | 2987 | { |
2988 | struct ring_buffer *buffer; | ||
2989 | struct ring_buffer_per_cpu *cpu_buffer; | 2988 | struct ring_buffer_per_cpu *cpu_buffer; |
2990 | struct ring_buffer_event *event; | 2989 | struct ring_buffer_event *event; |
2991 | unsigned length; | 2990 | unsigned length; |
2992 | 2991 | ||
2993 | cpu_buffer = iter->cpu_buffer; | 2992 | cpu_buffer = iter->cpu_buffer; |
2994 | buffer = cpu_buffer->buffer; | ||
2995 | 2993 | ||
2996 | /* | 2994 | /* |
2997 | * Check if we are at the end of the buffer. | 2995 | * Check if we are at the end of the buffer. |
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 000e6e85b445..31cc4cb0dbf2 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
@@ -91,6 +91,8 @@ int perf_trace_init(struct perf_event *p_event) | |||
91 | tp_event->class && tp_event->class->reg && | 91 | tp_event->class && tp_event->class->reg && |
92 | try_module_get(tp_event->mod)) { | 92 | try_module_get(tp_event->mod)) { |
93 | ret = perf_trace_event_init(tp_event, p_event); | 93 | ret = perf_trace_event_init(tp_event, p_event); |
94 | if (ret) | ||
95 | module_put(tp_event->mod); | ||
94 | break; | 96 | break; |
95 | } | 97 | } |
96 | } | 98 | } |
@@ -146,6 +148,7 @@ void perf_trace_destroy(struct perf_event *p_event) | |||
146 | } | 148 | } |
147 | } | 149 | } |
148 | out: | 150 | out: |
151 | module_put(tp_event->mod); | ||
149 | mutex_unlock(&event_mutex); | 152 | mutex_unlock(&event_mutex); |
150 | } | 153 | } |
151 | 154 | ||
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 8b27c9849b42..544301d29dee 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -514,8 +514,8 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); | |||
514 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, | 514 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, |
515 | struct pt_regs *regs); | 515 | struct pt_regs *regs); |
516 | 516 | ||
517 | /* Check the name is good for event/group */ | 517 | /* Check the name is good for event/group/fields */ |
518 | static int check_event_name(const char *name) | 518 | static int is_good_name(const char *name) |
519 | { | 519 | { |
520 | if (!isalpha(*name) && *name != '_') | 520 | if (!isalpha(*name) && *name != '_') |
521 | return 0; | 521 | return 0; |
@@ -557,7 +557,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
557 | else | 557 | else |
558 | tp->rp.kp.pre_handler = kprobe_dispatcher; | 558 | tp->rp.kp.pre_handler = kprobe_dispatcher; |
559 | 559 | ||
560 | if (!event || !check_event_name(event)) { | 560 | if (!event || !is_good_name(event)) { |
561 | ret = -EINVAL; | 561 | ret = -EINVAL; |
562 | goto error; | 562 | goto error; |
563 | } | 563 | } |
@@ -567,7 +567,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
567 | if (!tp->call.name) | 567 | if (!tp->call.name) |
568 | goto error; | 568 | goto error; |
569 | 569 | ||
570 | if (!group || !check_event_name(group)) { | 570 | if (!group || !is_good_name(group)) { |
571 | ret = -EINVAL; | 571 | ret = -EINVAL; |
572 | goto error; | 572 | goto error; |
573 | } | 573 | } |
@@ -883,7 +883,7 @@ static int create_trace_probe(int argc, char **argv) | |||
883 | int i, ret = 0; | 883 | int i, ret = 0; |
884 | int is_return = 0, is_delete = 0; | 884 | int is_return = 0, is_delete = 0; |
885 | char *symbol = NULL, *event = NULL, *group = NULL; | 885 | char *symbol = NULL, *event = NULL, *group = NULL; |
886 | char *arg, *tmp; | 886 | char *arg; |
887 | unsigned long offset = 0; | 887 | unsigned long offset = 0; |
888 | void *addr = NULL; | 888 | void *addr = NULL; |
889 | char buf[MAX_EVENT_NAME_LEN]; | 889 | char buf[MAX_EVENT_NAME_LEN]; |
@@ -992,26 +992,36 @@ static int create_trace_probe(int argc, char **argv) | |||
992 | /* parse arguments */ | 992 | /* parse arguments */ |
993 | ret = 0; | 993 | ret = 0; |
994 | for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { | 994 | for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { |
995 | /* Increment count for freeing args in error case */ | ||
996 | tp->nr_args++; | ||
997 | |||
995 | /* Parse argument name */ | 998 | /* Parse argument name */ |
996 | arg = strchr(argv[i], '='); | 999 | arg = strchr(argv[i], '='); |
997 | if (arg) | 1000 | if (arg) { |
998 | *arg++ = '\0'; | 1001 | *arg++ = '\0'; |
999 | else | 1002 | tp->args[i].name = kstrdup(argv[i], GFP_KERNEL); |
1003 | } else { | ||
1000 | arg = argv[i]; | 1004 | arg = argv[i]; |
1005 | /* If argument name is omitted, set "argN" */ | ||
1006 | snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1); | ||
1007 | tp->args[i].name = kstrdup(buf, GFP_KERNEL); | ||
1008 | } | ||
1001 | 1009 | ||
1002 | tp->args[i].name = kstrdup(argv[i], GFP_KERNEL); | ||
1003 | if (!tp->args[i].name) { | 1010 | if (!tp->args[i].name) { |
1004 | pr_info("Failed to allocate argument%d name '%s'.\n", | 1011 | pr_info("Failed to allocate argument[%d] name.\n", i); |
1005 | i, argv[i]); | ||
1006 | ret = -ENOMEM; | 1012 | ret = -ENOMEM; |
1007 | goto error; | 1013 | goto error; |
1008 | } | 1014 | } |
1009 | tmp = strchr(tp->args[i].name, ':'); | 1015 | |
1010 | if (tmp) | 1016 | if (!is_good_name(tp->args[i].name)) { |
1011 | *tmp = '_'; /* convert : to _ */ | 1017 | pr_info("Invalid argument[%d] name: %s\n", |
1018 | i, tp->args[i].name); | ||
1019 | ret = -EINVAL; | ||
1020 | goto error; | ||
1021 | } | ||
1012 | 1022 | ||
1013 | if (conflict_field_name(tp->args[i].name, tp->args, i)) { | 1023 | if (conflict_field_name(tp->args[i].name, tp->args, i)) { |
1014 | pr_info("Argument%d name '%s' conflicts with " | 1024 | pr_info("Argument[%d] name '%s' conflicts with " |
1015 | "another field.\n", i, argv[i]); | 1025 | "another field.\n", i, argv[i]); |
1016 | ret = -EINVAL; | 1026 | ret = -EINVAL; |
1017 | goto error; | 1027 | goto error; |
@@ -1020,12 +1030,9 @@ static int create_trace_probe(int argc, char **argv) | |||
1020 | /* Parse fetch argument */ | 1030 | /* Parse fetch argument */ |
1021 | ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); | 1031 | ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); |
1022 | if (ret) { | 1032 | if (ret) { |
1023 | pr_info("Parse error at argument%d. (%d)\n", i, ret); | 1033 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); |
1024 | kfree(tp->args[i].name); | ||
1025 | goto error; | 1034 | goto error; |
1026 | } | 1035 | } |
1027 | |||
1028 | tp->nr_args++; | ||
1029 | } | 1036 | } |
1030 | 1037 | ||
1031 | ret = register_trace_probe(tp); | 1038 | ret = register_trace_probe(tp); |