98 lines
3.2 KiB
Diff
98 lines
3.2 KiB
Diff
From: Roger Pau Monne <roger.pau@citrix.com>
|
|
Subject: x86/dpci: do not remove pirqs from domain tree on unbind
|
|
|
|
A fix for a previous issue removed the pirqs from the domain tree when
|
|
they are unbound in order to prevent shared pirqs from triggering a
|
|
BUG_ON in __pirq_guest_unbind if they are unbound multiple times. That
|
|
caused free_domain_pirqs to no longer unmap the pirqs because they
|
|
are gone from the domain pirq tree, thus leaving stale unbound pirqs
|
|
after domain destruction if the domain had mapped dpci pirqs after
|
|
shutdown.
|
|
|
|
Take a different approach to fix the original issue, instead of
|
|
removing the pirq from d->pirq_tree clear the flags of the dpci pirq
|
|
struct to signal that the pirq is now unbound. This prevents calling
|
|
pirq_guest_unbind multiple times for the same pirq without having to
|
|
remove it from the domain pirq tree.
|
|
|
|
This is XSA-360.
|
|
|
|
Fixes: 5b58dad089 ('x86/pass-through: avoid double IRQ unbind during domain cleanup')
|
|
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
|
|
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
|
|
|
--- a/xen/arch/x86/irq.c
|
|
+++ b/xen/arch/x86/irq.c
|
|
@@ -1331,7 +1331,7 @@ void (pirq_cleanup_check)(struct pirq *p
|
|
}
|
|
|
|
if ( radix_tree_delete(&d->pirq_tree, pirq->pirq) != pirq )
|
|
- BUG_ON(!d->is_dying);
|
|
+ BUG();
|
|
}
|
|
|
|
/* Flush all ready EOIs from the top of this CPU's pending-EOI stack. */
|
|
--- a/xen/drivers/passthrough/pci.c
|
|
+++ b/xen/drivers/passthrough/pci.c
|
|
@@ -862,6 +862,10 @@ static int pci_clean_dpci_irq(struct dom
|
|
{
|
|
struct dev_intx_gsi_link *digl, *tmp;
|
|
|
|
+ if ( !pirq_dpci->flags )
|
|
+ /* Already processed. */
|
|
+ return 0;
|
|
+
|
|
pirq_guest_unbind(d, dpci_pirq(pirq_dpci));
|
|
|
|
if ( pt_irq_need_timer(pirq_dpci->flags) )
|
|
@@ -872,15 +876,10 @@ static int pci_clean_dpci_irq(struct dom
|
|
list_del(&digl->list);
|
|
xfree(digl);
|
|
}
|
|
+ /* Note the pirq is now unbound. */
|
|
+ pirq_dpci->flags = 0;
|
|
|
|
- radix_tree_delete(&d->pirq_tree, dpci_pirq(pirq_dpci)->pirq);
|
|
-
|
|
- if ( !pt_pirq_softirq_active(pirq_dpci) )
|
|
- return 0;
|
|
-
|
|
- domain_get_irq_dpci(d)->pending_pirq_dpci = pirq_dpci;
|
|
-
|
|
- return -ERESTART;
|
|
+ return pt_pirq_softirq_active(pirq_dpci) ? -ERESTART : 0;
|
|
}
|
|
|
|
static int pci_clean_dpci_irqs(struct domain *d)
|
|
@@ -897,18 +896,8 @@ static int pci_clean_dpci_irqs(struct do
|
|
hvm_irq_dpci = domain_get_irq_dpci(d);
|
|
if ( hvm_irq_dpci != NULL )
|
|
{
|
|
- int ret = 0;
|
|
-
|
|
- if ( hvm_irq_dpci->pending_pirq_dpci )
|
|
- {
|
|
- if ( pt_pirq_softirq_active(hvm_irq_dpci->pending_pirq_dpci) )
|
|
- ret = -ERESTART;
|
|
- else
|
|
- hvm_irq_dpci->pending_pirq_dpci = NULL;
|
|
- }
|
|
+ int ret = pt_pirq_iterate(d, pci_clean_dpci_irq, NULL);
|
|
|
|
- if ( !ret )
|
|
- ret = pt_pirq_iterate(d, pci_clean_dpci_irq, NULL);
|
|
if ( ret )
|
|
{
|
|
spin_unlock(&d->event_lock);
|
|
--- a/xen/include/asm-x86/hvm/irq.h
|
|
+++ b/xen/include/asm-x86/hvm/irq.h
|
|
@@ -160,8 +160,6 @@ struct hvm_irq_dpci {
|
|
DECLARE_BITMAP(isairq_map, NR_ISAIRQS);
|
|
/* Record of mapped Links */
|
|
uint8_t link_cnt[NR_LINK];
|
|
- /* Clean up: Entry with a softirq invocation pending / in progress. */
|
|
- struct hvm_pirq_dpci *pending_pirq_dpci;
|
|
};
|
|
|
|
/* Machine IRQ to guest device/intx mapping. */
|