History

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

Linus Torvalds committed 9 years ago

Commit e46db8d2 parents 9dae41a 9b231d93 files · +48 −19Browse files

Unified · Split

3 files
  1. arch/x86/events/core.c +7 −9
  2. include/linux/perf_event.h +2 −2
  3. kernel/events/core.c +39 −8
arch/x86/events/core.c+7−9
@@ -2114,7 +2114,7 @@ static void refresh_pce(void *ignored) · 2113 unmodified lines
21142114 load_mm_cr4(this_cpu_read(cpu_tlbstate.loaded_mm));
21152115 }
21162116
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)
21182118 {
21192119 if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
21202120 return;
@@ -2129,22 +2129,20 @@ static void x86_pmu_event_mapped(struct perf_event *event) · 8 unmodified lines
21292129 * For now, this can't happen because all callers hold mmap_sem
21302130 * for write. If this changes, we'll need a different solution.
21312131 */
2132− lockdep_assert_held_exclusive(&current->mm->mmap_sem);
2132+ lockdep_assert_held_exclusive(&mm->mmap_sem);
21332133
2134− if (atomic_inc_return(&current->mm->context.perf_rdpmc_allowed) == 1)
2135− on_each_cpu_mask(mm_cpumask(current->mm), refresh_pce, NULL, 1);
2134+ if (atomic_inc_return(&mm->context.perf_rdpmc_allowed) == 1)
2135+ on_each_cpu_mask(mm_cpumask(mm), refresh_pce, NULL, 1);
21362136 }
21372137
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)
21392139 {
2140− if (!current->mm)
2141− return;
21422140
21432141 if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
21442142 return;
21452143
2146− if (atomic_dec_and_test(&current->mm->context.perf_rdpmc_allowed))
2147− on_each_cpu_mask(mm_cpumask(current->mm), refresh_pce, NULL, 1);
2144+ if (atomic_dec_and_test(&mm->context.perf_rdpmc_allowed))
2145+ on_each_cpu_mask(mm_cpumask(mm), refresh_pce, NULL, 1);
21482146 }
21492147
21502148 static int x86_pmu_event_idx(struct perf_event *event)
include/linux/perf_event.h+2−2
@@ -310,8 +310,8 @@ struct pmu { · 309 unmodified lines
310310 * Notification that the event was mapped or unmapped. Called
311311 * in the context of the mapping task.
312312 */
313− void (*event_mapped) (struct perf_event *event); /*optional*/
314− void (*event_unmapped) (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, struct mm_struct *mm); /* optional */
315315
316316 /*
317317 * Flags for ->add()/->del()/ ->start()/->stop(). There are
kernel/events/core.c+39−8
@@ -2217,6 +2217,33 @@ static int group_can_go_on(struct perf_event *event, · 2216 unmodified lines
22172217 return can_add_hw;
22182218 }
22192219
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+
22202247 static void add_event_to_ctx(struct perf_event *event,
22212248 struct perf_event_context *ctx)
22222249 {
@@ -2224,9 +2251,12 @@ static void add_event_to_ctx(struct perf_event *event, · 1 unmodified line
22242251
22252252 list_add_event(event, ctx);
22262253 perf_group_attach(event);
2227− event->tstamp_enabled = tstamp;
2228− event->tstamp_running = tstamp;
2229− event->tstamp_stopped = tstamp;
2254+ /*
2255+ * We can be called with event->state == STATE_OFF when we create with
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);
22302260 }
22312261
22322262 static void ctx_sched_out(struct perf_event_context *ctx,
@@ -2471,10 +2501,11 @@ static void __perf_event_mark_enabled(struct perf_event *event) · 238 unmodified lines
24712501 u64 tstamp = perf_event_time(event);
24722502
24732503 event->state = PERF_EVENT_STATE_INACTIVE;
2474− event->tstamp_enabled = tstamp - event->total_time_enabled;
2504+ __perf_event_enable_time(event, tstamp);
24752505 list_for_each_entry(sub, &event->sibling_list, group_entry) {
2506+ /* XXX should not be > INACTIVE if event isn't */
24762507 if (sub->state >= PERF_EVENT_STATE_INACTIVE)
2477− sub->tstamp_enabled = tstamp - sub->total_time_enabled;
2508+ __perf_event_enable_time(sub, tstamp);
24782509 }
24792510 }
24802511
@@ -5090,7 +5121,7 @@ static void perf_mmap_open(struct vm_area_struct *vma) · 2609 unmodified lines
50905121 atomic_inc(&event->rb->aux_mmap_count);
50915122
50925123 if (event->pmu->event_mapped)
5093− event->pmu->event_mapped(event);
5124+ event->pmu->event_mapped(event, vma->vm_mm);
50945125 }
50955126
50965127 static void perf_pmu_output_stop(struct perf_event *event);
@@ -5113,7 +5144,7 @@ static void perf_mmap_close(struct vm_area_struct *vma) · 16 unmodified lines
51135144 unsigned long size = perf_data_size(rb);
51145145
51155146 if (event->pmu->event_unmapped)
5116− event->pmu->event_unmapped(event);
5147+ event->pmu->event_unmapped(event, vma->vm_mm);
51175148
51185149 /*
51195150 * rb->aux_mmap_count will always drop before rb->mmap_count and
@@ -5411,7 +5442,7 @@ aux_unlock: · 291 unmodified lines
54115442 vma->vm_ops = &perf_mmap_vmops;
54125443
54135444 if (event->pmu->event_mapped)
5414− event->pmu->event_mapped(event);
5445+ event->pmu->event_mapped(event, vma->vm_mm);
54155446
54165447 return ret;
54175448 }