diff options
| author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-03-22 18:10:46 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-03-23 04:22:14 -0400 |
| commit | 07edf7121374609709ef1b0889f6e7b8d6a62ec1 (patch) | |
| tree | ad1649c9546dc3ce23bb2f8609a7459a7ca2006e /kernel | |
| parent | 9bd7d099ab3f10dd666da399c064999bae427cd9 (diff) | |
tracing/events: don't use wake up for events
Impact: fix hard-lockup with sched switch events
Some ftrace events, such as sched wakeup, can be traced
while the runqueue lock is hold. Since they are using
trace_current_buffer_unlock_commit(), they call wake_up()
which can try to grab the runqueue lock too, resulting in
a deadlock.
Now for all event, we call a new helper:
trace_nowake_buffer_unlock_commit() which do pretty the same than
trace_current_buffer_unlock_commit() except than it doesn't call
trace_wake_up().
Reported-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <1237759847-21025-4-git-send-email-fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/trace.c | 26 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 2 | ||||
| -rw-r--r-- | kernel/trace/trace_events_stage_3.h | 2 |
3 files changed, 24 insertions, 6 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e6fac0ffe6f0..6bad12819eb6 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -860,15 +860,25 @@ static void ftrace_trace_stack(struct trace_array *tr, | |||
| 860 | static void ftrace_trace_userstack(struct trace_array *tr, | 860 | static void ftrace_trace_userstack(struct trace_array *tr, |
| 861 | unsigned long flags, int pc); | 861 | unsigned long flags, int pc); |
| 862 | 862 | ||
| 863 | void trace_buffer_unlock_commit(struct trace_array *tr, | 863 | static inline void __trace_buffer_unlock_commit(struct trace_array *tr, |
| 864 | struct ring_buffer_event *event, | 864 | struct ring_buffer_event *event, |
| 865 | unsigned long flags, int pc) | 865 | unsigned long flags, int pc, |
| 866 | int wake) | ||
| 866 | { | 867 | { |
| 867 | ring_buffer_unlock_commit(tr->buffer, event); | 868 | ring_buffer_unlock_commit(tr->buffer, event); |
| 868 | 869 | ||
| 869 | ftrace_trace_stack(tr, flags, 6, pc); | 870 | ftrace_trace_stack(tr, flags, 6, pc); |
| 870 | ftrace_trace_userstack(tr, flags, pc); | 871 | ftrace_trace_userstack(tr, flags, pc); |
| 871 | trace_wake_up(); | 872 | |
| 873 | if (wake) | ||
| 874 | trace_wake_up(); | ||
| 875 | } | ||
| 876 | |||
| 877 | void trace_buffer_unlock_commit(struct trace_array *tr, | ||
| 878 | struct ring_buffer_event *event, | ||
| 879 | unsigned long flags, int pc) | ||
| 880 | { | ||
| 881 | __trace_buffer_unlock_commit(tr, event, flags, pc, 1); | ||
| 872 | } | 882 | } |
| 873 | 883 | ||
| 874 | struct ring_buffer_event * | 884 | struct ring_buffer_event * |
| @@ -882,7 +892,13 @@ trace_current_buffer_lock_reserve(unsigned char type, unsigned long len, | |||
| 882 | void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, | 892 | void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, |
| 883 | unsigned long flags, int pc) | 893 | unsigned long flags, int pc) |
| 884 | { | 894 | { |
| 885 | return trace_buffer_unlock_commit(&global_trace, event, flags, pc); | 895 | return __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 1); |
| 896 | } | ||
| 897 | |||
| 898 | void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event, | ||
| 899 | unsigned long flags, int pc) | ||
| 900 | { | ||
| 901 | return __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 0); | ||
| 886 | } | 902 | } |
| 887 | 903 | ||
| 888 | void | 904 | void |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index f267723c3c52..54fd9bcd0a65 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -483,6 +483,8 @@ trace_current_buffer_lock_reserve(unsigned char type, unsigned long len, | |||
| 483 | unsigned long flags, int pc); | 483 | unsigned long flags, int pc); |
| 484 | void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, | 484 | void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, |
| 485 | unsigned long flags, int pc); | 485 | unsigned long flags, int pc); |
| 486 | void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event, | ||
| 487 | unsigned long flags, int pc); | ||
| 486 | 488 | ||
| 487 | struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, | 489 | struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, |
| 488 | struct trace_array_cpu *data); | 490 | struct trace_array_cpu *data); |
diff --git a/kernel/trace/trace_events_stage_3.h b/kernel/trace/trace_events_stage_3.h index ebf215e87d5e..9a3bd49b52e5 100644 --- a/kernel/trace/trace_events_stage_3.h +++ b/kernel/trace/trace_events_stage_3.h | |||
| @@ -222,7 +222,7 @@ static void ftrace_raw_event_##call(proto) \ | |||
| 222 | \ | 222 | \ |
| 223 | assign; \ | 223 | assign; \ |
| 224 | \ | 224 | \ |
| 225 | trace_current_buffer_unlock_commit(event, irq_flags, pc); \ | 225 | trace_nowake_buffer_unlock_commit(event, irq_flags, pc); \ |
| 226 | \ | 226 | \ |
| 227 | if (call->preds && !filter_match_preds(call, entry)) \ | 227 | if (call->preds && !filter_match_preds(call, entry)) \ |
| 228 | ring_buffer_event_discard(event); \ | 228 | ring_buffer_event_discard(event); \ |
