perf/x86/intel: Delay memory deallocation until x86_pmu_dead_cpu() [Linux 4.9.156]

This Linux kernel change "perf/x86/intel: Delay memory deallocation until x86_pmu_dead_cpu()" is included in the Linux 4.9.156 release. This change is authored by Peter Zijlstra <peterz [at] infradead.org> on Wed Dec 19 17:53:50 2018 +0100. The commit for this change in Linux stable tree is bd10eb8 (patch) which is from upstream commit 602cae0. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 602cae0.

perf/x86/intel: Delay memory deallocation until x86_pmu_dead_cpu()

commit 602cae04c4864bb3487dfe4c2126c8d9e7e1614a upstream.

intel_pmu_cpu_prepare() allocated memory for ->shared_regs among other
members of struct cpu_hw_events. This memory is released in
intel_pmu_cpu_dying() which is wrong. The counterpart of the
intel_pmu_cpu_prepare() callback is x86_pmu_dead_cpu().

Otherwise if the CPU fails on the UP path between CPUHP_PERF_X86_PREPARE
and CPUHP_AP_PERF_X86_STARTING then it won't release the memory but
allocate new memory on the next attempt to online the CPU (leaking the
old memory).
Also, if the CPU down path fails between CPUHP_AP_PERF_X86_STARTING and
CPUHP_PERF_X86_PREPARE then the CPU will go back online but never
allocate the memory that was released in x86_pmu_dying_cpu().

Make the memory allocation/free symmetrical in regard to the CPU hotplug
notifier by moving the deallocation to intel_pmu_cpu_dead().

This started in commit:

   a7e3ed1e47011 ("perf: Add support for supplementary event registers").

In principle the bug was introduced in v2.6.39 (!), but it will almost
certainly not backport cleanly across the big CPU hotplug rewrite between v4.7-v4.15...

[ bigeasy: Added patch description. ]
[ mingo: Added backporting guidance. ]

Reported-by: He Zhe <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]> # With developer hat on
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]> # With maintainer hat on
Cc: Alexander Shishkin <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: <[email protected]>
Fixes: a7e3ed1e47011 ("perf: Add support for supplementary event registers").
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
[ He Zhe: Fixes conflict caused by missing disable_counter_freeze which is
 introduced since v4.20 af3bdb991a5cb. ]
Signed-off-by: He Zhe <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

There are 10 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 arch/x86/events/intel/core.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 4f85607..f600ab6 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -3235,6 +3235,11 @@ static void free_excl_cntrs(int cpu)

 static void intel_pmu_cpu_dying(int cpu)
 {
+   fini_debug_store_on_cpu(cpu);
+}
+
+static void intel_pmu_cpu_dead(int cpu)
+{
    struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
    struct intel_shared_regs *pc;

@@ -3246,8 +3251,6 @@ static void intel_pmu_cpu_dying(int cpu)
    }

    free_excl_cntrs(cpu);
-
-   fini_debug_store_on_cpu(cpu);
 }

 static void intel_pmu_sched_task(struct perf_event_context *ctx,
@@ -3324,6 +3327,7 @@ static void intel_pmu_sched_task(struct perf_event_context *ctx,
    .cpu_prepare        = intel_pmu_cpu_prepare,
    .cpu_starting       = intel_pmu_cpu_starting,
    .cpu_dying      = intel_pmu_cpu_dying,
+   .cpu_dead       = intel_pmu_cpu_dead,
 };

 static __initconst const struct x86_pmu intel_pmu = {
@@ -3359,6 +3363,8 @@ static void intel_pmu_sched_task(struct perf_event_context *ctx,
    .cpu_prepare        = intel_pmu_cpu_prepare,
    .cpu_starting       = intel_pmu_cpu_starting,
    .cpu_dying      = intel_pmu_cpu_dying,
+   .cpu_dead       = intel_pmu_cpu_dead,
+
    .guest_get_msrs     = intel_guest_get_msrs,
    .sched_task     = intel_pmu_sched_task,
 };

Leave a Reply

Your email address will not be published. Required fields are marked *