From: David Woodhouse <[email protected]> The remote kick paths (kvm_make_vcpus_request_mask(), kvm_make_all_cpus_request(), __kvm_vcpu_kick()) read READ_ONCE(vcpu->cpu) of the plane-0 vCPU. But vcpu->cpu is per plane vCPU (kvm_arch_vcpu_load() refreshes only the loaded twin's copy), while vcpu->mode is shared in kvm_vcpu_common. When the vCPU thread has migrated pCPUs while a non-zero plane was loaded, the shared mode reads IN_GUEST_MODE but the IPI goes to plane 0's stale pCPU: a waiting request such as a remote TLB flush completes while the twin keeps running on stale translations.
Read the pCPU from common->current_vcpu in both kick paths. It names the loaded twin, so its cpu field tracks where the vCPU thread runs (on x86, kvm_arch_vcpu_load() refreshes it). Found by a local Sashiko review. Signed-off-by: David Woodhouse <[email protected]> --- virt/kvm/kvm_main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d256bbf301f4..24d2291b60a2 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -244,7 +244,14 @@ static void kvm_make_vcpu_request(struct kvm_vcpu *vcpu, unsigned int req, * finalized. See kvm_vcpu_kick() for more details on handling requests. */ if (kvm_request_needs_ipi(vcpu, req)) { - cpu = READ_ONCE(vcpu->cpu); + /* + * vcpu->cpu is per plane vCPU and kvm_arch_vcpu_load() + * refreshes only the loaded twin's, so this plane's copy + * can point at a pCPU the thread has long left while a + * twin runs elsewhere. The mode just checked is shared; + * the IPI must go where the running twin actually is. + */ + cpu = READ_ONCE(READ_ONCE(vcpu->common->current_vcpu)->cpu); if (cpu != -1 && cpu != current_cpu) __cpumask_set_cpu(cpu, tmp); } @@ -4129,7 +4136,13 @@ void __kvm_vcpu_kick(struct kvm_vcpu *vcpu, bool wait) * vCPU also requires it to leave IN_GUEST_MODE. */ if (kvm_arch_vcpu_should_kick(vcpu)) { - cpu = READ_ONCE(vcpu->cpu); + /* + * Target the running twin's pCPU: this plane's vcpu->cpu + * goes stale whenever the thread migrates while another + * plane is loaded, and the IN_GUEST_MODE just observed is + * the (shared) mode of whichever twin runs. + */ + cpu = READ_ONCE(READ_ONCE(vcpu->common->current_vcpu)->cpu); if (cpu != me && (unsigned int)cpu < nr_cpu_ids && cpu_online(cpu)) { /* * Use a reschedule IPI to kick the vCPU if the caller -- 2.50.1
