History

perf/x86: Fix perf,x86,cpuhp deadlock

More lockdep gifts, a 5-way lockup race: perf_event_create_kernel_counter() perf_event_alloc() perf_try_init_event() x86_pmu_event_init() __x86_pmu_event_init() x86_reserve_hardware() #0 mutex_lock(&pmc_reserve_mutex); reserve_ds_buffer() #1 get_online_cpus() perf_event_release_kernel() _free_event() hw_perf_event_destroy() x86_release_hardware() #0 mutex_lock(&pmc_reserve_mutex) release_ds_buffer() #1 get_online_cpus() #1 do_cpu_up() perf_event_init_cpu() #2 mutex_lock(&pmus_lock) #3 mutex_lock(&ctx->mutex) sys_perf_event_open() mutex_lock_double() #3 mutex_lock(ctx->mutex) #4 mutex_lock_nested(ctx->mutex, 1); perf_try_init_event() #4 mutex_lock_nested(ctx->mutex, 1) x86_pmu_event_init() intel_pmu_hw_config() x86_add_exclusive() #0 mutex_lock(&pmc_reserve_mutex) Fix it by using ordering constructs instead of locking.

Peter Zijlstra committed 8 years ago

Commit efe951d1 parent 0c7296c1 file · +18 −15Browse files

Unified · Split

arch/x86/events/intel/ds.c+18−15
@@ -372,10 +372,9 @@ static int alloc_pebs_buffer(int cpu) · 371 unmodified lines
372static void release_pebs_buffer(int cpu)372static void release_pebs_buffer(int cpu)
373{373{
374 struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu);374 struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu);
375 struct debug_store *ds = hwev->ds;
376 void *cea;375 void *cea;
377 376
378 if (!ds || !x86_pmu.pebs)377 if (!x86_pmu.pebs)
379 return;378 return;
380 379
381 kfree(per_cpu(insn_buffer, cpu));380 kfree(per_cpu(insn_buffer, cpu));
@@ -384,7 +383,6 @@ static void release_pebs_buffer(int cpu) · 2 unmodified lines
384 /* Clear the fixmap */383 /* Clear the fixmap */
385 cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.pebs_buffer;384 cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.pebs_buffer;
386 ds_clear_cea(cea, x86_pmu.pebs_buffer_size);385 ds_clear_cea(cea, x86_pmu.pebs_buffer_size);
387 ds->pebs_buffer_base = 0;
388 dsfree_pages(hwev->ds_pebs_vaddr, x86_pmu.pebs_buffer_size);386 dsfree_pages(hwev->ds_pebs_vaddr, x86_pmu.pebs_buffer_size);
389 hwev->ds_pebs_vaddr = NULL;387 hwev->ds_pebs_vaddr = NULL;
390}388}
@@ -419,16 +417,14 @@ static int alloc_bts_buffer(int cpu) · 28 unmodified lines
419static void release_bts_buffer(int cpu)417static void release_bts_buffer(int cpu)
420{418{
421 struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu);419 struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu);
422 struct debug_store *ds = hwev->ds;
423 void *cea;420 void *cea;
424 421
425 if (!ds || !x86_pmu.bts)422 if (!x86_pmu.bts)
426 return;423 return;
427 424
428 /* Clear the fixmap */425 /* Clear the fixmap */
429 cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.bts_buffer;426 cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.bts_buffer;
430 ds_clear_cea(cea, BTS_BUFFER_SIZE);427 ds_clear_cea(cea, BTS_BUFFER_SIZE);
431 ds->bts_buffer_base = 0;
432 dsfree_pages(hwev->ds_bts_vaddr, BTS_BUFFER_SIZE);428 dsfree_pages(hwev->ds_bts_vaddr, BTS_BUFFER_SIZE);
433 hwev->ds_bts_vaddr = NULL;429 hwev->ds_bts_vaddr = NULL;
434}430}
@@ -454,16 +450,22 @@ void release_ds_buffers(void) · 19 unmodified lines
454 if (!x86_pmu.bts && !x86_pmu.pebs)450 if (!x86_pmu.bts && !x86_pmu.pebs)
455 return;451 return;
456 452
457 get_online_cpus();453 for_each_possible_cpu(cpu)
458 for_each_online_cpu(cpu)454 release_ds_buffer(cpu);
455
456 for_each_possible_cpu(cpu) {
457 /*
458 * Again, ignore errors from offline CPUs, they will no longer
459 * observe cpu_hw_events.ds and not program the DS_AREA when
460 * they come up.
461 */
459 fini_debug_store_on_cpu(cpu);462 fini_debug_store_on_cpu(cpu);
463 }
460 464
461 for_each_possible_cpu(cpu) {465 for_each_possible_cpu(cpu) {
462 release_pebs_buffer(cpu);466 release_pebs_buffer(cpu);
463 release_bts_buffer(cpu);467 release_bts_buffer(cpu);
464 release_ds_buffer(cpu);
465 }468 }
466 put_online_cpus();
467}469}
468 470
469void reserve_ds_buffers(void)471void reserve_ds_buffers(void)
@@ -483,8 +485,6 @@ void reserve_ds_buffers(void) · 13 unmodified lines
483 if (!x86_pmu.pebs)485 if (!x86_pmu.pebs)
484 pebs_err = 1;486 pebs_err = 1;
485 487
486 get_online_cpus();
487
488 for_each_possible_cpu(cpu) {488 for_each_possible_cpu(cpu) {
489 if (alloc_ds_buffer(cpu)) {489 if (alloc_ds_buffer(cpu)) {
490 bts_err = 1;490 bts_err = 1;
@@ -521,11 +521,14 @@ void reserve_ds_buffers(void) · 30 unmodified lines
521 if (x86_pmu.pebs && !pebs_err)521 if (x86_pmu.pebs && !pebs_err)
522 x86_pmu.pebs_active = 1;522 x86_pmu.pebs_active = 1;
523 523
524 for_each_online_cpu(cpu)524 for_each_possible_cpu(cpu) {
525 /*
526 * Ignores wrmsr_on_cpu() errors for offline CPUs they
527 * will get this call through intel_pmu_cpu_starting().
528 */
525 init_debug_store_on_cpu(cpu);529 init_debug_store_on_cpu(cpu);
530 }
526 }531 }
527
528 put_online_cpus();
529}532}
530 533
531/*534/*

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t