Commit 8bb39f9a authored by Mike Galbraith's avatar Mike Galbraith Committed by Ingo Molnar

perf: Fix 'perf sched record' deadlock

perf sched record can deadlock a box should the holder of
handle->data->lock take an interrupt, and then attempt to
acquire an rq lock held by a CPU trying to acquire the
same lock. Disable interrupts.

   CPU0                            CPU1
   sched event with rq->lock held
                                   grab handle->data->lock
   spin on handle->data->lock
                                   interrupt
                                   try to grab rq->lock
Reported-by: default avatarLi Zefan <lizf@cn.fujitsu.com>
Signed-off-by: default avatarMike Galbraith <efault@gmx.de>
Tested-by: default avatarLi Zefan <lizf@cn.fujitsu.com>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <1269598293.6174.8.camel@marge.simson.net>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 257ef9d2
...@@ -3376,15 +3376,23 @@ static void perf_event_task_output(struct perf_event *event, ...@@ -3376,15 +3376,23 @@ static void perf_event_task_output(struct perf_event *event,
struct perf_task_event *task_event) struct perf_task_event *task_event)
{ {
struct perf_output_handle handle; struct perf_output_handle handle;
int size;
struct task_struct *task = task_event->task; struct task_struct *task = task_event->task;
int ret; unsigned long flags;
int size, ret;
/*
* If this CPU attempts to acquire an rq lock held by a CPU spinning
* in perf_output_lock() from interrupt context, it's game over.
*/
local_irq_save(flags);
size = task_event->event_id.header.size; size = task_event->event_id.header.size;
ret = perf_output_begin(&handle, event, size, 0, 0); ret = perf_output_begin(&handle, event, size, 0, 0);
if (ret) if (ret) {
local_irq_restore(flags);
return; return;
}
task_event->event_id.pid = perf_event_pid(event, task); task_event->event_id.pid = perf_event_pid(event, task);
task_event->event_id.ppid = perf_event_pid(event, current); task_event->event_id.ppid = perf_event_pid(event, current);
...@@ -3395,6 +3403,7 @@ static void perf_event_task_output(struct perf_event *event, ...@@ -3395,6 +3403,7 @@ static void perf_event_task_output(struct perf_event *event,
perf_output_put(&handle, task_event->event_id); perf_output_put(&handle, task_event->event_id);
perf_output_end(&handle); perf_output_end(&handle);
local_irq_restore(flags);
} }
static int perf_event_task_match(struct perf_event *event) static int perf_event_task_match(struct perf_event *event)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment