forked from mirrors/linux
		
	x86/xen: don't let xen_pv_play_dead() return
A function called via the paravirt play_dead() hook should not return to the caller. xen_pv_play_dead() has a problem in this regard, as it currently will return in case an offlined cpu is brought to life again. This can be changed only by doing basically a longjmp() to cpu_bringup_and_idle(), as the hypercall for bringing down the cpu will just return when the cpu is coming up again. Just re-initializing the cpu isn't possible, as the Xen hypervisor will deny that operation. So introduce xen_cpu_bringup_again() resetting the stack and calling cpu_bringup_and_idle(), which can be called after HYPERVISOR_vcpu_op() in xen_pv_play_dead(). Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20221125063248.30256-2-jgross@suse.com Signed-off-by: Juergen Gross <jgross@suse.com>
This commit is contained in:
		
							parent
							
								
									415dab3c17
								
							
						
					
					
						commit
						336f560a89
					
				
					 3 changed files with 11 additions and 11 deletions
				
			
		|  | @ -21,6 +21,8 @@ void xen_smp_send_reschedule(int cpu); | ||||||
| void xen_smp_send_call_function_ipi(const struct cpumask *mask); | void xen_smp_send_call_function_ipi(const struct cpumask *mask); | ||||||
| void xen_smp_send_call_function_single_ipi(int cpu); | void xen_smp_send_call_function_single_ipi(int cpu); | ||||||
| 
 | 
 | ||||||
|  | void xen_cpu_bringup_again(unsigned long stack); | ||||||
|  | 
 | ||||||
| struct xen_common_irq { | struct xen_common_irq { | ||||||
| 	int irq; | 	int irq; | ||||||
| 	char *name; | 	char *name; | ||||||
|  |  | ||||||
|  | @ -385,17 +385,8 @@ static void xen_pv_play_dead(void) /* used only with HOTPLUG_CPU */ | ||||||
| { | { | ||||||
| 	play_dead_common(); | 	play_dead_common(); | ||||||
| 	HYPERVISOR_vcpu_op(VCPUOP_down, xen_vcpu_nr(smp_processor_id()), NULL); | 	HYPERVISOR_vcpu_op(VCPUOP_down, xen_vcpu_nr(smp_processor_id()), NULL); | ||||||
| 	cpu_bringup(); | 	xen_cpu_bringup_again((unsigned long)task_pt_regs(current)); | ||||||
| 	/*
 | 	BUG(); | ||||||
| 	 * commit 4b0c0f294 (tick: Cleanup NOHZ per cpu data on cpu down) |  | ||||||
| 	 * clears certain data that the cpu_idle loop (which called us |  | ||||||
| 	 * and that we return from) expects. The only way to get that |  | ||||||
| 	 * data back is to call: |  | ||||||
| 	 */ |  | ||||||
| 	tick_nohz_idle_enter(); |  | ||||||
| 	tick_nohz_idle_stop_tick_protected(); |  | ||||||
| 
 |  | ||||||
| 	cpuhp_online_idle(CPUHP_AP_ONLINE_IDLE); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #else /* !CONFIG_HOTPLUG_CPU */ | #else /* !CONFIG_HOTPLUG_CPU */ | ||||||
|  |  | ||||||
|  | @ -76,6 +76,13 @@ SYM_CODE_START(asm_cpu_bringup_and_idle) | ||||||
| 
 | 
 | ||||||
| 	call cpu_bringup_and_idle | 	call cpu_bringup_and_idle | ||||||
| SYM_CODE_END(asm_cpu_bringup_and_idle) | SYM_CODE_END(asm_cpu_bringup_and_idle) | ||||||
|  | 
 | ||||||
|  | SYM_CODE_START(xen_cpu_bringup_again) | ||||||
|  | 	UNWIND_HINT_FUNC | ||||||
|  | 	mov	%rdi, %rsp | ||||||
|  | 	UNWIND_HINT_REGS | ||||||
|  | 	call	cpu_bringup_and_idle | ||||||
|  | SYM_CODE_END(xen_cpu_bringup_again) | ||||||
| .popsection | .popsection | ||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Juergen Gross
						Juergen Gross