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>
This commit is contained in:
Родитель
9bd7d099ab
Коммит
07edf71213
|
@ -860,15 +860,25 @@ static void ftrace_trace_stack(struct trace_array *tr,
|
|||
static void ftrace_trace_userstack(struct trace_array *tr,
|
||||
unsigned long flags, int pc);
|
||||
|
||||
void trace_buffer_unlock_commit(struct trace_array *tr,
|
||||
struct ring_buffer_event *event,
|
||||
unsigned long flags, int pc)
|
||||
static inline void __trace_buffer_unlock_commit(struct trace_array *tr,
|
||||
struct ring_buffer_event *event,
|
||||
unsigned long flags, int pc,
|
||||
int wake)
|
||||
{
|
||||
ring_buffer_unlock_commit(tr->buffer, event);
|
||||
|
||||
ftrace_trace_stack(tr, flags, 6, pc);
|
||||
ftrace_trace_userstack(tr, flags, pc);
|
||||
trace_wake_up();
|
||||
|
||||
if (wake)
|
||||
trace_wake_up();
|
||||
}
|
||||
|
||||
void trace_buffer_unlock_commit(struct trace_array *tr,
|
||||
struct ring_buffer_event *event,
|
||||
unsigned long flags, int pc)
|
||||
{
|
||||
__trace_buffer_unlock_commit(tr, event, flags, pc, 1);
|
||||
}
|
||||
|
||||
struct ring_buffer_event *
|
||||
|
@ -882,7 +892,13 @@ trace_current_buffer_lock_reserve(unsigned char type, unsigned long len,
|
|||
void trace_current_buffer_unlock_commit(struct ring_buffer_event *event,
|
||||
unsigned long flags, int pc)
|
||||
{
|
||||
return trace_buffer_unlock_commit(&global_trace, event, flags, pc);
|
||||
return __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 1);
|
||||
}
|
||||
|
||||
void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event,
|
||||
unsigned long flags, int pc)
|
||||
{
|
||||
return __trace_buffer_unlock_commit(&global_trace, event, flags, pc, 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -483,6 +483,8 @@ trace_current_buffer_lock_reserve(unsigned char type, unsigned long len,
|
|||
unsigned long flags, int pc);
|
||||
void trace_current_buffer_unlock_commit(struct ring_buffer_event *event,
|
||||
unsigned long flags, int pc);
|
||||
void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event,
|
||||
unsigned long flags, int pc);
|
||||
|
||||
struct trace_entry *tracing_get_trace_entry(struct trace_array *tr,
|
||||
struct trace_array_cpu *data);
|
||||
|
|
|
@ -222,7 +222,7 @@ static void ftrace_raw_event_##call(proto) \
|
|||
\
|
||||
assign; \
|
||||
\
|
||||
trace_current_buffer_unlock_commit(event, irq_flags, pc); \
|
||||
trace_nowake_buffer_unlock_commit(event, irq_flags, pc); \
|
||||
\
|
||||
if (call->preds && !filter_match_preds(call, entry)) \
|
||||
ring_buffer_event_discard(event); \
|
||||
|
|
Загрузка…
Ссылка в новой задаче