mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	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. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
		
							parent
							
								
									0c7296cad6
								
							
						
					
					
						commit
						efe951d3de
					
				
					 1 changed files with 18 additions and 15 deletions
				
			
		|  | @ -372,10 +372,9 @@ static int alloc_pebs_buffer(int cpu) | |||
| static void release_pebs_buffer(int cpu) | ||||
| { | ||||
| 	struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu); | ||||
| 	struct debug_store *ds = hwev->ds; | ||||
| 	void *cea; | ||||
| 
 | ||||
| 	if (!ds || !x86_pmu.pebs) | ||||
| 	if (!x86_pmu.pebs) | ||||
| 		return; | ||||
| 
 | ||||
| 	kfree(per_cpu(insn_buffer, cpu)); | ||||
|  | @ -384,7 +383,6 @@ static void release_pebs_buffer(int cpu) | |||
| 	/* Clear the fixmap */ | ||||
| 	cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.pebs_buffer; | ||||
| 	ds_clear_cea(cea, x86_pmu.pebs_buffer_size); | ||||
| 	ds->pebs_buffer_base = 0; | ||||
| 	dsfree_pages(hwev->ds_pebs_vaddr, x86_pmu.pebs_buffer_size); | ||||
| 	hwev->ds_pebs_vaddr = NULL; | ||||
| } | ||||
|  | @ -419,16 +417,14 @@ static int alloc_bts_buffer(int cpu) | |||
| static void release_bts_buffer(int cpu) | ||||
| { | ||||
| 	struct cpu_hw_events *hwev = per_cpu_ptr(&cpu_hw_events, cpu); | ||||
| 	struct debug_store *ds = hwev->ds; | ||||
| 	void *cea; | ||||
| 
 | ||||
| 	if (!ds || !x86_pmu.bts) | ||||
| 	if (!x86_pmu.bts) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* Clear the fixmap */ | ||||
| 	cea = &get_cpu_entry_area(cpu)->cpu_debug_buffers.bts_buffer; | ||||
| 	ds_clear_cea(cea, BTS_BUFFER_SIZE); | ||||
| 	ds->bts_buffer_base = 0; | ||||
| 	dsfree_pages(hwev->ds_bts_vaddr, BTS_BUFFER_SIZE); | ||||
| 	hwev->ds_bts_vaddr = NULL; | ||||
| } | ||||
|  | @ -454,16 +450,22 @@ void release_ds_buffers(void) | |||
| 	if (!x86_pmu.bts && !x86_pmu.pebs) | ||||
| 		return; | ||||
| 
 | ||||
| 	get_online_cpus(); | ||||
| 	for_each_online_cpu(cpu) | ||||
| 	for_each_possible_cpu(cpu) | ||||
| 		release_ds_buffer(cpu); | ||||
| 
 | ||||
| 	for_each_possible_cpu(cpu) { | ||||
| 		/*
 | ||||
| 		 * Again, ignore errors from offline CPUs, they will no longer | ||||
| 		 * observe cpu_hw_events.ds and not program the DS_AREA when | ||||
| 		 * they come up. | ||||
| 		 */ | ||||
| 		fini_debug_store_on_cpu(cpu); | ||||
| 	} | ||||
| 
 | ||||
| 	for_each_possible_cpu(cpu) { | ||||
| 		release_pebs_buffer(cpu); | ||||
| 		release_bts_buffer(cpu); | ||||
| 		release_ds_buffer(cpu); | ||||
| 	} | ||||
| 	put_online_cpus(); | ||||
| } | ||||
| 
 | ||||
| void reserve_ds_buffers(void) | ||||
|  | @ -483,8 +485,6 @@ void reserve_ds_buffers(void) | |||
| 	if (!x86_pmu.pebs) | ||||
| 		pebs_err = 1; | ||||
| 
 | ||||
| 	get_online_cpus(); | ||||
| 
 | ||||
| 	for_each_possible_cpu(cpu) { | ||||
| 		if (alloc_ds_buffer(cpu)) { | ||||
| 			bts_err = 1; | ||||
|  | @ -521,11 +521,14 @@ void reserve_ds_buffers(void) | |||
| 		if (x86_pmu.pebs && !pebs_err) | ||||
| 			x86_pmu.pebs_active = 1; | ||||
| 
 | ||||
| 		for_each_online_cpu(cpu) | ||||
| 		for_each_possible_cpu(cpu) { | ||||
| 			/*
 | ||||
| 			 * Ignores wrmsr_on_cpu() errors for offline CPUs they | ||||
| 			 * will get this call through intel_pmu_cpu_starting(). | ||||
| 			 */ | ||||
| 			init_debug_store_on_cpu(cpu); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	put_online_cpus(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Peter Zijlstra
						Peter Zijlstra