Commit 4009b249 authored by Paolo Bonzini's avatar Paolo Bonzini

KVM: ioapic: try to recover if pending_eoi goes out of range

The RTC tracking code tracks the cardinality of rtc_status.dest_map
into rtc_status.pending_eoi.  It has some WARN_ONs that trigger if
pending_eoi ever becomes negative; however, these do not do anything
to recover, and it bad things will happen soon after they trigger.

When the next RTC interrupt is triggered, rtc_check_coalesced() will
return false, but ioapic_service will find pending_eoi != 0 and
do a BUG_ON.  To avoid this, should pending_eoi ever be nonzero,
call kvm_rtc_eoi_tracking_restore_all to recompute a correct
dest_map and pending_eoi.
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 5678de3f
...@@ -97,6 +97,14 @@ static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic) ...@@ -97,6 +97,14 @@ static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)
bitmap_zero(ioapic->rtc_status.dest_map, KVM_MAX_VCPUS); bitmap_zero(ioapic->rtc_status.dest_map, KVM_MAX_VCPUS);
} }
static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic);
static void rtc_status_pending_eoi_check_valid(struct kvm_ioapic *ioapic)
{
if (WARN_ON(ioapic->rtc_status.pending_eoi < 0))
kvm_rtc_eoi_tracking_restore_all(ioapic);
}
static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu) static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)
{ {
bool new_val, old_val; bool new_val, old_val;
...@@ -120,9 +128,8 @@ static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu) ...@@ -120,9 +128,8 @@ static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)
} else { } else {
__clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map); __clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);
ioapic->rtc_status.pending_eoi--; ioapic->rtc_status.pending_eoi--;
rtc_status_pending_eoi_check_valid(ioapic);
} }
WARN_ON(ioapic->rtc_status.pending_eoi < 0);
} }
void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu) void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)
...@@ -149,10 +156,10 @@ static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic) ...@@ -149,10 +156,10 @@ static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic)
static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu) static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu)
{ {
if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map)) if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map)) {
--ioapic->rtc_status.pending_eoi; --ioapic->rtc_status.pending_eoi;
rtc_status_pending_eoi_check_valid(ioapic);
WARN_ON(ioapic->rtc_status.pending_eoi < 0); }
} }
static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic) static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic)
...@@ -353,6 +360,12 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status) ...@@ -353,6 +360,12 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
ioapic->irr &= ~(1 << irq); ioapic->irr &= ~(1 << irq);
if (irq == RTC_GSI && line_status) { if (irq == RTC_GSI && line_status) {
/*
* pending_eoi cannot ever become negative (see
* rtc_status_pending_eoi_check_valid) and the caller
* ensures that it is only called if it is >= zero, namely
* if rtc_irq_check_coalesced returns false).
*/
BUG_ON(ioapic->rtc_status.pending_eoi != 0); BUG_ON(ioapic->rtc_status.pending_eoi != 0);
ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
ioapic->rtc_status.dest_map); ioapic->rtc_status.dest_map);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment