]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
KVM: X86: Yield to IPI target if necessary
authorWanpeng Li <wanpengli@tencent.com>
Tue, 11 Jun 2019 12:23:48 +0000 (20:23 +0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 2 Jul 2019 16:56:01 +0000 (18:56 +0200)
When sending a call-function IPI-many to vCPUs, yield if any of
the IPI target vCPUs was preempted, we just select the first
preempted target vCPU which we found since the state of target
vCPUs can change underneath and to avoid race conditions.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Cc: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Wanpeng Li <wanpengli@tencent.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Documentation/virtual/kvm/hypercalls.txt
arch/x86/include/uapi/asm/kvm_para.h
arch/x86/kernel/kvm.c
include/uapi/linux/kvm_para.h

index da24c138c8d131bea63aeb652af3d6fc373514ef..da210651f71486dde5e27bcbee3ab62aefa25080 100644 (file)
@@ -141,3 +141,14 @@ a0 corresponds to the APIC ID in the third argument (a2), bit 1
 corresponds to the APIC ID a2+1, and so on.
 
 Returns the number of CPUs to which the IPIs were delivered successfully.
+
+7. KVM_HC_SCHED_YIELD
+------------------------
+Architecture: x86
+Status: active
+Purpose: Hypercall used to yield if the IPI target vCPU is preempted
+
+a0: destination APIC ID
+
+Usage example: When sending a call-function IPI-many to vCPUs, yield if
+any of the IPI target vCPUs was preempted.
index 21d5f0240595f51b3514e833b674cfc538161e4c..2a8e0b6b9805a4c5f84ca4b2bf0c0e4ae74fcc02 100644 (file)
@@ -30,6 +30,7 @@
 #define KVM_FEATURE_ASYNC_PF_VMEXIT    10
 #define KVM_FEATURE_PV_SEND_IPI        11
 #define KVM_FEATURE_POLL_CONTROL       12
+#define KVM_FEATURE_PV_SCHED_YIELD     13
 
 #define KVM_HINTS_REALTIME      0
 
index 5169b8cc35bb2d99c322c3e607d9813e083659fc..82caf01b63dd964148bbef9c8a5e2d920b802d4c 100644 (file)
@@ -527,6 +527,21 @@ static void kvm_setup_pv_ipi(void)
        pr_info("KVM setup pv IPIs\n");
 }
 
+static void kvm_smp_send_call_func_ipi(const struct cpumask *mask)
+{
+       int cpu;
+
+       native_send_call_func_ipi(mask);
+
+       /* Make sure other vCPUs get a chance to run if they need to. */
+       for_each_cpu(cpu, mask) {
+               if (vcpu_is_preempted(cpu)) {
+                       kvm_hypercall1(KVM_HC_SCHED_YIELD, per_cpu(x86_cpu_to_apicid, cpu));
+                       break;
+               }
+       }
+}
+
 static void __init kvm_smp_prepare_cpus(unsigned int max_cpus)
 {
        native_smp_prepare_cpus(max_cpus);
@@ -638,6 +653,12 @@ static void __init kvm_guest_init(void)
 #ifdef CONFIG_SMP
        smp_ops.smp_prepare_cpus = kvm_smp_prepare_cpus;
        smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
+       if (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
+           !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
+           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
+               smp_ops.send_call_func_ipi = kvm_smp_send_call_func_ipi;
+               pr_info("KVM setup pv sched yield\n");
+       }
        if (cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/kvm:online",
                                      kvm_cpu_online, kvm_cpu_down_prepare) < 0)
                pr_err("kvm_guest: Failed to install cpu hotplug callbacks\n");
index 6c0ce49931e500da0759804d9c54e1ed4687fc5e..8b86609849b9fa2571f840cf904265f0cd95ca11 100644 (file)
@@ -28,6 +28,7 @@
 #define KVM_HC_MIPS_CONSOLE_OUTPUT     8
 #define KVM_HC_CLOCK_PAIRING           9
 #define KVM_HC_SEND_IPI                10
+#define KVM_HC_SCHED_YIELD             11
 
 /*
  * hypercalls use architecture specific