On Wed, 2009-12-30 at 22:36 +0800, Wang Liming wrote:Yes, it's OK to me.Best I can make of it is that there is a race where the parent gets hisI didn't find this case.
context instantiated and we manage to get the mutex before the other
thread manages to add the first event.
Then we observe parent_event_ctx but have an empty list.
Is that it?
In my case, if I perf record a existing process with "--pid" and finish record,
and if later the recorded process forks a process, the condition will occur.
Ah, right, that will lead to the same state, since closing the last
counter will not remove the context.
Does the below also fix your issue?
---
Subject: perf: Fix NULL deref in inheritance code
From: Peter Zijlstra <a.p.zijlstra@xxxxxxxxx>
Date: Wed Dec 30 16:00:35 CET 2009
Liming found a NULL deref when a task has a perf context but no counters when it forks.
This can occur in two cases, a race during construction where the fork hits
after installing the context but before the first counter gets inserted, or
more reproducably, a fork after the last counter is closed (which leaves the
context around).
CC: stable@xxxxxxxxxx
Reported-by: Wang Liming <liming.wang@xxxxxxxxxxxxx>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@xxxxxxxxx>
---
kernel/perf_event.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
Index: linux-2.6/kernel/perf_event.c
===================================================================
--- linux-2.6.orig/kernel/perf_event.c
+++ linux-2.6/kernel/perf_event.c
@@ -5149,7 +5149,7 @@ int perf_event_init_task(struct task_str
GFP_KERNEL);
if (!child_ctx) {
ret = -ENOMEM;
- goto exit;
+ break;
}
__perf_event_init_context(child_ctx, child);
@@ -5165,7 +5165,7 @@ int perf_event_init_task(struct task_str
}
}
- if (inherited_all) {
+ if (child_ctx && inherited_all) {
/*
* Mark the child context as a clone of the parent
* context, or of whatever the parent is a clone of.
@@ -5185,7 +5185,6 @@ int perf_event_init_task(struct task_str
get_ctx(child_ctx->parent_ctx);
}
-exit:
mutex_unlock(&parent_ctx->mutex);
perf_unpin_context(parent_ctx);