diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2010-12-07 08:18:20 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-12-08 14:14:08 -0500 |
commit | 5167695753c63444a9e6cbbef136200a16c7a225 (patch) | |
tree | 6394b1e620027882556beb2e899449805dd3c3cc /kernel/perf_event.c | |
parent | 6313e3c21743cc88bb5bd8aa72948ee1e83937b6 (diff) |
perf: Fix duplicate events with multiple-pmu vs software events
Because the multi-pmu bits can share contexts between struct pmu
instances we could get duplicate events by iterating the pmu list.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r-- | kernel/perf_event.c | 35 |
1 files changed, 29 insertions, 6 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index eac7e3364335..7b870174c56d 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -3824,6 +3824,8 @@ static void perf_event_task_event(struct perf_task_event *task_event) | |||
3824 | rcu_read_lock(); | 3824 | rcu_read_lock(); |
3825 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 3825 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
3826 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 3826 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
3827 | if (cpuctx->active_pmu != pmu) | ||
3828 | goto next; | ||
3827 | perf_event_task_ctx(&cpuctx->ctx, task_event); | 3829 | perf_event_task_ctx(&cpuctx->ctx, task_event); |
3828 | 3830 | ||
3829 | ctx = task_event->task_ctx; | 3831 | ctx = task_event->task_ctx; |
@@ -3959,6 +3961,8 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) | |||
3959 | rcu_read_lock(); | 3961 | rcu_read_lock(); |
3960 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 3962 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
3961 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 3963 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
3964 | if (cpuctx->active_pmu != pmu) | ||
3965 | goto next; | ||
3962 | perf_event_comm_ctx(&cpuctx->ctx, comm_event); | 3966 | perf_event_comm_ctx(&cpuctx->ctx, comm_event); |
3963 | 3967 | ||
3964 | ctxn = pmu->task_ctx_nr; | 3968 | ctxn = pmu->task_ctx_nr; |
@@ -4144,6 +4148,8 @@ got_name: | |||
4144 | rcu_read_lock(); | 4148 | rcu_read_lock(); |
4145 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 4149 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
4146 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 4150 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
4151 | if (cpuctx->active_pmu != pmu) | ||
4152 | goto next; | ||
4147 | perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, | 4153 | perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, |
4148 | vma->vm_flags & VM_EXEC); | 4154 | vma->vm_flags & VM_EXEC); |
4149 | 4155 | ||
@@ -5145,20 +5151,36 @@ static void *find_pmu_context(int ctxn) | |||
5145 | return NULL; | 5151 | return NULL; |
5146 | } | 5152 | } |
5147 | 5153 | ||
5148 | static void free_pmu_context(void * __percpu cpu_context) | 5154 | static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu) |
5149 | { | 5155 | { |
5150 | struct pmu *pmu; | 5156 | int cpu; |
5157 | |||
5158 | for_each_possible_cpu(cpu) { | ||
5159 | struct perf_cpu_context *cpuctx; | ||
5160 | |||
5161 | cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); | ||
5162 | |||
5163 | if (cpuctx->active_pmu == old_pmu) | ||
5164 | cpuctx->active_pmu = pmu; | ||
5165 | } | ||
5166 | } | ||
5167 | |||
5168 | static void free_pmu_context(struct pmu *pmu) | ||
5169 | { | ||
5170 | struct pmu *i; | ||
5151 | 5171 | ||
5152 | mutex_lock(&pmus_lock); | 5172 | mutex_lock(&pmus_lock); |
5153 | /* | 5173 | /* |
5154 | * Like a real lame refcount. | 5174 | * Like a real lame refcount. |
5155 | */ | 5175 | */ |
5156 | list_for_each_entry(pmu, &pmus, entry) { | 5176 | list_for_each_entry(i, &pmus, entry) { |
5157 | if (pmu->pmu_cpu_context == cpu_context) | 5177 | if (i->pmu_cpu_context == pmu->pmu_cpu_context) { |
5178 | update_pmu_context(i, pmu); | ||
5158 | goto out; | 5179 | goto out; |
5180 | } | ||
5159 | } | 5181 | } |
5160 | 5182 | ||
5161 | free_percpu(cpu_context); | 5183 | free_percpu(pmu->pmu_cpu_context); |
5162 | out: | 5184 | out: |
5163 | mutex_unlock(&pmus_lock); | 5185 | mutex_unlock(&pmus_lock); |
5164 | } | 5186 | } |
@@ -5190,6 +5212,7 @@ int perf_pmu_register(struct pmu *pmu) | |||
5190 | cpuctx->ctx.pmu = pmu; | 5212 | cpuctx->ctx.pmu = pmu; |
5191 | cpuctx->jiffies_interval = 1; | 5213 | cpuctx->jiffies_interval = 1; |
5192 | INIT_LIST_HEAD(&cpuctx->rotation_list); | 5214 | INIT_LIST_HEAD(&cpuctx->rotation_list); |
5215 | cpuctx->active_pmu = pmu; | ||
5193 | } | 5216 | } |
5194 | 5217 | ||
5195 | got_cpu_context: | 5218 | got_cpu_context: |
@@ -5241,7 +5264,7 @@ void perf_pmu_unregister(struct pmu *pmu) | |||
5241 | synchronize_rcu(); | 5264 | synchronize_rcu(); |
5242 | 5265 | ||
5243 | free_percpu(pmu->pmu_disable_count); | 5266 | free_percpu(pmu->pmu_disable_count); |
5244 | free_pmu_context(pmu->pmu_cpu_context); | 5267 | free_pmu_context(pmu); |
5245 | } | 5268 | } |
5246 | 5269 | ||
5247 | struct pmu *perf_init_event(struct perf_event *event) | 5270 | struct pmu *perf_init_event(struct perf_event *event) |