| Subject: x86: perf: Deal with kfree from atomic contexts |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Thu, 04 Oct 2012 13:32:46 +0100 |
| |
| The x86 perf code allocates memory upfront because it might need |
| it. The detection that it is not needed happens in atomic context and |
| calls kfree from there. RT cant do that. Use kfree_rcu instead. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| --- |
| arch/x86/kernel/cpu/perf_event.h | 1 + |
| arch/x86/kernel/cpu/perf_event_intel.c | 2 +- |
| arch/x86/kernel/cpu/perf_event_intel_uncore.c | 5 +++-- |
| arch/x86/kernel/cpu/perf_event_intel_uncore.h | 1 + |
| 4 files changed, 6 insertions(+), 3 deletions(-) |
| |
| --- a/arch/x86/kernel/cpu/perf_event.h |
| +++ b/arch/x86/kernel/cpu/perf_event.h |
| @@ -108,6 +108,7 @@ struct intel_shared_regs { |
| struct er_account regs[EXTRA_REG_MAX]; |
| int refcnt; /* per-core: #HT threads */ |
| unsigned core_id; /* per-core: core id */ |
| + struct rcu_head rcu; |
| }; |
| |
| #define MAX_LBR_ENTRIES 16 |
| --- a/arch/x86/kernel/cpu/perf_event_intel.c |
| +++ b/arch/x86/kernel/cpu/perf_event_intel.c |
| @@ -1715,7 +1715,7 @@ static void intel_pmu_cpu_dying(int cpu) |
| pc = cpuc->shared_regs; |
| if (pc) { |
| if (pc->core_id == -1 || --pc->refcnt == 0) |
| - kfree(pc); |
| + kfree_rcu(pc, rcu); |
| cpuc->shared_regs = NULL; |
| } |
| |
| --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c |
| +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c |
| @@ -2636,7 +2636,7 @@ static void __cpuinit uncore_cpu_dying(i |
| box = *per_cpu_ptr(pmu->box, cpu); |
| *per_cpu_ptr(pmu->box, cpu) = NULL; |
| if (box && atomic_dec_and_test(&box->refcnt)) |
| - kfree(box); |
| + kfree_rcu(box, rcu); |
| } |
| } |
| } |
| @@ -2666,7 +2666,8 @@ static int __cpuinit uncore_cpu_starting |
| if (exist && exist->phys_id == phys_id) { |
| atomic_inc(&exist->refcnt); |
| *per_cpu_ptr(pmu->box, cpu) = exist; |
| - kfree(box); |
| + if (box) |
| + kfree_rcu(box, rcu); |
| box = NULL; |
| break; |
| } |
| --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h |
| +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h |
| @@ -421,6 +421,7 @@ struct intel_uncore_box { |
| struct hrtimer hrtimer; |
| struct list_head list; |
| struct intel_uncore_extra_reg shared_regs[0]; |
| + struct rcu_head rcu; |
| }; |
| |
| #define UNCORE_BOX_FLAG_INITIATED 0 |