diff options
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r-- | kernel/trace/trace.c | 82 |
1 files changed, 53 insertions, 29 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index d345d649d073..697eda36b86a 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include <linux/stacktrace.h> | 35 | #include <linux/stacktrace.h> |
36 | #include <linux/ring_buffer.h> | 36 | #include <linux/ring_buffer.h> |
37 | #include <linux/irqflags.h> | ||
37 | 38 | ||
38 | #include "trace.h" | 39 | #include "trace.h" |
39 | 40 | ||
@@ -655,7 +656,11 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, | |||
655 | entry->preempt_count = pc & 0xff; | 656 | entry->preempt_count = pc & 0xff; |
656 | entry->pid = (tsk) ? tsk->pid : 0; | 657 | entry->pid = (tsk) ? tsk->pid : 0; |
657 | entry->flags = | 658 | entry->flags = |
659 | #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT | ||
658 | (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) | | 660 | (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) | |
661 | #else | ||
662 | TRACE_FLAG_IRQS_NOSUPPORT | | ||
663 | #endif | ||
659 | ((pc & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) | | 664 | ((pc & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) | |
660 | ((pc & SOFTIRQ_MASK) ? TRACE_FLAG_SOFTIRQ : 0) | | 665 | ((pc & SOFTIRQ_MASK) ? TRACE_FLAG_SOFTIRQ : 0) | |
661 | (need_resched() ? TRACE_FLAG_NEED_RESCHED : 0); | 666 | (need_resched() ? TRACE_FLAG_NEED_RESCHED : 0); |
@@ -700,6 +705,7 @@ static void ftrace_trace_stack(struct trace_array *tr, | |||
700 | unsigned long flags, | 705 | unsigned long flags, |
701 | int skip, int pc) | 706 | int skip, int pc) |
702 | { | 707 | { |
708 | #ifdef CONFIG_STACKTRACE | ||
703 | struct ring_buffer_event *event; | 709 | struct ring_buffer_event *event; |
704 | struct stack_entry *entry; | 710 | struct stack_entry *entry; |
705 | struct stack_trace trace; | 711 | struct stack_trace trace; |
@@ -725,6 +731,7 @@ static void ftrace_trace_stack(struct trace_array *tr, | |||
725 | 731 | ||
726 | save_stack_trace(&trace); | 732 | save_stack_trace(&trace); |
727 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); | 733 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); |
734 | #endif | ||
728 | } | 735 | } |
729 | 736 | ||
730 | void __trace_stack(struct trace_array *tr, | 737 | void __trace_stack(struct trace_array *tr, |
@@ -851,7 +858,7 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) | |||
851 | preempt_enable_notrace(); | 858 | preempt_enable_notrace(); |
852 | } | 859 | } |
853 | 860 | ||
854 | #ifdef CONFIG_FTRACE | 861 | #ifdef CONFIG_FUNCTION_TRACER |
855 | static void | 862 | static void |
856 | function_trace_call(unsigned long ip, unsigned long parent_ip) | 863 | function_trace_call(unsigned long ip, unsigned long parent_ip) |
857 | { | 864 | { |
@@ -865,9 +872,6 @@ function_trace_call(unsigned long ip, unsigned long parent_ip) | |||
865 | if (unlikely(!ftrace_function_enabled)) | 872 | if (unlikely(!ftrace_function_enabled)) |
866 | return; | 873 | return; |
867 | 874 | ||
868 | if (skip_trace(ip)) | ||
869 | return; | ||
870 | |||
871 | pc = preempt_count(); | 875 | pc = preempt_count(); |
872 | resched = need_resched(); | 876 | resched = need_resched(); |
873 | preempt_disable_notrace(); | 877 | preempt_disable_notrace(); |
@@ -1084,17 +1088,20 @@ static void s_stop(struct seq_file *m, void *p) | |||
1084 | mutex_unlock(&trace_types_lock); | 1088 | mutex_unlock(&trace_types_lock); |
1085 | } | 1089 | } |
1086 | 1090 | ||
1087 | #define KRETPROBE_MSG "[unknown/kretprobe'd]" | ||
1088 | |||
1089 | #ifdef CONFIG_KRETPROBES | 1091 | #ifdef CONFIG_KRETPROBES |
1090 | static inline int kretprobed(unsigned long addr) | 1092 | static inline const char *kretprobed(const char *name) |
1091 | { | 1093 | { |
1092 | return addr == (unsigned long)kretprobe_trampoline; | 1094 | static const char tramp_name[] = "kretprobe_trampoline"; |
1095 | int size = sizeof(tramp_name); | ||
1096 | |||
1097 | if (strncmp(tramp_name, name, size) == 0) | ||
1098 | return "[unknown/kretprobe'd]"; | ||
1099 | return name; | ||
1093 | } | 1100 | } |
1094 | #else | 1101 | #else |
1095 | static inline int kretprobed(unsigned long addr) | 1102 | static inline const char *kretprobed(const char *name) |
1096 | { | 1103 | { |
1097 | return 0; | 1104 | return name; |
1098 | } | 1105 | } |
1099 | #endif /* CONFIG_KRETPROBES */ | 1106 | #endif /* CONFIG_KRETPROBES */ |
1100 | 1107 | ||
@@ -1103,10 +1110,13 @@ seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address) | |||
1103 | { | 1110 | { |
1104 | #ifdef CONFIG_KALLSYMS | 1111 | #ifdef CONFIG_KALLSYMS |
1105 | char str[KSYM_SYMBOL_LEN]; | 1112 | char str[KSYM_SYMBOL_LEN]; |
1113 | const char *name; | ||
1106 | 1114 | ||
1107 | kallsyms_lookup(address, NULL, NULL, NULL, str); | 1115 | kallsyms_lookup(address, NULL, NULL, NULL, str); |
1108 | 1116 | ||
1109 | return trace_seq_printf(s, fmt, str); | 1117 | name = kretprobed(str); |
1118 | |||
1119 | return trace_seq_printf(s, fmt, name); | ||
1110 | #endif | 1120 | #endif |
1111 | return 1; | 1121 | return 1; |
1112 | } | 1122 | } |
@@ -1117,9 +1127,12 @@ seq_print_sym_offset(struct trace_seq *s, const char *fmt, | |||
1117 | { | 1127 | { |
1118 | #ifdef CONFIG_KALLSYMS | 1128 | #ifdef CONFIG_KALLSYMS |
1119 | char str[KSYM_SYMBOL_LEN]; | 1129 | char str[KSYM_SYMBOL_LEN]; |
1130 | const char *name; | ||
1120 | 1131 | ||
1121 | sprint_symbol(str, address); | 1132 | sprint_symbol(str, address); |
1122 | return trace_seq_printf(s, fmt, str); | 1133 | name = kretprobed(str); |
1134 | |||
1135 | return trace_seq_printf(s, fmt, name); | ||
1123 | #endif | 1136 | #endif |
1124 | return 1; | 1137 | return 1; |
1125 | } | 1138 | } |
@@ -1246,7 +1259,8 @@ lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu) | |||
1246 | trace_seq_printf(s, "%8.8s-%-5d ", comm, entry->pid); | 1259 | trace_seq_printf(s, "%8.8s-%-5d ", comm, entry->pid); |
1247 | trace_seq_printf(s, "%3d", cpu); | 1260 | trace_seq_printf(s, "%3d", cpu); |
1248 | trace_seq_printf(s, "%c%c", | 1261 | trace_seq_printf(s, "%c%c", |
1249 | (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' : '.', | 1262 | (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' : |
1263 | (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ? 'X' : '.', | ||
1250 | ((entry->flags & TRACE_FLAG_NEED_RESCHED) ? 'N' : '.')); | 1264 | ((entry->flags & TRACE_FLAG_NEED_RESCHED) ? 'N' : '.')); |
1251 | 1265 | ||
1252 | hardirq = entry->flags & TRACE_FLAG_HARDIRQ; | 1266 | hardirq = entry->flags & TRACE_FLAG_HARDIRQ; |
@@ -1372,10 +1386,7 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) | |||
1372 | 1386 | ||
1373 | seq_print_ip_sym(s, field->ip, sym_flags); | 1387 | seq_print_ip_sym(s, field->ip, sym_flags); |
1374 | trace_seq_puts(s, " ("); | 1388 | trace_seq_puts(s, " ("); |
1375 | if (kretprobed(field->parent_ip)) | 1389 | seq_print_ip_sym(s, field->parent_ip, sym_flags); |
1376 | trace_seq_puts(s, KRETPROBE_MSG); | ||
1377 | else | ||
1378 | seq_print_ip_sym(s, field->parent_ip, sym_flags); | ||
1379 | trace_seq_puts(s, ")\n"); | 1390 | trace_seq_puts(s, ")\n"); |
1380 | break; | 1391 | break; |
1381 | } | 1392 | } |
@@ -1491,12 +1502,9 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter) | |||
1491 | ret = trace_seq_printf(s, " <-"); | 1502 | ret = trace_seq_printf(s, " <-"); |
1492 | if (!ret) | 1503 | if (!ret) |
1493 | return TRACE_TYPE_PARTIAL_LINE; | 1504 | return TRACE_TYPE_PARTIAL_LINE; |
1494 | if (kretprobed(field->parent_ip)) | 1505 | ret = seq_print_ip_sym(s, |
1495 | ret = trace_seq_puts(s, KRETPROBE_MSG); | 1506 | field->parent_ip, |
1496 | else | 1507 | sym_flags); |
1497 | ret = seq_print_ip_sym(s, | ||
1498 | field->parent_ip, | ||
1499 | sym_flags); | ||
1500 | if (!ret) | 1508 | if (!ret) |
1501 | return TRACE_TYPE_PARTIAL_LINE; | 1509 | return TRACE_TYPE_PARTIAL_LINE; |
1502 | } | 1510 | } |
@@ -1747,7 +1755,7 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter) | |||
1747 | return TRACE_TYPE_HANDLED; | 1755 | return TRACE_TYPE_HANDLED; |
1748 | 1756 | ||
1749 | SEQ_PUT_FIELD_RET(s, entry->pid); | 1757 | SEQ_PUT_FIELD_RET(s, entry->pid); |
1750 | SEQ_PUT_FIELD_RET(s, iter->cpu); | 1758 | SEQ_PUT_FIELD_RET(s, entry->cpu); |
1751 | SEQ_PUT_FIELD_RET(s, iter->ts); | 1759 | SEQ_PUT_FIELD_RET(s, iter->ts); |
1752 | 1760 | ||
1753 | switch (entry->type) { | 1761 | switch (entry->type) { |
@@ -2379,9 +2387,10 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf, | |||
2379 | int i; | 2387 | int i; |
2380 | size_t ret; | 2388 | size_t ret; |
2381 | 2389 | ||
2390 | ret = cnt; | ||
2391 | |||
2382 | if (cnt > max_tracer_type_len) | 2392 | if (cnt > max_tracer_type_len) |
2383 | cnt = max_tracer_type_len; | 2393 | cnt = max_tracer_type_len; |
2384 | ret = cnt; | ||
2385 | 2394 | ||
2386 | if (copy_from_user(&buf, ubuf, cnt)) | 2395 | if (copy_from_user(&buf, ubuf, cnt)) |
2387 | return -EFAULT; | 2396 | return -EFAULT; |
@@ -2414,8 +2423,8 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf, | |||
2414 | out: | 2423 | out: |
2415 | mutex_unlock(&trace_types_lock); | 2424 | mutex_unlock(&trace_types_lock); |
2416 | 2425 | ||
2417 | if (ret == cnt) | 2426 | if (ret > 0) |
2418 | filp->f_pos += cnt; | 2427 | filp->f_pos += ret; |
2419 | 2428 | ||
2420 | return ret; | 2429 | return ret; |
2421 | } | 2430 | } |
@@ -2667,7 +2676,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf, | |||
2667 | { | 2676 | { |
2668 | unsigned long val; | 2677 | unsigned long val; |
2669 | char buf[64]; | 2678 | char buf[64]; |
2670 | int ret; | 2679 | int ret, cpu; |
2671 | struct trace_array *tr = filp->private_data; | 2680 | struct trace_array *tr = filp->private_data; |
2672 | 2681 | ||
2673 | if (cnt >= sizeof(buf)) | 2682 | if (cnt >= sizeof(buf)) |
@@ -2695,6 +2704,14 @@ tracing_entries_write(struct file *filp, const char __user *ubuf, | |||
2695 | goto out; | 2704 | goto out; |
2696 | } | 2705 | } |
2697 | 2706 | ||
2707 | /* disable all cpu buffers */ | ||
2708 | for_each_tracing_cpu(cpu) { | ||
2709 | if (global_trace.data[cpu]) | ||
2710 | atomic_inc(&global_trace.data[cpu]->disabled); | ||
2711 | if (max_tr.data[cpu]) | ||
2712 | atomic_inc(&max_tr.data[cpu]->disabled); | ||
2713 | } | ||
2714 | |||
2698 | if (val != global_trace.entries) { | 2715 | if (val != global_trace.entries) { |
2699 | ret = ring_buffer_resize(global_trace.buffer, val); | 2716 | ret = ring_buffer_resize(global_trace.buffer, val); |
2700 | if (ret < 0) { | 2717 | if (ret < 0) { |
@@ -2726,6 +2743,13 @@ tracing_entries_write(struct file *filp, const char __user *ubuf, | |||
2726 | if (tracing_disabled) | 2743 | if (tracing_disabled) |
2727 | cnt = -ENOMEM; | 2744 | cnt = -ENOMEM; |
2728 | out: | 2745 | out: |
2746 | for_each_tracing_cpu(cpu) { | ||
2747 | if (global_trace.data[cpu]) | ||
2748 | atomic_dec(&global_trace.data[cpu]->disabled); | ||
2749 | if (max_tr.data[cpu]) | ||
2750 | atomic_dec(&max_tr.data[cpu]->disabled); | ||
2751 | } | ||
2752 | |||
2729 | max_tr.entries = global_trace.entries; | 2753 | max_tr.entries = global_trace.entries; |
2730 | mutex_unlock(&trace_types_lock); | 2754 | mutex_unlock(&trace_types_lock); |
2731 | 2755 | ||
@@ -3097,7 +3121,7 @@ void ftrace_dump(void) | |||
3097 | dump_ran = 1; | 3121 | dump_ran = 1; |
3098 | 3122 | ||
3099 | /* No turning back! */ | 3123 | /* No turning back! */ |
3100 | ftrace_kill_atomic(); | 3124 | ftrace_kill(); |
3101 | 3125 | ||
3102 | for_each_tracing_cpu(cpu) { | 3126 | for_each_tracing_cpu(cpu) { |
3103 | atomic_inc(&global_trace.data[cpu]->disabled); | 3127 | atomic_inc(&global_trace.data[cpu]->disabled); |