Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07edf712 authored by Frederic Weisbecker's avatar Frederic Weisbecker Committed by Ingo Molnar
Browse files

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: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <1237759847-21025-4-git-send-email-fweisbec@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 9bd7d099
Loading
Loading
Loading
Loading
+21 −5
Original line number Diff line number Diff line
@@ -860,17 +860,27 @@ 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,
static inline void __trace_buffer_unlock_commit(struct trace_array *tr,
					struct ring_buffer_event *event,
				unsigned long flags, int pc)
					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);

	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 *
trace_current_buffer_lock_reserve(unsigned char type, unsigned long len,
				  unsigned long flags, int pc)
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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);			\