From: "Huang, Kai" <kai.huang@intel.com>
To: "seanjc@google.com" <seanjc@google.com>,
"hao_zhang_kdev@163.com" <hao_zhang_kdev@163.com>
Cc: "kvm@vger.kernel.org" <kvm@vger.kernel.org>,
"pbonzini@redhat.com" <pbonzini@redhat.com>
Subject: Re: [PATCH 1/2] KVM: x86: ioapic: Update state only after successful delivery
Date: Mon, 10 Aug 2026 08:34:47 +0000 [thread overview]
Message-ID: <c9193d0a13e39fc385699772ba58b457e41ccbac.camel@intel.com> (raw)
In-Reply-To: <anls-aUppuiFolpS@192.168.1.215>
On Mon, 2026-08-10 at 14:17 +0800, Hao Zhang wrote:
> From: Hao Zhang <zhanghao1@kylinos.cn>
>
> The I/O APIC tracks delivered interrupts in state that is later used to
> decide whether an interrupt is still pending or blocked waiting for an
> EOI.
>
> For level-triggered interrupts, remote_irr means that a local APIC
> accepted the interrupt and that the I/O APIC must wait for the
> corresponding EOI before delivering the interrupt again. For
> edge-triggered interrupts, irr_delivered is used to hide delivered
> interrupts from KVM_GET_IRQCHIP so that userspace does not reinject an
> interrupt that has already left the I/O APIC.
>
> But ioapic_service() currently updates that state before or without
> checking that interrupt delivery actually succeeded.
> kvm_irq_delivery_to_apic() can return -1 when no destination is found.
> Treating failed delivery as success can either leave a level-triggered
> pin blocked forever waiting for an EOI that will never be generated, or
> cause KVM_GET_IRQCHIP to drop an undelivered edge-triggered interrupt
> from the saved IRR state.
>
> Update I/O APIC delivery state only when the delivery result is positive,
> i.e. when at least one local APIC accepted the interrupt.
>
> Fixes: 4925663a079c ("KVM: Report IRQ injection status to userspace.")
> Fixes: 5bda6eed2e36 ("KVM: ioapic: Record edge-triggered interrupts delivery status")
> Signed-off-by: Hao Zhang <zhanghao1@kylinos.cn>
> ---
> Changes in v2:
> - Address Kai Huang's review by deferring both remote_irr and
> irr_delivered updates until interrupt delivery succeeds.
> - Extend the selftest to cover failed edge-triggered delivery and verify
> that the interrupt remains pending in IRR.
>
> Link to v1: https://lore.kernel.org/all/anSOdijwS6LBbfYJ@192.168.1.215/
>
> arch/x86/kvm/ioapic.c | 11 ++++++-----
> 1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
> index 757667fb2bfa..540e5665fbe4 100644
> --- a/arch/x86/kvm/ioapic.c
> +++ b/arch/x86/kvm/ioapic.c
> @@ -474,9 +474,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
> irqe.shorthand = APIC_DEST_NOSHORT;
> irqe.msi_redir_hint = false;
>
> - if (irqe.trig_mode == IOAPIC_EDGE_TRIG)
> - ioapic->irr_delivered |= 1 << irq;
> -
> if (irq == RTC_GSI && line_status) {
> /*
> * pending_eoi cannot ever become negative (see
> @@ -491,8 +488,12 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
> } else
> ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe);
>
> - if (ret && irqe.trig_mode == IOAPIC_LEVEL_TRIG)
> - entry->fields.remote_irr = 1;
> + if (ret > 0) {
> + if (irqe.trig_mode == IOAPIC_EDGE_TRIG)
> + ioapic->irr_delivered |= 1 << irq;
> + else if (irqe.trig_mode == IOAPIC_LEVEL_TRIG)
> + entry->fields.remote_irr = 1;
> + }
>
Ah looking at this I immediately realized I misread the code, that I thought the
irr_delivered was for level triggered as well, but actually it is for edge
triggered. I guess we both got it wrong :-)
For edge triggered IRQ the existing code is correct I believe, since once the
function is called the IRQ is considered delivered no matter whether it is
actually accepted by LAPIC. I think this exactly reflects the hardware
behaviour. (In fact, in ioapic_set_irq() you can see the IRQ is removed from
irr_delivered for edge triggered right before ioapic_service() is called.)
For level triggered, I don't see ioapic->irr is cleared by KVM, but only cleared
when ioapic_set_irq() is called with irq_level == 0. I now (AFAICT) realize it
is the right behaviour since it should be the driver which dessert the level to
stop the level-triggered IRQ.
So in short, I think your v1 is correct, and sorry about my noise. :-(
next prev parent reply other threads:[~2026-08-10 8:35 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-10 6:17 [PATCH 1/2] KVM: x86: ioapic: Update state only after successful delivery Hao Zhang
2026-08-10 6:22 ` [PATCH v2 2/2] KVM: selftests: Verify failed IOAPIC delivery preserves state Hao Zhang
2026-08-10 6:33 ` sashiko-bot
2026-08-10 6:45 ` [PATCH 1/2] KVM: x86: ioapic: Update state only after successful delivery sashiko-bot
2026-08-10 8:34 ` Huang, Kai [this message]
2026-08-10 9:39 ` hao_zhang_kdev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c9193d0a13e39fc385699772ba58b457e41ccbac.camel@intel.com \
--to=kai.huang@intel.com \
--cc=hao_zhang_kdev@163.com \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox