diff options
-rw-r--r-- | include/linux/ftrace.h | 19 | ||||
-rw-r--r-- | kernel/trace/trace.h | 4 | ||||
-rw-r--r-- | kernel/trace/trace_boot.c | 101 |
3 files changed, 124 insertions, 0 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 5de9903645d5..91954eb6460f 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -5,6 +5,8 @@ | |||
5 | 5 | ||
6 | #include <linux/linkage.h> | 6 | #include <linux/linkage.h> |
7 | #include <linux/fs.h> | 7 | #include <linux/fs.h> |
8 | #include <linux/init.h> | ||
9 | #include <linux/types.h> | ||
8 | 10 | ||
9 | extern int ftrace_enabled; | 11 | extern int ftrace_enabled; |
10 | extern int | 12 | extern int |
@@ -209,4 +211,21 @@ ftrace_init_module(unsigned long *start, unsigned long *end) { } | |||
209 | #endif | 211 | #endif |
210 | 212 | ||
211 | 213 | ||
214 | struct boot_trace { | ||
215 | pid_t caller; | ||
216 | initcall_t func; | ||
217 | int result; | ||
218 | unsigned long long duration; | ||
219 | }; | ||
220 | |||
221 | #ifdef CONFIG_BOOT_TRACER | ||
222 | extern void trace_boot(struct boot_trace *it); | ||
223 | extern void start_boot_trace(void); | ||
224 | #else | ||
225 | static inline void trace_boot(struct boot_trace *it) { } | ||
226 | static inline void start_boot_trace(void) { } | ||
227 | #endif | ||
228 | |||
229 | |||
230 | |||
212 | #endif /* _LINUX_FTRACE_H */ | 231 | #endif /* _LINUX_FTRACE_H */ |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index cb2c3fb7dd54..b28bf8812efc 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
7 | #include <linux/clocksource.h> | 7 | #include <linux/clocksource.h> |
8 | #include <linux/mmiotrace.h> | 8 | #include <linux/mmiotrace.h> |
9 | #include <linux/ftrace.h> | ||
9 | 10 | ||
10 | enum trace_type { | 11 | enum trace_type { |
11 | __TRACE_FIRST_TYPE = 0, | 12 | __TRACE_FIRST_TYPE = 0, |
@@ -19,6 +20,7 @@ enum trace_type { | |||
19 | TRACE_SPECIAL, | 20 | TRACE_SPECIAL, |
20 | TRACE_MMIO_RW, | 21 | TRACE_MMIO_RW, |
21 | TRACE_MMIO_MAP, | 22 | TRACE_MMIO_MAP, |
23 | TRACE_BOOT, | ||
22 | 24 | ||
23 | __TRACE_LAST_TYPE | 25 | __TRACE_LAST_TYPE |
24 | }; | 26 | }; |
@@ -30,6 +32,7 @@ struct ftrace_entry { | |||
30 | unsigned long ip; | 32 | unsigned long ip; |
31 | unsigned long parent_ip; | 33 | unsigned long parent_ip; |
32 | }; | 34 | }; |
35 | extern struct tracer boot_tracer; | ||
33 | 36 | ||
34 | /* | 37 | /* |
35 | * Context switch trace entry - which task (and prio) we switched from/to: | 38 | * Context switch trace entry - which task (and prio) we switched from/to: |
@@ -108,6 +111,7 @@ struct trace_field { | |||
108 | struct print_entry print; | 111 | struct print_entry print; |
109 | struct mmiotrace_rw mmiorw; | 112 | struct mmiotrace_rw mmiorw; |
110 | struct mmiotrace_map mmiomap; | 113 | struct mmiotrace_map mmiomap; |
114 | struct boot_trace initcall; | ||
111 | }; | 115 | }; |
112 | }; | 116 | }; |
113 | 117 | ||
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c new file mode 100644 index 000000000000..c65ef8ffd6b4 --- /dev/null +++ b/kernel/trace/trace_boot.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * ring buffer based initcalls tracer | ||
3 | * | ||
4 | * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/debugfs.h> | ||
10 | #include <linux/ftrace.h> | ||
11 | |||
12 | #include "trace.h" | ||
13 | |||
14 | static struct trace_array *boot_trace; | ||
15 | static int trace_boot_enabled; | ||
16 | |||
17 | |||
18 | /* Should be started after do_pre_smp_initcalls() in init/main.c */ | ||
19 | void start_boot_trace(void) | ||
20 | { | ||
21 | trace_boot_enabled = 1; | ||
22 | } | ||
23 | |||
24 | void stop_boot_trace(struct trace_array *tr) | ||
25 | { | ||
26 | trace_boot_enabled = 0; | ||
27 | } | ||
28 | |||
29 | static void boot_trace_init(struct trace_array *tr) | ||
30 | { | ||
31 | int cpu; | ||
32 | boot_trace = tr; | ||
33 | |||
34 | trace_boot_enabled = 0; | ||
35 | |||
36 | for_each_cpu_mask(cpu, cpu_possible_map) | ||
37 | tracing_reset(tr->data[cpu]); | ||
38 | } | ||
39 | |||
40 | static void boot_trace_ctrl_update(struct trace_array *tr) | ||
41 | { | ||
42 | if (tr->ctrl) | ||
43 | start_boot_trace(); | ||
44 | else | ||
45 | stop_boot_trace(tr); | ||
46 | } | ||
47 | |||
48 | static int initcall_print_line(struct trace_iterator *iter) | ||
49 | { | ||
50 | int ret = 1; | ||
51 | struct trace_entry *entry = iter->ent; | ||
52 | struct boot_trace *it = &entry->field.initcall; | ||
53 | struct trace_seq *s = &iter->seq; | ||
54 | |||
55 | if (iter->ent->type == TRACE_BOOT) | ||
56 | ret = trace_seq_printf(s, "%pF called from %i " | ||
57 | "returned %d after %lld msecs\n", | ||
58 | it->func, it->caller, it->result, | ||
59 | it->duration); | ||
60 | if (ret) | ||
61 | return 1; | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | struct tracer boot_tracer __read_mostly = | ||
66 | { | ||
67 | .name = "initcall", | ||
68 | .init = boot_trace_init, | ||
69 | .reset = stop_boot_trace, | ||
70 | .ctrl_update = boot_trace_ctrl_update, | ||
71 | .print_line = initcall_print_line, | ||
72 | }; | ||
73 | |||
74 | |||
75 | void trace_boot(struct boot_trace *it) | ||
76 | { | ||
77 | struct trace_entry *entry; | ||
78 | struct trace_array_cpu *data; | ||
79 | unsigned long irq_flags; | ||
80 | struct trace_array *tr = boot_trace; | ||
81 | |||
82 | if (!trace_boot_enabled) | ||
83 | return; | ||
84 | |||
85 | preempt_disable(); | ||
86 | data = tr->data[smp_processor_id()]; | ||
87 | |||
88 | raw_local_irq_save(irq_flags); | ||
89 | __raw_spin_lock(&data->lock); | ||
90 | |||
91 | entry = tracing_get_trace_entry(tr, data); | ||
92 | tracing_generic_entry_update(entry, 0); | ||
93 | entry->type = TRACE_BOOT; | ||
94 | entry->field.initcall = *it; | ||
95 | |||
96 | __raw_spin_unlock(&data->lock); | ||
97 | raw_local_irq_restore(irq_flags); | ||
98 | trace_wake_up(); | ||
99 | |||
100 | preempt_enable(); | ||
101 | } | ||