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


Reply via email to