Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -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);