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: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
5678de3f15
commit
4009b2499e
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bool new_val, old_val;
|
||||
|
@ -120,9 +128,8 @@ static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)
|
|||
} else {
|
||||
__clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
|
||||
WARN_ON(ioapic->rtc_status.pending_eoi < 0);
|
||||
rtc_status_pending_eoi_check_valid(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)
|
|||
ioapic->irr &= ~(1 << irq);
|
||||
|
||||
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);
|
||||
ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
|
||||
ioapic->rtc_status.dest_map);
|
||||
|
|
Loading…
Reference in New Issue