forked from mirrors/linux
		
	perf,x86: fix kernel crash with PEBS/BTS after suspend/resume
This patch fixes a kernel crash when using precise sampling (PEBS) after a suspend/resume. Turns out the CPU notifier code is not invoked on CPU0 (BP). Therefore, the DS_AREA (used by PEBS) is not restored properly by the kernel and keeps it power-on/resume value of 0 causing any PEBS measurement to crash when running on CPU0. The workaround is to add a hook in the actual resume code to restore the DS Area MSR value. It is invoked for all CPUS. So for all but CPU0, the DS_AREA will be restored twice but this is harmless. Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Stephane Eranian <eranian@google.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									a2362d2476
								
							
						
					
					
						commit
						1d9d8639c0
					
				
					 3 changed files with 12 additions and 0 deletions
				
			
		|  | @ -729,3 +729,11 @@ void intel_ds_init(void) | |||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void perf_restore_debug_store(void) | ||||
| { | ||||
| 	if (!x86_pmu.bts && !x86_pmu.pebs) | ||||
| 		return; | ||||
| 
 | ||||
| 	init_debug_store_on_cpu(smp_processor_id()); | ||||
| } | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
| #include <linux/suspend.h> | ||||
| #include <linux/export.h> | ||||
| #include <linux/smp.h> | ||||
| #include <linux/perf_event.h> | ||||
| 
 | ||||
| #include <asm/pgtable.h> | ||||
| #include <asm/proto.h> | ||||
|  | @ -228,6 +229,7 @@ static void __restore_processor_state(struct saved_context *ctxt) | |||
| 	do_fpu_end(); | ||||
| 	x86_platform.restore_sched_clock_state(); | ||||
| 	mtrr_bp_restore(); | ||||
| 	perf_restore_debug_store(); | ||||
| } | ||||
| 
 | ||||
| /* Needed by apm.c */ | ||||
|  |  | |||
|  | @ -758,6 +758,7 @@ extern void perf_event_enable(struct perf_event *event); | |||
| extern void perf_event_disable(struct perf_event *event); | ||||
| extern int __perf_event_disable(void *info); | ||||
| extern void perf_event_task_tick(void); | ||||
| extern void perf_restore_debug_store(void); | ||||
| #else | ||||
| static inline void | ||||
| perf_event_task_sched_in(struct task_struct *prev, | ||||
|  | @ -797,6 +798,7 @@ static inline void perf_event_enable(struct perf_event *event)		{ } | |||
| static inline void perf_event_disable(struct perf_event *event)		{ } | ||||
| static inline int __perf_event_disable(void *info)			{ return -1; } | ||||
| static inline void perf_event_task_tick(void)				{ } | ||||
| static inline void perf_restore_debug_store(void)			{ } | ||||
| #endif | ||||
| 
 | ||||
| #define perf_output_put(handle, x) perf_output_copy((handle), &(x), sizeof(x)) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Stephane Eranian
						Stephane Eranian