Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: X86: Yield to IPI target if necessary

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>

authored by

Wanpeng Li and committed by
Paolo Bonzini
f85f6e7b 11e34914

+34
+11
Documentation/virtual/kvm/hypercalls.txt
··· 141 141 corresponds to the APIC ID a2+1, and so on. 142 142 143 143 Returns the number of CPUs to which the IPIs were delivered successfully. 144 + 145 + 7. KVM_HC_SCHED_YIELD 146 + ------------------------ 147 + Architecture: x86 148 + Status: active 149 + Purpose: Hypercall used to yield if the IPI target vCPU is preempted 150 + 151 + a0: destination APIC ID 152 + 153 + Usage example: When sending a call-function IPI-many to vCPUs, yield if 154 + any of the IPI target vCPUs was preempted.
+1
arch/x86/include/uapi/asm/kvm_para.h
··· 30 30 #define KVM_FEATURE_ASYNC_PF_VMEXIT 10 31 31 #define KVM_FEATURE_PV_SEND_IPI 11 32 32 #define KVM_FEATURE_POLL_CONTROL 12 33 + #define KVM_FEATURE_PV_SCHED_YIELD 13 33 34 34 35 #define KVM_HINTS_REALTIME 0 35 36
+21
arch/x86/kernel/kvm.c
··· 527 527 pr_info("KVM setup pv IPIs\n"); 528 528 } 529 529 530 + static void kvm_smp_send_call_func_ipi(const struct cpumask *mask) 531 + { 532 + int cpu; 533 + 534 + native_send_call_func_ipi(mask); 535 + 536 + /* Make sure other vCPUs get a chance to run if they need to. */ 537 + for_each_cpu(cpu, mask) { 538 + if (vcpu_is_preempted(cpu)) { 539 + kvm_hypercall1(KVM_HC_SCHED_YIELD, per_cpu(x86_cpu_to_apicid, cpu)); 540 + break; 541 + } 542 + } 543 + } 544 + 530 545 static void __init kvm_smp_prepare_cpus(unsigned int max_cpus) 531 546 { 532 547 native_smp_prepare_cpus(max_cpus); ··· 653 638 #ifdef CONFIG_SMP 654 639 smp_ops.smp_prepare_cpus = kvm_smp_prepare_cpus; 655 640 smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu; 641 + if (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) && 642 + !kvm_para_has_hint(KVM_HINTS_REALTIME) && 643 + kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) { 644 + smp_ops.send_call_func_ipi = kvm_smp_send_call_func_ipi; 645 + pr_info("KVM setup pv sched yield\n"); 646 + } 656 647 if (cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/kvm:online", 657 648 kvm_cpu_online, kvm_cpu_down_prepare) < 0) 658 649 pr_err("kvm_guest: Failed to install cpu hotplug callbacks\n");
+1
include/uapi/linux/kvm_para.h
··· 28 28 #define KVM_HC_MIPS_CONSOLE_OUTPUT 8 29 29 #define KVM_HC_CLOCK_PAIRING 9 30 30 #define KVM_HC_SEND_IPI 10 31 + #define KVM_HC_SCHED_YIELD 11 31 32 32 33 /* 33 34 * hypercalls use architecture specific