diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/Makefile | 1 | ||||
-rw-r--r-- | kernel/trace/events.c | 1 | ||||
-rw-r--r-- | kernel/trace/trace.c | 111 | ||||
-rw-r--r-- | kernel/trace/trace.h | 17 | ||||
-rw-r--r-- | kernel/trace/trace_event_profile.c | 31 | ||||
-rw-r--r-- | kernel/trace/trace_event_types.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 45 | ||||
-rw-r--r-- | kernel/trace/trace_events_stage_3.h | 59 | ||||
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 219 | ||||
-rw-r--r-- | kernel/trace/trace_mmiotrace.c | 2 | ||||
-rw-r--r-- | kernel/trace/trace_output.c | 37 | ||||
-rw-r--r-- | kernel/trace/trace_output.h | 5 | ||||
-rw-r--r-- | kernel/trace/trace_printk.c | 8 | ||||
-rw-r--r-- | kernel/trace/trace_selftest.c | 38 |
14 files changed, 407 insertions, 169 deletions
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index c3feea01c3e0..0e45c206c2f9 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile | |||
@@ -44,5 +44,6 @@ obj-$(CONFIG_EVENT_TRACER) += trace_events.o | |||
44 | obj-$(CONFIG_EVENT_TRACER) += events.o | 44 | obj-$(CONFIG_EVENT_TRACER) += events.o |
45 | obj-$(CONFIG_EVENT_TRACER) += trace_export.o | 45 | obj-$(CONFIG_EVENT_TRACER) += trace_export.o |
46 | obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o | 46 | obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o |
47 | obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o | ||
47 | 48 | ||
48 | libftrace-y := ftrace.o | 49 | libftrace-y := ftrace.o |
diff --git a/kernel/trace/events.c b/kernel/trace/events.c index 9fc918da404f..246f2aa6dc46 100644 --- a/kernel/trace/events.c +++ b/kernel/trace/events.c | |||
@@ -12,4 +12,3 @@ | |||
12 | #include "trace_events_stage_2.h" | 12 | #include "trace_events_stage_2.h" |
13 | #include "trace_events_stage_3.h" | 13 | #include "trace_events_stage_3.h" |
14 | 14 | ||
15 | #include <trace/trace_event_types.h> | ||
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index c95b7292be70..e6fac0ffe6f0 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -1201,7 +1201,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace) | |||
1201 | * trace_vbprintk - write binary msg to tracing buffer | 1201 | * trace_vbprintk - write binary msg to tracing buffer |
1202 | * | 1202 | * |
1203 | */ | 1203 | */ |
1204 | int trace_vbprintk(unsigned long ip, int depth, const char *fmt, va_list args) | 1204 | int trace_vbprintk(unsigned long ip, const char *fmt, va_list args) |
1205 | { | 1205 | { |
1206 | static raw_spinlock_t trace_buf_lock = | 1206 | static raw_spinlock_t trace_buf_lock = |
1207 | (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; | 1207 | (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; |
@@ -1243,7 +1243,6 @@ int trace_vbprintk(unsigned long ip, int depth, const char *fmt, va_list args) | |||
1243 | goto out_unlock; | 1243 | goto out_unlock; |
1244 | entry = ring_buffer_event_data(event); | 1244 | entry = ring_buffer_event_data(event); |
1245 | entry->ip = ip; | 1245 | entry->ip = ip; |
1246 | entry->depth = depth; | ||
1247 | entry->fmt = fmt; | 1246 | entry->fmt = fmt; |
1248 | 1247 | ||
1249 | memcpy(entry->buf, trace_buf, sizeof(u32) * len); | 1248 | memcpy(entry->buf, trace_buf, sizeof(u32) * len); |
@@ -1261,7 +1260,7 @@ out: | |||
1261 | } | 1260 | } |
1262 | EXPORT_SYMBOL_GPL(trace_vbprintk); | 1261 | EXPORT_SYMBOL_GPL(trace_vbprintk); |
1263 | 1262 | ||
1264 | int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args) | 1263 | int trace_vprintk(unsigned long ip, const char *fmt, va_list args) |
1265 | { | 1264 | { |
1266 | static raw_spinlock_t trace_buf_lock = __RAW_SPIN_LOCK_UNLOCKED; | 1265 | static raw_spinlock_t trace_buf_lock = __RAW_SPIN_LOCK_UNLOCKED; |
1267 | static char trace_buf[TRACE_BUF_SIZE]; | 1266 | static char trace_buf[TRACE_BUF_SIZE]; |
@@ -1298,7 +1297,6 @@ int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args) | |||
1298 | goto out_unlock; | 1297 | goto out_unlock; |
1299 | entry = ring_buffer_event_data(event); | 1298 | entry = ring_buffer_event_data(event); |
1300 | entry->ip = ip; | 1299 | entry->ip = ip; |
1301 | entry->depth = depth; | ||
1302 | 1300 | ||
1303 | memcpy(&entry->buf, trace_buf, len); | 1301 | memcpy(&entry->buf, trace_buf, len); |
1304 | entry->buf[len] = 0; | 1302 | entry->buf[len] = 0; |
@@ -1701,38 +1699,6 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter) | |||
1701 | return TRACE_TYPE_HANDLED; | 1699 | return TRACE_TYPE_HANDLED; |
1702 | } | 1700 | } |
1703 | 1701 | ||
1704 | static enum print_line_t print_bprintk_msg_only(struct trace_iterator *iter) | ||
1705 | { | ||
1706 | struct trace_seq *s = &iter->seq; | ||
1707 | struct trace_entry *entry = iter->ent; | ||
1708 | struct bprint_entry *field; | ||
1709 | int ret; | ||
1710 | |||
1711 | trace_assign_type(field, entry); | ||
1712 | |||
1713 | ret = trace_seq_bprintf(s, field->fmt, field->buf); | ||
1714 | if (!ret) | ||
1715 | return TRACE_TYPE_PARTIAL_LINE; | ||
1716 | |||
1717 | return TRACE_TYPE_HANDLED; | ||
1718 | } | ||
1719 | |||
1720 | static enum print_line_t print_printk_msg_only(struct trace_iterator *iter) | ||
1721 | { | ||
1722 | struct trace_seq *s = &iter->seq; | ||
1723 | struct trace_entry *entry = iter->ent; | ||
1724 | struct print_entry *field; | ||
1725 | int ret; | ||
1726 | |||
1727 | trace_assign_type(field, entry); | ||
1728 | |||
1729 | ret = trace_seq_printf(s, "%s", field->buf); | ||
1730 | if (!ret) | ||
1731 | return TRACE_TYPE_PARTIAL_LINE; | ||
1732 | |||
1733 | return TRACE_TYPE_HANDLED; | ||
1734 | } | ||
1735 | |||
1736 | static enum print_line_t print_bin_fmt(struct trace_iterator *iter) | 1702 | static enum print_line_t print_bin_fmt(struct trace_iterator *iter) |
1737 | { | 1703 | { |
1738 | struct trace_seq *s = &iter->seq; | 1704 | struct trace_seq *s = &iter->seq; |
@@ -1794,12 +1760,12 @@ static enum print_line_t print_trace_line(struct trace_iterator *iter) | |||
1794 | if (iter->ent->type == TRACE_BPRINT && | 1760 | if (iter->ent->type == TRACE_BPRINT && |
1795 | trace_flags & TRACE_ITER_PRINTK && | 1761 | trace_flags & TRACE_ITER_PRINTK && |
1796 | trace_flags & TRACE_ITER_PRINTK_MSGONLY) | 1762 | trace_flags & TRACE_ITER_PRINTK_MSGONLY) |
1797 | return print_bprintk_msg_only(iter); | 1763 | return trace_print_bprintk_msg_only(iter); |
1798 | 1764 | ||
1799 | if (iter->ent->type == TRACE_PRINT && | 1765 | if (iter->ent->type == TRACE_PRINT && |
1800 | trace_flags & TRACE_ITER_PRINTK && | 1766 | trace_flags & TRACE_ITER_PRINTK && |
1801 | trace_flags & TRACE_ITER_PRINTK_MSGONLY) | 1767 | trace_flags & TRACE_ITER_PRINTK_MSGONLY) |
1802 | return print_printk_msg_only(iter); | 1768 | return trace_print_printk_msg_only(iter); |
1803 | 1769 | ||
1804 | if (trace_flags & TRACE_ITER_BIN) | 1770 | if (trace_flags & TRACE_ITER_BIN) |
1805 | return print_bin_fmt(iter); | 1771 | return print_bin_fmt(iter); |
@@ -1948,9 +1914,14 @@ int tracing_open_generic(struct inode *inode, struct file *filp) | |||
1948 | static int tracing_release(struct inode *inode, struct file *file) | 1914 | static int tracing_release(struct inode *inode, struct file *file) |
1949 | { | 1915 | { |
1950 | struct seq_file *m = (struct seq_file *)file->private_data; | 1916 | struct seq_file *m = (struct seq_file *)file->private_data; |
1951 | struct trace_iterator *iter = m->private; | 1917 | struct trace_iterator *iter; |
1952 | int cpu; | 1918 | int cpu; |
1953 | 1919 | ||
1920 | if (!(file->f_mode & FMODE_READ)) | ||
1921 | return 0; | ||
1922 | |||
1923 | iter = m->private; | ||
1924 | |||
1954 | mutex_lock(&trace_types_lock); | 1925 | mutex_lock(&trace_types_lock); |
1955 | for_each_tracing_cpu(cpu) { | 1926 | for_each_tracing_cpu(cpu) { |
1956 | if (iter->buffer_iter[cpu]) | 1927 | if (iter->buffer_iter[cpu]) |
@@ -1976,12 +1947,24 @@ static int tracing_open(struct inode *inode, struct file *file) | |||
1976 | struct trace_iterator *iter; | 1947 | struct trace_iterator *iter; |
1977 | int ret = 0; | 1948 | int ret = 0; |
1978 | 1949 | ||
1979 | iter = __tracing_open(inode, file); | 1950 | /* If this file was open for write, then erase contents */ |
1980 | if (IS_ERR(iter)) | 1951 | if ((file->f_mode & FMODE_WRITE) && |
1981 | ret = PTR_ERR(iter); | 1952 | !(file->f_flags & O_APPEND)) { |
1982 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) | 1953 | long cpu = (long) inode->i_private; |
1983 | iter->iter_flags |= TRACE_FILE_LAT_FMT; | 1954 | |
1955 | if (cpu == TRACE_PIPE_ALL_CPU) | ||
1956 | tracing_reset_online_cpus(&global_trace); | ||
1957 | else | ||
1958 | tracing_reset(&global_trace, cpu); | ||
1959 | } | ||
1984 | 1960 | ||
1961 | if (file->f_mode & FMODE_READ) { | ||
1962 | iter = __tracing_open(inode, file); | ||
1963 | if (IS_ERR(iter)) | ||
1964 | ret = PTR_ERR(iter); | ||
1965 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) | ||
1966 | iter->iter_flags |= TRACE_FILE_LAT_FMT; | ||
1967 | } | ||
1985 | return ret; | 1968 | return ret; |
1986 | } | 1969 | } |
1987 | 1970 | ||
@@ -2056,9 +2039,17 @@ static int show_traces_open(struct inode *inode, struct file *file) | |||
2056 | return ret; | 2039 | return ret; |
2057 | } | 2040 | } |
2058 | 2041 | ||
2042 | static ssize_t | ||
2043 | tracing_write_stub(struct file *filp, const char __user *ubuf, | ||
2044 | size_t count, loff_t *ppos) | ||
2045 | { | ||
2046 | return count; | ||
2047 | } | ||
2048 | |||
2059 | static const struct file_operations tracing_fops = { | 2049 | static const struct file_operations tracing_fops = { |
2060 | .open = tracing_open, | 2050 | .open = tracing_open, |
2061 | .read = seq_read, | 2051 | .read = seq_read, |
2052 | .write = tracing_write_stub, | ||
2062 | .llseek = seq_lseek, | 2053 | .llseek = seq_lseek, |
2063 | .release = tracing_release, | 2054 | .release = tracing_release, |
2064 | }; | 2055 | }; |
@@ -3154,7 +3145,7 @@ static int mark_printk(const char *fmt, ...) | |||
3154 | int ret; | 3145 | int ret; |
3155 | va_list args; | 3146 | va_list args; |
3156 | va_start(args, fmt); | 3147 | va_start(args, fmt); |
3157 | ret = trace_vprintk(0, -1, fmt, args); | 3148 | ret = trace_vprintk(0, fmt, args); |
3158 | va_end(args); | 3149 | va_end(args); |
3159 | return ret; | 3150 | return ret; |
3160 | } | 3151 | } |
@@ -3583,7 +3574,7 @@ static void tracing_init_debugfs_percpu(long cpu) | |||
3583 | pr_warning("Could not create debugfs 'trace_pipe' entry\n"); | 3574 | pr_warning("Could not create debugfs 'trace_pipe' entry\n"); |
3584 | 3575 | ||
3585 | /* per cpu trace */ | 3576 | /* per cpu trace */ |
3586 | entry = debugfs_create_file("trace", 0444, d_cpu, | 3577 | entry = debugfs_create_file("trace", 0644, d_cpu, |
3587 | (void *) cpu, &tracing_fops); | 3578 | (void *) cpu, &tracing_fops); |
3588 | if (!entry) | 3579 | if (!entry) |
3589 | pr_warning("Could not create debugfs 'trace' entry\n"); | 3580 | pr_warning("Could not create debugfs 'trace' entry\n"); |
@@ -3897,7 +3888,7 @@ static __init int tracer_init_debugfs(void) | |||
3897 | if (!entry) | 3888 | if (!entry) |
3898 | pr_warning("Could not create debugfs 'tracing_cpumask' entry\n"); | 3889 | pr_warning("Could not create debugfs 'tracing_cpumask' entry\n"); |
3899 | 3890 | ||
3900 | entry = debugfs_create_file("trace", 0444, d_tracer, | 3891 | entry = debugfs_create_file("trace", 0644, d_tracer, |
3901 | (void *) TRACE_PIPE_ALL_CPU, &tracing_fops); | 3892 | (void *) TRACE_PIPE_ALL_CPU, &tracing_fops); |
3902 | if (!entry) | 3893 | if (!entry) |
3903 | pr_warning("Could not create debugfs 'trace' entry\n"); | 3894 | pr_warning("Could not create debugfs 'trace' entry\n"); |
@@ -4027,11 +4018,12 @@ trace_printk_seq(struct trace_seq *s) | |||
4027 | trace_seq_init(s); | 4018 | trace_seq_init(s); |
4028 | } | 4019 | } |
4029 | 4020 | ||
4030 | void ftrace_dump(void) | 4021 | static void __ftrace_dump(bool disable_tracing) |
4031 | { | 4022 | { |
4032 | static DEFINE_SPINLOCK(ftrace_dump_lock); | 4023 | static DEFINE_SPINLOCK(ftrace_dump_lock); |
4033 | /* use static because iter can be a bit big for the stack */ | 4024 | /* use static because iter can be a bit big for the stack */ |
4034 | static struct trace_iterator iter; | 4025 | static struct trace_iterator iter; |
4026 | unsigned int old_userobj; | ||
4035 | static int dump_ran; | 4027 | static int dump_ran; |
4036 | unsigned long flags; | 4028 | unsigned long flags; |
4037 | int cnt = 0, cpu; | 4029 | int cnt = 0, cpu; |
@@ -4043,14 +4035,17 @@ void ftrace_dump(void) | |||
4043 | 4035 | ||
4044 | dump_ran = 1; | 4036 | dump_ran = 1; |
4045 | 4037 | ||
4046 | /* No turning back! */ | ||
4047 | tracing_off(); | 4038 | tracing_off(); |
4048 | ftrace_kill(); | 4039 | |
4040 | if (disable_tracing) | ||
4041 | ftrace_kill(); | ||
4049 | 4042 | ||
4050 | for_each_tracing_cpu(cpu) { | 4043 | for_each_tracing_cpu(cpu) { |
4051 | atomic_inc(&global_trace.data[cpu]->disabled); | 4044 | atomic_inc(&global_trace.data[cpu]->disabled); |
4052 | } | 4045 | } |
4053 | 4046 | ||
4047 | old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ; | ||
4048 | |||
4054 | /* don't look at user memory in panic mode */ | 4049 | /* don't look at user memory in panic mode */ |
4055 | trace_flags &= ~TRACE_ITER_SYM_USEROBJ; | 4050 | trace_flags &= ~TRACE_ITER_SYM_USEROBJ; |
4056 | 4051 | ||
@@ -4095,10 +4090,26 @@ void ftrace_dump(void) | |||
4095 | else | 4090 | else |
4096 | printk(KERN_TRACE "---------------------------------\n"); | 4091 | printk(KERN_TRACE "---------------------------------\n"); |
4097 | 4092 | ||
4093 | /* Re-enable tracing if requested */ | ||
4094 | if (!disable_tracing) { | ||
4095 | trace_flags |= old_userobj; | ||
4096 | |||
4097 | for_each_tracing_cpu(cpu) { | ||
4098 | atomic_dec(&global_trace.data[cpu]->disabled); | ||
4099 | } | ||
4100 | tracing_on(); | ||
4101 | } | ||
4102 | |||
4098 | out: | 4103 | out: |
4099 | spin_unlock_irqrestore(&ftrace_dump_lock, flags); | 4104 | spin_unlock_irqrestore(&ftrace_dump_lock, flags); |
4100 | } | 4105 | } |
4101 | 4106 | ||
4107 | /* By default: disable tracing after the dump */ | ||
4108 | void ftrace_dump(void) | ||
4109 | { | ||
4110 | __ftrace_dump(true); | ||
4111 | } | ||
4112 | |||
4102 | __init static int tracer_alloc_buffers(void) | 4113 | __init static int tracer_alloc_buffers(void) |
4103 | { | 4114 | { |
4104 | struct trace_array_cpu *data; | 4115 | struct trace_array_cpu *data; |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 38276d1638e3..7cfb741be200 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -123,7 +123,6 @@ struct userstack_entry { | |||
123 | struct bprint_entry { | 123 | struct bprint_entry { |
124 | struct trace_entry ent; | 124 | struct trace_entry ent; |
125 | unsigned long ip; | 125 | unsigned long ip; |
126 | int depth; | ||
127 | const char *fmt; | 126 | const char *fmt; |
128 | u32 buf[]; | 127 | u32 buf[]; |
129 | }; | 128 | }; |
@@ -131,7 +130,6 @@ struct bprint_entry { | |||
131 | struct print_entry { | 130 | struct print_entry { |
132 | struct trace_entry ent; | 131 | struct trace_entry ent; |
133 | unsigned long ip; | 132 | unsigned long ip; |
134 | int depth; | ||
135 | char buf[]; | 133 | char buf[]; |
136 | }; | 134 | }; |
137 | 135 | ||
@@ -598,9 +596,9 @@ extern int trace_selftest_startup_branch(struct tracer *trace, | |||
598 | extern void *head_page(struct trace_array_cpu *data); | 596 | extern void *head_page(struct trace_array_cpu *data); |
599 | extern long ns2usecs(cycle_t nsec); | 597 | extern long ns2usecs(cycle_t nsec); |
600 | extern int | 598 | extern int |
601 | trace_vbprintk(unsigned long ip, int depth, const char *fmt, va_list args); | 599 | trace_vbprintk(unsigned long ip, const char *fmt, va_list args); |
602 | extern int | 600 | extern int |
603 | trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args); | 601 | trace_vprintk(unsigned long ip, const char *fmt, va_list args); |
604 | 602 | ||
605 | extern unsigned long trace_flags; | 603 | extern unsigned long trace_flags; |
606 | 604 | ||
@@ -787,12 +785,23 @@ struct ftrace_event_call { | |||
787 | int id; | 785 | int id; |
788 | int (*raw_init)(void); | 786 | int (*raw_init)(void); |
789 | int (*show_format)(struct trace_seq *s); | 787 | int (*show_format)(struct trace_seq *s); |
788 | |||
789 | #ifdef CONFIG_EVENT_PROFILE | ||
790 | atomic_t profile_count; | ||
791 | int (*profile_enable)(struct ftrace_event_call *); | ||
792 | void (*profile_disable)(struct ftrace_event_call *); | ||
793 | #endif | ||
790 | }; | 794 | }; |
791 | 795 | ||
792 | void event_trace_printk(unsigned long ip, const char *fmt, ...); | 796 | void event_trace_printk(unsigned long ip, const char *fmt, ...); |
793 | extern struct ftrace_event_call __start_ftrace_events[]; | 797 | extern struct ftrace_event_call __start_ftrace_events[]; |
794 | extern struct ftrace_event_call __stop_ftrace_events[]; | 798 | extern struct ftrace_event_call __stop_ftrace_events[]; |
795 | 799 | ||
800 | #define for_each_event(event) \ | ||
801 | for (event = __start_ftrace_events; \ | ||
802 | (unsigned long)event < (unsigned long)__stop_ftrace_events; \ | ||
803 | event++) | ||
804 | |||
796 | extern const char *__start___trace_bprintk_fmt[]; | 805 | extern const char *__start___trace_bprintk_fmt[]; |
797 | extern const char *__stop___trace_bprintk_fmt[]; | 806 | extern const char *__stop___trace_bprintk_fmt[]; |
798 | 807 | ||
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c new file mode 100644 index 000000000000..22cba9970776 --- /dev/null +++ b/kernel/trace/trace_event_profile.c | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * trace event based perf counter profiling | ||
3 | * | ||
4 | * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include "trace.h" | ||
9 | |||
10 | int ftrace_profile_enable(int event_id) | ||
11 | { | ||
12 | struct ftrace_event_call *event; | ||
13 | |||
14 | for_each_event(event) { | ||
15 | if (event->id == event_id) | ||
16 | return event->profile_enable(event); | ||
17 | } | ||
18 | |||
19 | return -EINVAL; | ||
20 | } | ||
21 | |||
22 | void ftrace_profile_disable(int event_id) | ||
23 | { | ||
24 | struct ftrace_event_call *event; | ||
25 | |||
26 | for_each_event(event) { | ||
27 | if (event->id == event_id) | ||
28 | return event->profile_disable(event); | ||
29 | } | ||
30 | } | ||
31 | |||
diff --git a/kernel/trace/trace_event_types.h b/kernel/trace/trace_event_types.h index 019915063fe6..fd78bee71dd7 100644 --- a/kernel/trace/trace_event_types.h +++ b/kernel/trace/trace_event_types.h | |||
@@ -105,7 +105,6 @@ TRACE_EVENT_FORMAT(user_stack, TRACE_USER_STACK, userstack_entry, ignore, | |||
105 | TRACE_EVENT_FORMAT(bprint, TRACE_BPRINT, bprint_entry, ignore, | 105 | TRACE_EVENT_FORMAT(bprint, TRACE_BPRINT, bprint_entry, ignore, |
106 | TRACE_STRUCT( | 106 | TRACE_STRUCT( |
107 | TRACE_FIELD(unsigned long, ip, ip) | 107 | TRACE_FIELD(unsigned long, ip, ip) |
108 | TRACE_FIELD(unsigned int, depth, depth) | ||
109 | TRACE_FIELD(char *, fmt, fmt) | 108 | TRACE_FIELD(char *, fmt, fmt) |
110 | TRACE_FIELD_ZERO_CHAR(buf) | 109 | TRACE_FIELD_ZERO_CHAR(buf) |
111 | ), | 110 | ), |
@@ -115,7 +114,6 @@ TRACE_EVENT_FORMAT(bprint, TRACE_BPRINT, bprint_entry, ignore, | |||
115 | TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore, | 114 | TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore, |
116 | TRACE_STRUCT( | 115 | TRACE_STRUCT( |
117 | TRACE_FIELD(unsigned long, ip, ip) | 116 | TRACE_FIELD(unsigned long, ip, ip) |
118 | TRACE_FIELD(unsigned int, depth, depth) | ||
119 | TRACE_FIELD_ZERO_CHAR(buf) | 117 | TRACE_FIELD_ZERO_CHAR(buf) |
120 | ), | 118 | ), |
121 | TP_RAW_FMT("%08lx (%d) fmt:%p %s") | 119 | TP_RAW_FMT("%08lx (%d) fmt:%p %s") |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index c88227b3b9db..3047b56f6637 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -19,11 +19,6 @@ | |||
19 | 19 | ||
20 | static DEFINE_MUTEX(event_mutex); | 20 | static DEFINE_MUTEX(event_mutex); |
21 | 21 | ||
22 | #define events_for_each(event) \ | ||
23 | for (event = __start_ftrace_events; \ | ||
24 | (unsigned long)event < (unsigned long)__stop_ftrace_events; \ | ||
25 | event++) | ||
26 | |||
27 | static void ftrace_clear_events(void) | 22 | static void ftrace_clear_events(void) |
28 | { | 23 | { |
29 | struct ftrace_event_call *call = (void *)__start_ftrace_events; | 24 | struct ftrace_event_call *call = (void *)__start_ftrace_events; |
@@ -90,7 +85,7 @@ static int ftrace_set_clr_event(char *buf, int set) | |||
90 | } | 85 | } |
91 | 86 | ||
92 | mutex_lock(&event_mutex); | 87 | mutex_lock(&event_mutex); |
93 | events_for_each(call) { | 88 | for_each_event(call) { |
94 | 89 | ||
95 | if (!call->name || !call->regfunc) | 90 | if (!call->name || !call->regfunc) |
96 | continue; | 91 | continue; |
@@ -412,6 +407,29 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
412 | return r; | 407 | return r; |
413 | } | 408 | } |
414 | 409 | ||
410 | static ssize_t | ||
411 | event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) | ||
412 | { | ||
413 | struct ftrace_event_call *call = filp->private_data; | ||
414 | struct trace_seq *s; | ||
415 | int r; | ||
416 | |||
417 | if (*ppos) | ||
418 | return 0; | ||
419 | |||
420 | s = kmalloc(sizeof(*s), GFP_KERNEL); | ||
421 | if (!s) | ||
422 | return -ENOMEM; | ||
423 | |||
424 | trace_seq_init(s); | ||
425 | trace_seq_printf(s, "%d\n", call->id); | ||
426 | |||
427 | r = simple_read_from_buffer(ubuf, cnt, ppos, | ||
428 | s->buffer, s->len); | ||
429 | kfree(s); | ||
430 | return r; | ||
431 | } | ||
432 | |||
415 | static const struct seq_operations show_event_seq_ops = { | 433 | static const struct seq_operations show_event_seq_ops = { |
416 | .start = t_start, | 434 | .start = t_start, |
417 | .next = t_next, | 435 | .next = t_next, |
@@ -452,6 +470,11 @@ static const struct file_operations ftrace_event_format_fops = { | |||
452 | .read = event_format_read, | 470 | .read = event_format_read, |
453 | }; | 471 | }; |
454 | 472 | ||
473 | static const struct file_operations ftrace_event_id_fops = { | ||
474 | .open = tracing_open_generic, | ||
475 | .read = event_id_read, | ||
476 | }; | ||
477 | |||
455 | static struct dentry *event_trace_events_dir(void) | 478 | static struct dentry *event_trace_events_dir(void) |
456 | { | 479 | { |
457 | static struct dentry *d_tracer; | 480 | static struct dentry *d_tracer; |
@@ -550,6 +573,14 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | |||
550 | "'%s/enable' entry\n", call->name); | 573 | "'%s/enable' entry\n", call->name); |
551 | } | 574 | } |
552 | 575 | ||
576 | if (call->id) { | ||
577 | entry = debugfs_create_file("id", 0444, call->dir, call, | ||
578 | &ftrace_event_id_fops); | ||
579 | if (!entry) | ||
580 | pr_warning("Could not create debugfs '%s/id' entry\n", | ||
581 | call->name); | ||
582 | } | ||
583 | |||
553 | /* A trace may not want to export its format */ | 584 | /* A trace may not want to export its format */ |
554 | if (!call->show_format) | 585 | if (!call->show_format) |
555 | return 0; | 586 | return 0; |
@@ -592,7 +623,7 @@ static __init int event_trace_init(void) | |||
592 | if (!d_events) | 623 | if (!d_events) |
593 | return 0; | 624 | return 0; |
594 | 625 | ||
595 | events_for_each(call) { | 626 | for_each_event(call) { |
596 | /* The linker may leave blanks */ | 627 | /* The linker may leave blanks */ |
597 | if (!call->name) | 628 | if (!call->name) |
598 | continue; | 629 | continue; |
diff --git a/kernel/trace/trace_events_stage_3.h b/kernel/trace/trace_events_stage_3.h index ae2e323df0c7..6b3261ca988c 100644 --- a/kernel/trace/trace_events_stage_3.h +++ b/kernel/trace/trace_events_stage_3.h | |||
@@ -109,6 +109,40 @@ | |||
109 | #undef TP_FMT | 109 | #undef TP_FMT |
110 | #define TP_FMT(fmt, args...) fmt "\n", ##args | 110 | #define TP_FMT(fmt, args...) fmt "\n", ##args |
111 | 111 | ||
112 | #ifdef CONFIG_EVENT_PROFILE | ||
113 | #define _TRACE_PROFILE(call, proto, args) \ | ||
114 | static void ftrace_profile_##call(proto) \ | ||
115 | { \ | ||
116 | extern void perf_tpcounter_event(int); \ | ||
117 | perf_tpcounter_event(event_##call.id); \ | ||
118 | } \ | ||
119 | \ | ||
120 | static int ftrace_profile_enable_##call(struct ftrace_event_call *call) \ | ||
121 | { \ | ||
122 | int ret = 0; \ | ||
123 | \ | ||
124 | if (!atomic_inc_return(&call->profile_count)) \ | ||
125 | ret = register_trace_##call(ftrace_profile_##call); \ | ||
126 | \ | ||
127 | return ret; \ | ||
128 | } \ | ||
129 | \ | ||
130 | static void ftrace_profile_disable_##call(struct ftrace_event_call *call) \ | ||
131 | { \ | ||
132 | if (atomic_add_negative(-1, &call->profile_count)) \ | ||
133 | unregister_trace_##call(ftrace_profile_##call); \ | ||
134 | } | ||
135 | |||
136 | #define _TRACE_PROFILE_INIT(call) \ | ||
137 | .profile_count = ATOMIC_INIT(-1), \ | ||
138 | .profile_enable = ftrace_profile_enable_##call, \ | ||
139 | .profile_disable = ftrace_profile_disable_##call, | ||
140 | |||
141 | #else | ||
142 | #define _TRACE_PROFILE(call, proto, args) | ||
143 | #define _TRACE_PROFILE_INIT(call) | ||
144 | #endif | ||
145 | |||
112 | #define _TRACE_FORMAT(call, proto, args, fmt) \ | 146 | #define _TRACE_FORMAT(call, proto, args, fmt) \ |
113 | static void ftrace_event_##call(proto) \ | 147 | static void ftrace_event_##call(proto) \ |
114 | { \ | 148 | { \ |
@@ -130,18 +164,33 @@ static void ftrace_unreg_event_##call(void) \ | |||
130 | { \ | 164 | { \ |
131 | unregister_trace_##call(ftrace_event_##call); \ | 165 | unregister_trace_##call(ftrace_event_##call); \ |
132 | } \ | 166 | } \ |
133 | 167 | \ | |
168 | static struct ftrace_event_call event_##call; \ | ||
169 | \ | ||
170 | static int ftrace_init_event_##call(void) \ | ||
171 | { \ | ||
172 | int id; \ | ||
173 | \ | ||
174 | id = register_ftrace_event(NULL); \ | ||
175 | if (!id) \ | ||
176 | return -ENODEV; \ | ||
177 | event_##call.id = id; \ | ||
178 | return 0; \ | ||
179 | } | ||
134 | 180 | ||
135 | #undef TRACE_FORMAT | 181 | #undef TRACE_FORMAT |
136 | #define TRACE_FORMAT(call, proto, args, fmt) \ | 182 | #define TRACE_FORMAT(call, proto, args, fmt) \ |
137 | _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ | 183 | _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ |
184 | _TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ | ||
138 | static struct ftrace_event_call __used \ | 185 | static struct ftrace_event_call __used \ |
139 | __attribute__((__aligned__(4))) \ | 186 | __attribute__((__aligned__(4))) \ |
140 | __attribute__((section("_ftrace_events"))) event_##call = { \ | 187 | __attribute__((section("_ftrace_events"))) event_##call = { \ |
141 | .name = #call, \ | 188 | .name = #call, \ |
142 | .system = __stringify(TRACE_SYSTEM), \ | 189 | .system = __stringify(TRACE_SYSTEM), \ |
190 | .raw_init = ftrace_init_event_##call, \ | ||
143 | .regfunc = ftrace_reg_event_##call, \ | 191 | .regfunc = ftrace_reg_event_##call, \ |
144 | .unregfunc = ftrace_unreg_event_##call, \ | 192 | .unregfunc = ftrace_unreg_event_##call, \ |
193 | _TRACE_PROFILE_INIT(call) \ | ||
145 | } | 194 | } |
146 | 195 | ||
147 | #undef __entry | 196 | #undef __entry |
@@ -149,6 +198,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
149 | 198 | ||
150 | #undef TRACE_EVENT | 199 | #undef TRACE_EVENT |
151 | #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ | 200 | #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ |
201 | _TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ | ||
152 | \ | 202 | \ |
153 | static struct ftrace_event_call event_##call; \ | 203 | static struct ftrace_event_call event_##call; \ |
154 | \ | 204 | \ |
@@ -214,4 +264,11 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
214 | .regfunc = ftrace_raw_reg_event_##call, \ | 264 | .regfunc = ftrace_raw_reg_event_##call, \ |
215 | .unregfunc = ftrace_raw_unreg_event_##call, \ | 265 | .unregfunc = ftrace_raw_unreg_event_##call, \ |
216 | .show_format = ftrace_format_##call, \ | 266 | .show_format = ftrace_format_##call, \ |
267 | _TRACE_PROFILE_INIT(call) \ | ||
217 | } | 268 | } |
269 | |||
270 | #include <trace/trace_event_types.h> | ||
271 | |||
272 | #undef _TRACE_PROFILE | ||
273 | #undef _TRACE_PROFILE_INIT | ||
274 | |||
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 6004ccac2dd7..e876816fa8e7 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -14,6 +14,11 @@ | |||
14 | #include "trace.h" | 14 | #include "trace.h" |
15 | #include "trace_output.h" | 15 | #include "trace_output.h" |
16 | 16 | ||
17 | struct fgraph_data { | ||
18 | pid_t last_pid; | ||
19 | int depth; | ||
20 | }; | ||
21 | |||
17 | #define TRACE_GRAPH_INDENT 2 | 22 | #define TRACE_GRAPH_INDENT 2 |
18 | 23 | ||
19 | /* Flag options */ | 24 | /* Flag options */ |
@@ -231,16 +236,16 @@ print_graph_proc(struct trace_seq *s, pid_t pid) | |||
231 | 236 | ||
232 | /* If the pid changed since the last trace, output this event */ | 237 | /* If the pid changed since the last trace, output this event */ |
233 | static enum print_line_t | 238 | static enum print_line_t |
234 | verif_pid(struct trace_seq *s, pid_t pid, int cpu, pid_t *last_pids_cpu) | 239 | verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data) |
235 | { | 240 | { |
236 | pid_t prev_pid; | 241 | pid_t prev_pid; |
237 | pid_t *last_pid; | 242 | pid_t *last_pid; |
238 | int ret; | 243 | int ret; |
239 | 244 | ||
240 | if (!last_pids_cpu) | 245 | if (!data) |
241 | return TRACE_TYPE_HANDLED; | 246 | return TRACE_TYPE_HANDLED; |
242 | 247 | ||
243 | last_pid = per_cpu_ptr(last_pids_cpu, cpu); | 248 | last_pid = &(per_cpu_ptr(data, cpu)->last_pid); |
244 | 249 | ||
245 | if (*last_pid == pid) | 250 | if (*last_pid == pid) |
246 | return TRACE_TYPE_HANDLED; | 251 | return TRACE_TYPE_HANDLED; |
@@ -471,6 +476,7 @@ print_graph_entry_leaf(struct trace_iterator *iter, | |||
471 | struct ftrace_graph_ent_entry *entry, | 476 | struct ftrace_graph_ent_entry *entry, |
472 | struct ftrace_graph_ret_entry *ret_entry, struct trace_seq *s) | 477 | struct ftrace_graph_ret_entry *ret_entry, struct trace_seq *s) |
473 | { | 478 | { |
479 | struct fgraph_data *data = iter->private; | ||
474 | struct ftrace_graph_ret *graph_ret; | 480 | struct ftrace_graph_ret *graph_ret; |
475 | struct ftrace_graph_ent *call; | 481 | struct ftrace_graph_ent *call; |
476 | unsigned long long duration; | 482 | unsigned long long duration; |
@@ -481,6 +487,18 @@ print_graph_entry_leaf(struct trace_iterator *iter, | |||
481 | call = &entry->graph_ent; | 487 | call = &entry->graph_ent; |
482 | duration = graph_ret->rettime - graph_ret->calltime; | 488 | duration = graph_ret->rettime - graph_ret->calltime; |
483 | 489 | ||
490 | if (data) { | ||
491 | int cpu = iter->cpu; | ||
492 | int *depth = &(per_cpu_ptr(data, cpu)->depth); | ||
493 | |||
494 | /* | ||
495 | * Comments display at + 1 to depth. Since | ||
496 | * this is a leaf function, keep the comments | ||
497 | * equal to this depth. | ||
498 | */ | ||
499 | *depth = call->depth - 1; | ||
500 | } | ||
501 | |||
484 | /* Overhead */ | 502 | /* Overhead */ |
485 | ret = print_graph_overhead(duration, s); | 503 | ret = print_graph_overhead(duration, s); |
486 | if (!ret) | 504 | if (!ret) |
@@ -512,12 +530,21 @@ print_graph_entry_leaf(struct trace_iterator *iter, | |||
512 | } | 530 | } |
513 | 531 | ||
514 | static enum print_line_t | 532 | static enum print_line_t |
515 | print_graph_entry_nested(struct ftrace_graph_ent_entry *entry, | 533 | print_graph_entry_nested(struct trace_iterator *iter, |
516 | struct trace_seq *s, pid_t pid, int cpu) | 534 | struct ftrace_graph_ent_entry *entry, |
535 | struct trace_seq *s, int cpu) | ||
517 | { | 536 | { |
518 | int i; | ||
519 | int ret; | ||
520 | struct ftrace_graph_ent *call = &entry->graph_ent; | 537 | struct ftrace_graph_ent *call = &entry->graph_ent; |
538 | struct fgraph_data *data = iter->private; | ||
539 | int ret; | ||
540 | int i; | ||
541 | |||
542 | if (data) { | ||
543 | int cpu = iter->cpu; | ||
544 | int *depth = &(per_cpu_ptr(data, cpu)->depth); | ||
545 | |||
546 | *depth = call->depth; | ||
547 | } | ||
521 | 548 | ||
522 | /* No overhead */ | 549 | /* No overhead */ |
523 | ret = print_graph_overhead(-1, s); | 550 | ret = print_graph_overhead(-1, s); |
@@ -554,24 +581,24 @@ print_graph_entry_nested(struct ftrace_graph_ent_entry *entry, | |||
554 | } | 581 | } |
555 | 582 | ||
556 | static enum print_line_t | 583 | static enum print_line_t |
557 | print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, | 584 | print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, |
558 | struct trace_iterator *iter) | 585 | int type, unsigned long addr) |
559 | { | 586 | { |
560 | int ret; | 587 | struct fgraph_data *data = iter->private; |
561 | int cpu = iter->cpu; | ||
562 | pid_t *last_entry = iter->private; | ||
563 | struct trace_entry *ent = iter->ent; | 588 | struct trace_entry *ent = iter->ent; |
564 | struct ftrace_graph_ent *call = &field->graph_ent; | 589 | int cpu = iter->cpu; |
565 | struct ftrace_graph_ret_entry *leaf_ret; | 590 | int ret; |
566 | 591 | ||
567 | /* Pid */ | 592 | /* Pid */ |
568 | if (verif_pid(s, ent->pid, cpu, last_entry) == TRACE_TYPE_PARTIAL_LINE) | 593 | if (verif_pid(s, ent->pid, cpu, data) == TRACE_TYPE_PARTIAL_LINE) |
569 | return TRACE_TYPE_PARTIAL_LINE; | 594 | return TRACE_TYPE_PARTIAL_LINE; |
570 | 595 | ||
571 | /* Interrupt */ | 596 | if (type) { |
572 | ret = print_graph_irq(iter, call->func, TRACE_GRAPH_ENT, cpu, ent->pid); | 597 | /* Interrupt */ |
573 | if (ret == TRACE_TYPE_PARTIAL_LINE) | 598 | ret = print_graph_irq(iter, addr, type, cpu, ent->pid); |
574 | return TRACE_TYPE_PARTIAL_LINE; | 599 | if (ret == TRACE_TYPE_PARTIAL_LINE) |
600 | return TRACE_TYPE_PARTIAL_LINE; | ||
601 | } | ||
575 | 602 | ||
576 | /* Absolute time */ | 603 | /* Absolute time */ |
577 | if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { | 604 | if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { |
@@ -598,11 +625,25 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, | |||
598 | return TRACE_TYPE_PARTIAL_LINE; | 625 | return TRACE_TYPE_PARTIAL_LINE; |
599 | } | 626 | } |
600 | 627 | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static enum print_line_t | ||
632 | print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, | ||
633 | struct trace_iterator *iter) | ||
634 | { | ||
635 | int cpu = iter->cpu; | ||
636 | struct ftrace_graph_ent *call = &field->graph_ent; | ||
637 | struct ftrace_graph_ret_entry *leaf_ret; | ||
638 | |||
639 | if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func)) | ||
640 | return TRACE_TYPE_PARTIAL_LINE; | ||
641 | |||
601 | leaf_ret = get_return_for_leaf(iter, field); | 642 | leaf_ret = get_return_for_leaf(iter, field); |
602 | if (leaf_ret) | 643 | if (leaf_ret) |
603 | return print_graph_entry_leaf(iter, field, leaf_ret, s); | 644 | return print_graph_entry_leaf(iter, field, leaf_ret, s); |
604 | else | 645 | else |
605 | return print_graph_entry_nested(field, s, iter->ent->pid, cpu); | 646 | return print_graph_entry_nested(iter, field, s, cpu); |
606 | 647 | ||
607 | } | 648 | } |
608 | 649 | ||
@@ -610,40 +651,27 @@ static enum print_line_t | |||
610 | print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | 651 | print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, |
611 | struct trace_entry *ent, struct trace_iterator *iter) | 652 | struct trace_entry *ent, struct trace_iterator *iter) |
612 | { | 653 | { |
613 | int i; | ||
614 | int ret; | ||
615 | int cpu = iter->cpu; | ||
616 | pid_t *last_pid = iter->private, pid = ent->pid; | ||
617 | unsigned long long duration = trace->rettime - trace->calltime; | 654 | unsigned long long duration = trace->rettime - trace->calltime; |
655 | struct fgraph_data *data = iter->private; | ||
656 | pid_t pid = ent->pid; | ||
657 | int cpu = iter->cpu; | ||
658 | int ret; | ||
659 | int i; | ||
618 | 660 | ||
619 | /* Pid */ | 661 | if (data) { |
620 | if (verif_pid(s, pid, cpu, last_pid) == TRACE_TYPE_PARTIAL_LINE) | 662 | int cpu = iter->cpu; |
621 | return TRACE_TYPE_PARTIAL_LINE; | 663 | int *depth = &(per_cpu_ptr(data, cpu)->depth); |
622 | |||
623 | /* Absolute time */ | ||
624 | if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { | ||
625 | ret = print_graph_abs_time(iter->ts, s); | ||
626 | if (!ret) | ||
627 | return TRACE_TYPE_PARTIAL_LINE; | ||
628 | } | ||
629 | 664 | ||
630 | /* Cpu */ | 665 | /* |
631 | if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { | 666 | * Comments display at + 1 to depth. This is the |
632 | ret = print_graph_cpu(s, cpu); | 667 | * return from a function, we now want the comments |
633 | if (ret == TRACE_TYPE_PARTIAL_LINE) | 668 | * to display at the same level of the bracket. |
634 | return TRACE_TYPE_PARTIAL_LINE; | 669 | */ |
670 | *depth = trace->depth - 1; | ||
635 | } | 671 | } |
636 | 672 | ||
637 | /* Proc */ | 673 | if (print_graph_prologue(iter, s, 0, 0)) |
638 | if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) { | 674 | return TRACE_TYPE_PARTIAL_LINE; |
639 | ret = print_graph_proc(s, ent->pid); | ||
640 | if (ret == TRACE_TYPE_PARTIAL_LINE) | ||
641 | return TRACE_TYPE_PARTIAL_LINE; | ||
642 | |||
643 | ret = trace_seq_printf(s, " | "); | ||
644 | if (!ret) | ||
645 | return TRACE_TYPE_PARTIAL_LINE; | ||
646 | } | ||
647 | 675 | ||
648 | /* Overhead */ | 676 | /* Overhead */ |
649 | ret = print_graph_overhead(duration, s); | 677 | ret = print_graph_overhead(duration, s); |
@@ -684,42 +712,21 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
684 | } | 712 | } |
685 | 713 | ||
686 | static enum print_line_t | 714 | static enum print_line_t |
687 | print_graph_comment(struct bprint_entry *trace, struct trace_seq *s, | 715 | print_graph_comment(struct trace_seq *s, struct trace_entry *ent, |
688 | struct trace_entry *ent, struct trace_iterator *iter) | 716 | struct trace_iterator *iter) |
689 | { | 717 | { |
690 | int i; | 718 | unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK); |
719 | struct fgraph_data *data = iter->private; | ||
720 | struct trace_event *event; | ||
721 | int depth = 0; | ||
691 | int ret; | 722 | int ret; |
692 | int cpu = iter->cpu; | 723 | int i; |
693 | pid_t *last_pid = iter->private; | ||
694 | |||
695 | /* Pid */ | ||
696 | if (verif_pid(s, ent->pid, cpu, last_pid) == TRACE_TYPE_PARTIAL_LINE) | ||
697 | return TRACE_TYPE_PARTIAL_LINE; | ||
698 | |||
699 | /* Absolute time */ | ||
700 | if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) { | ||
701 | ret = print_graph_abs_time(iter->ts, s); | ||
702 | if (!ret) | ||
703 | return TRACE_TYPE_PARTIAL_LINE; | ||
704 | } | ||
705 | |||
706 | /* Cpu */ | ||
707 | if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { | ||
708 | ret = print_graph_cpu(s, cpu); | ||
709 | if (ret == TRACE_TYPE_PARTIAL_LINE) | ||
710 | return TRACE_TYPE_PARTIAL_LINE; | ||
711 | } | ||
712 | 724 | ||
713 | /* Proc */ | 725 | if (data) |
714 | if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) { | 726 | depth = per_cpu_ptr(data, iter->cpu)->depth; |
715 | ret = print_graph_proc(s, ent->pid); | ||
716 | if (ret == TRACE_TYPE_PARTIAL_LINE) | ||
717 | return TRACE_TYPE_PARTIAL_LINE; | ||
718 | 727 | ||
719 | ret = trace_seq_printf(s, " | "); | 728 | if (print_graph_prologue(iter, s, 0, 0)) |
720 | if (!ret) | 729 | return TRACE_TYPE_PARTIAL_LINE; |
721 | return TRACE_TYPE_PARTIAL_LINE; | ||
722 | } | ||
723 | 730 | ||
724 | /* No overhead */ | 731 | /* No overhead */ |
725 | ret = print_graph_overhead(-1, s); | 732 | ret = print_graph_overhead(-1, s); |
@@ -734,8 +741,8 @@ print_graph_comment(struct bprint_entry *trace, struct trace_seq *s, | |||
734 | } | 741 | } |
735 | 742 | ||
736 | /* Indentation */ | 743 | /* Indentation */ |
737 | if (trace->depth > 0) | 744 | if (depth > 0) |
738 | for (i = 0; i < (trace->depth + 1) * TRACE_GRAPH_INDENT; i++) { | 745 | for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++) { |
739 | ret = trace_seq_printf(s, " "); | 746 | ret = trace_seq_printf(s, " "); |
740 | if (!ret) | 747 | if (!ret) |
741 | return TRACE_TYPE_PARTIAL_LINE; | 748 | return TRACE_TYPE_PARTIAL_LINE; |
@@ -746,9 +753,26 @@ print_graph_comment(struct bprint_entry *trace, struct trace_seq *s, | |||
746 | if (!ret) | 753 | if (!ret) |
747 | return TRACE_TYPE_PARTIAL_LINE; | 754 | return TRACE_TYPE_PARTIAL_LINE; |
748 | 755 | ||
749 | ret = trace_seq_bprintf(s, trace->fmt, trace->buf); | 756 | switch (iter->ent->type) { |
750 | if (!ret) | 757 | case TRACE_BPRINT: |
751 | return TRACE_TYPE_PARTIAL_LINE; | 758 | ret = trace_print_bprintk_msg_only(iter); |
759 | if (ret != TRACE_TYPE_HANDLED) | ||
760 | return ret; | ||
761 | break; | ||
762 | case TRACE_PRINT: | ||
763 | ret = trace_print_printk_msg_only(iter); | ||
764 | if (ret != TRACE_TYPE_HANDLED) | ||
765 | return ret; | ||
766 | break; | ||
767 | default: | ||
768 | event = ftrace_find_event(ent->type); | ||
769 | if (!event) | ||
770 | return TRACE_TYPE_UNHANDLED; | ||
771 | |||
772 | ret = event->trace(iter, sym_flags); | ||
773 | if (ret != TRACE_TYPE_HANDLED) | ||
774 | return ret; | ||
775 | } | ||
752 | 776 | ||
753 | /* Strip ending newline */ | 777 | /* Strip ending newline */ |
754 | if (s->buffer[s->len - 1] == '\n') { | 778 | if (s->buffer[s->len - 1] == '\n') { |
@@ -767,8 +791,8 @@ print_graph_comment(struct bprint_entry *trace, struct trace_seq *s, | |||
767 | enum print_line_t | 791 | enum print_line_t |
768 | print_graph_function(struct trace_iterator *iter) | 792 | print_graph_function(struct trace_iterator *iter) |
769 | { | 793 | { |
770 | struct trace_seq *s = &iter->seq; | ||
771 | struct trace_entry *entry = iter->ent; | 794 | struct trace_entry *entry = iter->ent; |
795 | struct trace_seq *s = &iter->seq; | ||
772 | 796 | ||
773 | switch (entry->type) { | 797 | switch (entry->type) { |
774 | case TRACE_GRAPH_ENT: { | 798 | case TRACE_GRAPH_ENT: { |
@@ -781,14 +805,11 @@ print_graph_function(struct trace_iterator *iter) | |||
781 | trace_assign_type(field, entry); | 805 | trace_assign_type(field, entry); |
782 | return print_graph_return(&field->ret, s, entry, iter); | 806 | return print_graph_return(&field->ret, s, entry, iter); |
783 | } | 807 | } |
784 | case TRACE_BPRINT: { | ||
785 | struct bprint_entry *field; | ||
786 | trace_assign_type(field, entry); | ||
787 | return print_graph_comment(field, s, entry, iter); | ||
788 | } | ||
789 | default: | 808 | default: |
790 | return TRACE_TYPE_UNHANDLED; | 809 | return print_graph_comment(s, entry, iter); |
791 | } | 810 | } |
811 | |||
812 | return TRACE_TYPE_HANDLED; | ||
792 | } | 813 | } |
793 | 814 | ||
794 | static void print_graph_headers(struct seq_file *s) | 815 | static void print_graph_headers(struct seq_file *s) |
@@ -820,19 +841,21 @@ static void print_graph_headers(struct seq_file *s) | |||
820 | 841 | ||
821 | static void graph_trace_open(struct trace_iterator *iter) | 842 | static void graph_trace_open(struct trace_iterator *iter) |
822 | { | 843 | { |
823 | /* pid on the last trace processed */ | 844 | /* pid and depth on the last trace processed */ |
824 | pid_t *last_pid = alloc_percpu(pid_t); | 845 | struct fgraph_data *data = alloc_percpu(struct fgraph_data); |
825 | int cpu; | 846 | int cpu; |
826 | 847 | ||
827 | if (!last_pid) | 848 | if (!data) |
828 | pr_warning("function graph tracer: not enough memory\n"); | 849 | pr_warning("function graph tracer: not enough memory\n"); |
829 | else | 850 | else |
830 | for_each_possible_cpu(cpu) { | 851 | for_each_possible_cpu(cpu) { |
831 | pid_t *pid = per_cpu_ptr(last_pid, cpu); | 852 | pid_t *pid = &(per_cpu_ptr(data, cpu)->last_pid); |
853 | int *depth = &(per_cpu_ptr(data, cpu)->depth); | ||
832 | *pid = -1; | 854 | *pid = -1; |
855 | *depth = 0; | ||
833 | } | 856 | } |
834 | 857 | ||
835 | iter->private = last_pid; | 858 | iter->private = data; |
836 | } | 859 | } |
837 | 860 | ||
838 | static void graph_trace_close(struct trace_iterator *iter) | 861 | static void graph_trace_close(struct trace_iterator *iter) |
diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c index f095916e477f..8e37fcddd8b4 100644 --- a/kernel/trace/trace_mmiotrace.c +++ b/kernel/trace/trace_mmiotrace.c | |||
@@ -359,5 +359,5 @@ void mmio_trace_mapping(struct mmiotrace_map *map) | |||
359 | 359 | ||
360 | int mmio_trace_printk(const char *fmt, va_list args) | 360 | int mmio_trace_printk(const char *fmt, va_list args) |
361 | { | 361 | { |
362 | return trace_vprintk(0, -1, fmt, args); | 362 | return trace_vprintk(0, fmt, args); |
363 | } | 363 | } |
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 6a4c9dea191e..19261fdd2455 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
@@ -19,6 +19,38 @@ static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly; | |||
19 | 19 | ||
20 | static int next_event_type = __TRACE_LAST_TYPE + 1; | 20 | static int next_event_type = __TRACE_LAST_TYPE + 1; |
21 | 21 | ||
22 | enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter) | ||
23 | { | ||
24 | struct trace_seq *s = &iter->seq; | ||
25 | struct trace_entry *entry = iter->ent; | ||
26 | struct bprint_entry *field; | ||
27 | int ret; | ||
28 | |||
29 | trace_assign_type(field, entry); | ||
30 | |||
31 | ret = trace_seq_bprintf(s, field->fmt, field->buf); | ||
32 | if (!ret) | ||
33 | return TRACE_TYPE_PARTIAL_LINE; | ||
34 | |||
35 | return TRACE_TYPE_HANDLED; | ||
36 | } | ||
37 | |||
38 | enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter) | ||
39 | { | ||
40 | struct trace_seq *s = &iter->seq; | ||
41 | struct trace_entry *entry = iter->ent; | ||
42 | struct print_entry *field; | ||
43 | int ret; | ||
44 | |||
45 | trace_assign_type(field, entry); | ||
46 | |||
47 | ret = trace_seq_printf(s, "%s", field->buf); | ||
48 | if (!ret) | ||
49 | return TRACE_TYPE_PARTIAL_LINE; | ||
50 | |||
51 | return TRACE_TYPE_HANDLED; | ||
52 | } | ||
53 | |||
22 | /** | 54 | /** |
23 | * trace_seq_printf - sequence printing of trace information | 55 | * trace_seq_printf - sequence printing of trace information |
24 | * @s: trace sequence descriptor | 56 | * @s: trace sequence descriptor |
@@ -449,6 +481,11 @@ int register_ftrace_event(struct trace_event *event) | |||
449 | 481 | ||
450 | mutex_lock(&trace_event_mutex); | 482 | mutex_lock(&trace_event_mutex); |
451 | 483 | ||
484 | if (!event) { | ||
485 | ret = next_event_type++; | ||
486 | goto out; | ||
487 | } | ||
488 | |||
452 | if (!event->type) | 489 | if (!event->type) |
453 | event->type = next_event_type++; | 490 | event->type = next_event_type++; |
454 | else if (event->type > __TRACE_LAST_TYPE) { | 491 | else if (event->type > __TRACE_LAST_TYPE) { |
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h index 3b90e6ade1aa..35c422fb51a9 100644 --- a/kernel/trace/trace_output.h +++ b/kernel/trace/trace_output.h | |||
@@ -15,6 +15,11 @@ struct trace_event { | |||
15 | trace_print_func binary; | 15 | trace_print_func binary; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | extern enum print_line_t | ||
19 | trace_print_bprintk_msg_only(struct trace_iterator *iter); | ||
20 | extern enum print_line_t | ||
21 | trace_print_printk_msg_only(struct trace_iterator *iter); | ||
22 | |||
18 | extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | 23 | extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) |
19 | __attribute__ ((format (printf, 2, 3))); | 24 | __attribute__ ((format (printf, 2, 3))); |
20 | extern int | 25 | extern int |
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index 486785214e3e..eb81556107fe 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c | |||
@@ -112,7 +112,7 @@ int __trace_bprintk(unsigned long ip, const char *fmt, ...) | |||
112 | return 0; | 112 | return 0; |
113 | 113 | ||
114 | va_start(ap, fmt); | 114 | va_start(ap, fmt); |
115 | ret = trace_vbprintk(ip, task_curr_ret_stack(current), fmt, ap); | 115 | ret = trace_vbprintk(ip, fmt, ap); |
116 | va_end(ap); | 116 | va_end(ap); |
117 | return ret; | 117 | return ret; |
118 | } | 118 | } |
@@ -126,7 +126,7 @@ int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap) | |||
126 | if (!(trace_flags & TRACE_ITER_PRINTK)) | 126 | if (!(trace_flags & TRACE_ITER_PRINTK)) |
127 | return 0; | 127 | return 0; |
128 | 128 | ||
129 | return trace_vbprintk(ip, task_curr_ret_stack(current), fmt, ap); | 129 | return trace_vbprintk(ip, fmt, ap); |
130 | } | 130 | } |
131 | EXPORT_SYMBOL_GPL(__ftrace_vbprintk); | 131 | EXPORT_SYMBOL_GPL(__ftrace_vbprintk); |
132 | 132 | ||
@@ -139,7 +139,7 @@ int __trace_printk(unsigned long ip, const char *fmt, ...) | |||
139 | return 0; | 139 | return 0; |
140 | 140 | ||
141 | va_start(ap, fmt); | 141 | va_start(ap, fmt); |
142 | ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap); | 142 | ret = trace_vprintk(ip, fmt, ap); |
143 | va_end(ap); | 143 | va_end(ap); |
144 | return ret; | 144 | return ret; |
145 | } | 145 | } |
@@ -150,7 +150,7 @@ int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap) | |||
150 | if (!(trace_flags & TRACE_ITER_PRINTK)) | 150 | if (!(trace_flags & TRACE_ITER_PRINTK)) |
151 | return 0; | 151 | return 0; |
152 | 152 | ||
153 | return trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap); | 153 | return trace_vprintk(ip, fmt, ap); |
154 | } | 154 | } |
155 | EXPORT_SYMBOL_GPL(__ftrace_vprintk); | 155 | EXPORT_SYMBOL_GPL(__ftrace_vprintk); |
156 | 156 | ||
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 38856ba78a92..08f4eb2763d1 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
@@ -248,6 +248,28 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) | |||
248 | 248 | ||
249 | 249 | ||
250 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 250 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
251 | |||
252 | /* Maximum number of functions to trace before diagnosing a hang */ | ||
253 | #define GRAPH_MAX_FUNC_TEST 100000000 | ||
254 | |||
255 | static void __ftrace_dump(bool disable_tracing); | ||
256 | static unsigned int graph_hang_thresh; | ||
257 | |||
258 | /* Wrap the real function entry probe to avoid possible hanging */ | ||
259 | static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace) | ||
260 | { | ||
261 | /* This is harmlessly racy, we want to approximately detect a hang */ | ||
262 | if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) { | ||
263 | ftrace_graph_stop(); | ||
264 | printk(KERN_WARNING "BUG: Function graph tracer hang!\n"); | ||
265 | if (ftrace_dump_on_oops) | ||
266 | __ftrace_dump(false); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | return trace_graph_entry(trace); | ||
271 | } | ||
272 | |||
251 | /* | 273 | /* |
252 | * Pretty much the same than for the function tracer from which the selftest | 274 | * Pretty much the same than for the function tracer from which the selftest |
253 | * has been borrowed. | 275 | * has been borrowed. |
@@ -259,15 +281,29 @@ trace_selftest_startup_function_graph(struct tracer *trace, | |||
259 | int ret; | 281 | int ret; |
260 | unsigned long count; | 282 | unsigned long count; |
261 | 283 | ||
262 | ret = tracer_init(trace, tr); | 284 | /* |
285 | * Simulate the init() callback but we attach a watchdog callback | ||
286 | * to detect and recover from possible hangs | ||
287 | */ | ||
288 | tracing_reset_online_cpus(tr); | ||
289 | ret = register_ftrace_graph(&trace_graph_return, | ||
290 | &trace_graph_entry_watchdog); | ||
263 | if (ret) { | 291 | if (ret) { |
264 | warn_failed_init_tracer(trace, ret); | 292 | warn_failed_init_tracer(trace, ret); |
265 | goto out; | 293 | goto out; |
266 | } | 294 | } |
295 | tracing_start_cmdline_record(); | ||
267 | 296 | ||
268 | /* Sleep for a 1/10 of a second */ | 297 | /* Sleep for a 1/10 of a second */ |
269 | msleep(100); | 298 | msleep(100); |
270 | 299 | ||
300 | /* Have we just recovered from a hang? */ | ||
301 | if (graph_hang_thresh > GRAPH_MAX_FUNC_TEST) { | ||
302 | tracing_selftest_disabled = true; | ||
303 | ret = -1; | ||
304 | goto out; | ||
305 | } | ||
306 | |||
271 | tracing_stop(); | 307 | tracing_stop(); |
272 | 308 | ||
273 | /* check the trace buffer */ | 309 | /* check the trace buffer */ |