x86/perf: A CR4.PCE bugfix and clarification
Subsystems (3)
cover x86/perf: A CR4.PCE bugfix and clarification
Hi all-
Vince found a bug in our CR4.PCE handling. While investigating, I found what looked like another bug but actually wasn't.
Here's a fix for the bug (cc'd to stable) and a comment and lockdep annotation for why the other non-bug isn't actually a bug.
Andy Lutomirski (2):
x86/perf: Fix CR4.PCE propagation to use active_mm instead of mm x86/perf: Clarify why x86_pmu_event_mapped() isn't racy
arch/x86/events/core.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
Signature · 1 line
2.9.3
PATCH 1/2 x86/perf: Fix CR4.PCE propagation to use active_mm instead of mm
If one thread mmaps a perf event while another thread in the same mm is in some context where active_mm != mm (which can happen in the scheduler, for example), refresh_pce() would write the wrong value to CR4.PCE. This broke some PAPI tests.
--- arch/x86/events/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/events/core.c +2 -2
@@ -2101,8 +2101,8 @@ static int x86_pmu_event_init(struct perf_event *event)static void refresh_pce (void *ignored) { -if (current->mm) -load_mm_cr4 (current->mm); +if (current->active_mm) +load_mm_cr4 (current->active_mm); }static void x86_pmu_event_mapped (struct perf_event *event)
Signature · 1 line
2.9.3
tip-bot for Andy Lutomirski
merge bot[tip:perf/urgent] x86/perf: Fix CR4.PCE propagation to use active_mm instead of mm
x86/perf: Fix CR4.PCE propagation to use active_mm instead of mm
Commit-ID: 5dc855d44c2ad960a86f593c60461f1ae1566b6d Gitweb: http://git.kernel.org/tip/5dc855d44c2ad960a86f593c60461f1ae1566b6d Author: Andy Lutomirski <[email protected]> AuthorDate: Thu, 16 Mar 2017 12:59:39 -0700 Committer: Ingo Molnar <[email protected]> CommitDate: Fri, 17 Mar 2017 08:28:26 +0100
x86/perf: Fix CR4.PCE propagation to use active_mm instead of mm
If one thread mmaps a perf event while another thread in the same mm is in some context where active_mm != mm (which can happen in the scheduler, for example), refresh_pce() would write the wrong value to CR4.PCE. This broke some PAPI tests.
--- arch/x86/events/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/events/core.c +2 -2
@@ -2100,8 +2100,8 @@ static int x86_pmu_event_init(struct perf_event *event)static void refresh_pce (void *ignored) { -if (current->mm) -load_mm_cr4 (current->mm); +if (current->active_mm) +load_mm_cr4 (current->active_mm); }static void x86_pmu_event_mapped (struct perf_event *event)
PATCH 2/2 x86/perf: Clarify why x86_pmu_event_mapped() isn't racy
In reply to Andy LutomirskiNaively, it looks racy, but mmap_sem saves it. Add a comment and a lockdep assertion.
--- arch/x86/events/core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/x86/events/core.c +12 -0
@@ -2110,6 +2110,18 @@ static void x86_pmu_event_mapped(struct perf_event *event)if (!(event->hw.flags &PERF_X86_EVENT_RDPMC_ALLOWED ))return ; +/* +* This function relies on not being called concurrently in two +* tasks in the same mm. Otherwise one task could observe +* perf_rdpmc_allowed > 1 and return all the way back to +* userspace with CR4.PCE clear while another task is still +* doing on_each_cpu_mask() to propagate CR4.PCE. +* +* For now, this can't happen because all callers hold mmap_sem +* for write. If this changes, we'll need a different solution. +*/ +lockdep_assert_held_exclusive (¤t->mm->mmap_sem); +if (atomic_inc_return (¤t->mm->context.perf_rdpmc_allowed) ==1 )on_each_cpu_mask (mm_cpumask (current->mm), refresh_pce,NULL ,1 ); }
Signature · 1 line
2.9.3
tip-bot for Andy Lutomirski
merge bot[tip:perf/urgent] x86/perf: Clarify why x86_pmu_event_mapped() isn't racy
x86/perf: Clarify why x86_pmu_event_mapped() isn't racy
Commit-ID: 4b07372a32c0c1505a7634ad7e607d83340ef645 Gitweb: http://git.kernel.org/tip/4b07372a32c0c1505a7634ad7e607d83340ef645 Author: Andy Lutomirski <[email protected]> AuthorDate: Thu, 16 Mar 2017 12:59:40 -0700 Committer: Ingo Molnar <[email protected]> CommitDate: Fri, 17 Mar 2017 08:28:26 +0100
x86/perf: Clarify why x86_pmu_event_mapped() isn't racy
Naively, it looks racy, but ->mmap_sem saves it. Add a comment and a lockdep assertion.
--- arch/x86/events/core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/x86/events/core.c +12 -0
@@ -2109,6 +2109,18 @@ static void x86_pmu_event_mapped(struct perf_event *event)if (!(event->hw.flags &PERF_X86_EVENT_RDPMC_ALLOWED ))return ; +/* +* This function relies on not being called concurrently in two +* tasks in the same mm. Otherwise one task could observe +* perf_rdpmc_allowed > 1 and return all the way back to +* userspace with CR4.PCE clear while another task is still +* doing on_each_cpu_mask() to propagate CR4.PCE. +* +* For now, this can't happen because all callers hold mmap_sem +* for write. If this changes, we'll need a different solution. +*/ +lockdep_assert_held_exclusive (¤t->mm->mmap_sem); +if (atomic_inc_return (¤t->mm->context.perf_rdpmc_allowed) ==1 )on_each_cpu_mask (mm_cpumask (current->mm), refresh_pce,NULL ,1 ); }