aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-08-20 12:20:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-08-20 12:20:57 -0400
commite46db8d2ef58f9b515f83be4608cef90ff9ae2c6 (patch)
treea06fb90781963e956c964da12e7cc3aabd33af72
parent9dae41a238a952eb65c8aa8a59d8aa39058a7bcf (diff)
parent9b231d9f47c6114d317ce28cff92a74ad80547f5 (diff)
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Thomas Gleixner: "Two fixes for the perf subsystem: - Fix an inconsistency of RDPMC mm struct tagging across exec() which causes RDPMC to fault. - Correct the timestamp mechanics across IOC_DISABLE/ENABLE which causes incorrect timestamps and total time calculations" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: perf/core: Fix time on IOC_ENABLE perf/x86: Fix RDPMC vs. mm_struct tracking
-rw-r--r--arch/x86/events/core.c16
-rw-r--r--include/linux/perf_event.h4
-rw-r--r--kernel/events/core.c47
3 files changed, 48 insertions, 19 deletions
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 8e3db8f642a7..af12e294caed 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2114,7 +2114,7 @@ static void refresh_pce(void *ignored)
2114 load_mm_cr4(this_cpu_read(cpu_tlbstate.loaded_mm)); 2114 load_mm_cr4(this_cpu_read(cpu_tlbstate.loaded_mm));
2115} 2115}
2116 2116
2117static void x86_pmu_event_mapped(struct perf_event *event) 2117static void x86_pmu_event_mapped(struct perf_event *event, struct mm_struct *mm)
2118{ 2118{
2119 if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED)) 2119 if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
2120 return; 2120 return;
@@ -2129,22 +2129,20 @@ static void x86_pmu_event_mapped(struct perf_event *event)
2129 * For now, this can't happen because all callers hold mmap_sem 2129 * For now, this can't happen because all callers hold mmap_sem
2130 * for write. If this changes, we'll need a different solution. 2130 * for write. If this changes, we'll need a different solution.
2131 */ 2131 */
2132 lockdep_assert_held_exclusive(&current->mm->mmap_sem); 2132 lockdep_assert_held_exclusive(&mm->mmap_sem);
2133 2133
2134 if (atomic_inc_return(&current->mm->context.perf_rdpmc_allowed) == 1) 2134 if (atomic_inc_return(&mm->context.perf_rdpmc_allowed) == 1)
2135 on_each_cpu_mask(mm_cpumask(current->mm), refresh_pce, NULL, 1); 2135 on_each_cpu_mask(mm_cpumask(mm), refresh_pce, NULL, 1);
2136} 2136}
2137 2137
2138static void x86_pmu_event_unmapped(struct perf_event *event) 2138static void x86_pmu_event_unmapped(struct perf_event *event, struct mm_struct *mm)
2139{ 2139{
2140 if (!current->mm)
2141 return;
2142 2140
2143 if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED)) 2141 if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
2144 return; 2142 return;
2145 2143
2146 if (atomic_dec_and_test(&current->mm->context.perf_rdpmc_allowed)) 2144 if (atomic_dec_and_test(&mm->context.perf_rdpmc_allowed))
2147 on_each_cpu_mask(mm_cpumask(current->mm), refresh_pce, NULL, 1); 2145 on_each_cpu_mask(mm_cpumask(mm), refresh_pce, NULL, 1);
2148} 2146}
2149 2147
2150static int x86_pmu_event_idx(struct perf_event *event) 2148static int x86_pmu_event_idx(struct perf_event *event)
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index a3b873fc59e4..b14095bcf4bb 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -310,8 +310,8 @@ struct pmu {
310 * Notification that the event was mapped or unmapped. Called 310 * Notification that the event was mapped or unmapped. Called
311 * in the context of the mapping task. 311 * in the context of the mapping task.
312 */ 312 */
313 void (*event_mapped) (struct perf_event *event); /*optional*/ 313 void (*event_mapped) (struct perf_event *event, struct mm_struct *mm); /* optional */
314 void (*event_unmapped) (struct perf_event *event); /*optional*/ 314 void (*event_unmapped) (struct perf_event *event, struct mm_struct *mm); /* optional */
315 315
316 /* 316 /*
317 * Flags for ->add()/->del()/ ->start()/->stop(). There are 317 * Flags for ->add()/->del()/ ->start()/->stop(). There are
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 426c2ffba16d..ee20d4c546b5 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2217,6 +2217,33 @@ static int group_can_go_on(struct perf_event *event,
2217 return can_add_hw; 2217 return can_add_hw;
2218} 2218}
2219 2219
2220/*
2221 * Complement to update_event_times(). This computes the tstamp_* values to
2222 * continue 'enabled' state from @now, and effectively discards the time
2223 * between the prior tstamp_stopped and now (as we were in the OFF state, or
2224 * just switched (context) time base).
2225 *
2226 * This further assumes '@event->state == INACTIVE' (we just came from OFF) and
2227 * cannot have been scheduled in yet. And going into INACTIVE state means
2228 * '@event->tstamp_stopped = @now'.
2229 *
2230 * Thus given the rules of update_event_times():
2231 *
2232 * total_time_enabled = tstamp_stopped - tstamp_enabled
2233 * total_time_running = tstamp_stopped - tstamp_running
2234 *
2235 * We can insert 'tstamp_stopped == now' and reverse them to compute new
2236 * tstamp_* values.
2237 */
2238static void __perf_event_enable_time(struct perf_event *event, u64 now)
2239{
2240 WARN_ON_ONCE(event->state != PERF_EVENT_STATE_INACTIVE);
2241
2242 event->tstamp_stopped = now;
2243 event->tstamp_enabled = now - event->total_time_enabled;
2244 event->tstamp_running = now - event->total_time_running;
2245}
2246
2220static void add_event_to_ctx(struct perf_event *event, 2247static void add_event_to_ctx(struct perf_event *event,
2221 struct perf_event_context *ctx) 2248 struct perf_event_context *ctx)
2222{ 2249{
@@ -2224,9 +2251,12 @@ static void add_event_to_ctx(struct perf_event *event,
2224 2251
2225 list_add_event(event, ctx); 2252 list_add_event(event, ctx);
2226 perf_group_attach(event); 2253 perf_group_attach(event);
2227 event->tstamp_enabled = tstamp; 2254 /*
2228 event->tstamp_running = tstamp; 2255 * We can be called with event->state == STATE_OFF when we create with
2229 event->tstamp_stopped = tstamp; 2256 * .disabled = 1. In that case the IOC_ENABLE will call this function.
2257 */
2258 if (event->state == PERF_EVENT_STATE_INACTIVE)
2259 __perf_event_enable_time(event, tstamp);
2230} 2260}
2231 2261
2232static void ctx_sched_out(struct perf_event_context *ctx, 2262static void ctx_sched_out(struct perf_event_context *ctx,
@@ -2471,10 +2501,11 @@ static void __perf_event_mark_enabled(struct perf_event *event)
2471 u64 tstamp = perf_event_time(event); 2501 u64 tstamp = perf_event_time(event);
2472 2502
2473 event->state = PERF_EVENT_STATE_INACTIVE; 2503 event->state = PERF_EVENT_STATE_INACTIVE;
2474 event->tstamp_enabled = tstamp - event->total_time_enabled; 2504 __perf_event_enable_time(event, tstamp);
2475 list_for_each_entry(sub, &event->sibling_list, group_entry) { 2505 list_for_each_entry(sub, &event->sibling_list, group_entry) {
2506 /* XXX should not be > INACTIVE if event isn't */
2476 if (sub->state >= PERF_EVENT_STATE_INACTIVE) 2507 if (sub->state >= PERF_EVENT_STATE_INACTIVE)
2477 sub->tstamp_enabled = tstamp - sub->total_time_enabled; 2508 __perf_event_enable_time(sub, tstamp);
2478 } 2509 }
2479} 2510}
2480 2511
@@ -5090,7 +5121,7 @@ static void perf_mmap_open(struct vm_area_struct *vma)
5090 atomic_inc(&event->rb->aux_mmap_count); 5121 atomic_inc(&event->rb->aux_mmap_count);
5091 5122
5092 if (event->pmu->event_mapped) 5123 if (event->pmu->event_mapped)
5093 event->pmu->event_mapped(event); 5124 event->pmu->event_mapped(event, vma->vm_mm);
5094} 5125}
5095 5126
5096static void perf_pmu_output_stop(struct perf_event *event); 5127static void perf_pmu_output_stop(struct perf_event *event);
@@ -5113,7 +5144,7 @@ static void perf_mmap_close(struct vm_area_struct *vma)
5113 unsigned long size = perf_data_size(rb); 5144 unsigned long size = perf_data_size(rb);
5114 5145
5115 if (event->pmu->event_unmapped) 5146 if (event->pmu->event_unmapped)
5116 event->pmu->event_unmapped(event); 5147 event->pmu->event_unmapped(event, vma->vm_mm);
5117 5148
5118 /* 5149 /*
5119 * rb->aux_mmap_count will always drop before rb->mmap_count and 5150 * rb->aux_mmap_count will always drop before rb->mmap_count and
@@ -5411,7 +5442,7 @@ aux_unlock:
5411 vma->vm_ops = &perf_mmap_vmops; 5442 vma->vm_ops = &perf_mmap_vmops;
5412 5443
5413 if (event->pmu->event_mapped) 5444 if (event->pmu->event_mapped)
5414 event->pmu->event_mapped(event); 5445 event->pmu->event_mapped(event, vma->vm_mm);
5415 5446
5416 return ret; 5447 return ret;
5417} 5448}