diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-08-20 12:20:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-08-20 12:20:57 -0400 |
commit | e46db8d2ef58f9b515f83be4608cef90ff9ae2c6 (patch) | |
tree | a06fb90781963e956c964da12e7cc3aabd33af72 | |
parent | 9dae41a238a952eb65c8aa8a59d8aa39058a7bcf (diff) | |
parent | 9b231d9f47c6114d317ce28cff92a74ad80547f5 (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.c | 16 | ||||
-rw-r--r-- | include/linux/perf_event.h | 4 | ||||
-rw-r--r-- | kernel/events/core.c | 47 |
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 | ||
2117 | static void x86_pmu_event_mapped(struct perf_event *event) | 2117 | static 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(¤t->mm->mmap_sem); | 2132 | lockdep_assert_held_exclusive(&mm->mmap_sem); |
2133 | 2133 | ||
2134 | if (atomic_inc_return(¤t->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 | ||
2138 | static void x86_pmu_event_unmapped(struct perf_event *event) | 2138 | static 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(¤t->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 | ||
2150 | static int x86_pmu_event_idx(struct perf_event *event) | 2148 | static 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 | */ | ||
2238 | static 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 | |||
2220 | static void add_event_to_ctx(struct perf_event *event, | 2247 | static 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 | ||
2232 | static void ctx_sched_out(struct perf_event_context *ctx, | 2262 | static 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 | ||
5096 | static void perf_pmu_output_stop(struct perf_event *event); | 5127 | static 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 | } |