diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index bb53edbb5c8c..d9062f5cc0c0 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/hash.h> | 29 | #include <linux/hash.h> |
30 | #include <linux/rcupdate.h> | ||
30 | 31 | ||
31 | #include <trace/events/sched.h> | 32 | #include <trace/events/sched.h> |
32 | 33 | ||
@@ -84,18 +85,22 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | |||
84 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; | 85 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; |
85 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; | 86 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; |
86 | 87 | ||
88 | /* | ||
89 | * Traverse the ftrace_list, invoking all entries. The reason that we | ||
90 | * can use rcu_dereference_raw() is that elements removed from this list | ||
91 | * are simply leaked, so there is no need to interact with a grace-period | ||
92 | * mechanism. The rcu_dereference_raw() calls are needed to handle | ||
93 | * concurrent insertions into the ftrace_list. | ||
94 | * | ||
95 | * Silly Alpha and silly pointer-speculation compiler optimizations! | ||
96 | */ | ||
87 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) | 97 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) |
88 | { | 98 | { |
89 | struct ftrace_ops *op = ftrace_list; | 99 | struct ftrace_ops *op = rcu_dereference_raw(ftrace_list); /*see above*/ |
90 | |||
91 | /* in case someone actually ports this to alpha! */ | ||
92 | read_barrier_depends(); | ||
93 | 100 | ||
94 | while (op != &ftrace_list_end) { | 101 | while (op != &ftrace_list_end) { |
95 | /* silly alpha */ | ||
96 | read_barrier_depends(); | ||
97 | op->func(ip, parent_ip); | 102 | op->func(ip, parent_ip); |
98 | op = op->next; | 103 | op = rcu_dereference_raw(op->next); /*see above*/ |
99 | }; | 104 | }; |
100 | } | 105 | } |
101 | 106 | ||
@@ -150,8 +155,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
150 | * the ops->next pointer is valid before another CPU sees | 155 | * the ops->next pointer is valid before another CPU sees |
151 | * the ops pointer included into the ftrace_list. | 156 | * the ops pointer included into the ftrace_list. |
152 | */ | 157 | */ |
153 | smp_wmb(); | 158 | rcu_assign_pointer(ftrace_list, ops); |
154 | ftrace_list = ops; | ||
155 | 159 | ||
156 | if (ftrace_enabled) { | 160 | if (ftrace_enabled) { |
157 | ftrace_func_t func; | 161 | ftrace_func_t func; |