Commit 336f560a authored by Juergen Gross's avatar Juergen Gross

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: default avatarJuergen Gross <jgross@suse.com>
Reviewed-by: default avatarBoris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20221125063248.30256-2-jgross@suse.comSigned-off-by: default avatarJuergen Gross <jgross@suse.com>
parent 415dab3c
...@@ -21,6 +21,8 @@ void xen_smp_send_reschedule(int cpu); ...@@ -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 */ ...@@ -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) ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment