KVM: Fix race between timer migration and vcpu migration

A guest vcpu instance can be scheduled to a different physical CPU
between the test for KVM_REQ_MIGRATE_TIMER and local_irq_disable().

If that happens, the timer will only be migrated to the current pCPU on
the next exit, meaning that guest LAPIC timer event can be delayed until
a host interrupt is triggered.

Fix it by cancelling guest entry if any vcpu request is pending.  This
has the side effect of nicely consolidating vcpu->requests checks.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
Marcelo Tosatti 2008-06-06 16:37:35 -03:00 коммит произвёл Avi Kivity
Родитель 62786b9e81
Коммит d4acf7e7ab
1 изменённых файлов: 3 добавлений и 12 удалений

Просмотреть файл

@ -2759,6 +2759,8 @@ again:
if (vcpu->requests) { if (vcpu->requests) {
if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests)) if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests))
__kvm_migrate_timers(vcpu); __kvm_migrate_timers(vcpu);
if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
kvm_x86_ops->tlb_flush(vcpu);
if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS, if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS,
&vcpu->requests)) { &vcpu->requests)) {
kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS; kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS;
@ -2781,21 +2783,13 @@ again:
local_irq_disable(); local_irq_disable();
if (need_resched()) { if (vcpu->requests || need_resched()) {
local_irq_enable(); local_irq_enable();
preempt_enable(); preempt_enable();
r = 1; r = 1;
goto out; goto out;
} }
if (vcpu->requests)
if (test_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) {
local_irq_enable();
preempt_enable();
r = 1;
goto out;
}
if (signal_pending(current)) { if (signal_pending(current)) {
local_irq_enable(); local_irq_enable();
preempt_enable(); preempt_enable();
@ -2825,9 +2819,6 @@ again:
kvm_guest_enter(); kvm_guest_enter();
if (vcpu->requests)
if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
kvm_x86_ops->tlb_flush(vcpu);
KVMTRACE_0D(VMENTRY, vcpu, entryexit); KVMTRACE_0D(VMENTRY, vcpu, entryexit);
kvm_x86_ops->run(vcpu, kvm_run); kvm_x86_ops->run(vcpu, kvm_run);