Skip to content

Commit 488e13a

Browse files
Like XuPeter Zijlstra
authored andcommitted
perf/x86/lbr: Remove cpuc->lbr_xsave allocation from atomic context
If the kernel is compiled with the CONFIG_LOCKDEP option, the conditional might_sleep_if() deep in kmem_cache_alloc() will generate the following trace, and potentially cause a deadlock when another LBR event is added: [] BUG: sleeping function called from invalid context at include/linux/sched/mm.h:196 [] Call Trace: [] kmem_cache_alloc+0x36/0x250 [] intel_pmu_lbr_add+0x152/0x170 [] x86_pmu_add+0x83/0xd0 Make it symmetric with the release_lbr_buffers() call and mirror the existing DS buffers. Fixes: c085fb8 ("perf/x86/intel/lbr: Support XSAVES for arch LBR read") Signed-off-by: Like Xu <[email protected]> [peterz: simplified] Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Tested-by: Kan Liang <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 3317c26 commit 488e13a

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

arch/x86/events/core.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,12 @@ int x86_reserve_hardware(void)
396396
if (!atomic_inc_not_zero(&pmc_refcount)) {
397397
mutex_lock(&pmc_reserve_mutex);
398398
if (atomic_read(&pmc_refcount) == 0) {
399-
if (!reserve_pmc_hardware())
399+
if (!reserve_pmc_hardware()) {
400400
err = -EBUSY;
401-
else
401+
} else {
402402
reserve_ds_buffers();
403+
reserve_lbr_buffers();
404+
}
403405
}
404406
if (!err)
405407
atomic_inc(&pmc_refcount);

arch/x86/events/intel/lbr.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,6 @@ static inline bool branch_user_callstack(unsigned br_sel)
658658

659659
void intel_pmu_lbr_add(struct perf_event *event)
660660
{
661-
struct kmem_cache *kmem_cache = event->pmu->task_ctx_cache;
662661
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
663662

664663
if (!x86_pmu.lbr_nr)
@@ -696,11 +695,6 @@ void intel_pmu_lbr_add(struct perf_event *event)
696695
perf_sched_cb_inc(event->ctx->pmu);
697696
if (!cpuc->lbr_users++ && !event->total_time_running)
698697
intel_pmu_lbr_reset();
699-
700-
if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&
701-
kmem_cache && !cpuc->lbr_xsave &&
702-
(cpuc->lbr_users != cpuc->lbr_pebs_users))
703-
cpuc->lbr_xsave = kmem_cache_alloc(kmem_cache, GFP_KERNEL);
704698
}
705699

706700
void release_lbr_buffers(void)
@@ -722,6 +716,26 @@ void release_lbr_buffers(void)
722716
}
723717
}
724718

719+
void reserve_lbr_buffers(void)
720+
{
721+
struct kmem_cache *kmem_cache;
722+
struct cpu_hw_events *cpuc;
723+
int cpu;
724+
725+
if (!static_cpu_has(X86_FEATURE_ARCH_LBR))
726+
return;
727+
728+
for_each_possible_cpu(cpu) {
729+
cpuc = per_cpu_ptr(&cpu_hw_events, cpu);
730+
kmem_cache = x86_get_pmu(cpu)->task_ctx_cache;
731+
if (!kmem_cache || cpuc->lbr_xsave)
732+
continue;
733+
734+
cpuc->lbr_xsave = kmem_cache_alloc_node(kmem_cache, GFP_KERNEL,
735+
cpu_to_node(cpu));
736+
}
737+
}
738+
725739
void intel_pmu_lbr_del(struct perf_event *event)
726740
{
727741
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);

arch/x86/events/perf_event.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,8 @@ void reserve_ds_buffers(void);
12441244

12451245
void release_lbr_buffers(void);
12461246

1247+
void reserve_lbr_buffers(void);
1248+
12471249
extern struct event_constraint bts_constraint;
12481250
extern struct event_constraint vlbr_constraint;
12491251

@@ -1393,6 +1395,10 @@ static inline void release_lbr_buffers(void)
13931395
{
13941396
}
13951397

1398+
static inline void reserve_lbr_buffers(void)
1399+
{
1400+
}
1401+
13961402
static inline int intel_pmu_init(void)
13971403
{
13981404
return 0;

0 commit comments

Comments
 (0)