diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 9a611c79e0..017a94e311 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -1400,6 +1400,7 @@ void (pirq_cleanup_check)(struct pirq *pirq, struct domain *d) if ( radix_tree_delete(&d->pirq_tree, pirq->pirq) != pirq ) BUG(); + free_pirq_struct(pirq); } /* Flush all ready EOIs from the top of this CPU's pending-EOI stack. */ diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index a67feff989..aac7d4b93f 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -710,9 +710,14 @@ int evtchn_close(struct domain *d1, int port1, bool guest) if ( !is_hvm_domain(d1) ) pirq_guest_unbind(d1, pirq); pirq->evtchn = 0; - pirq_cleanup_check(pirq, d1); - if ( is_hvm_domain(d1) && domain_pirq_to_irq(d1, pirq->pirq) > 0 ) - unmap_domain_pirq_emuirq(d1, pirq->pirq); + if ( !is_hvm_domain(d1) || + domain_pirq_to_irq(d1, pirq->pirq) <= 0 || + unmap_domain_pirq_emuirq(d1, pirq->pirq) < 0 ) + /* + * The successful path of unmap_domain_pirq_emuirq() will have + * called pirq_cleanup_check() already. + */ + pirq_cleanup_check(pirq, d1); } unlink_pirq_port(chn1, d1->vcpu[chn1->notify_vcpu_id]); break; diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h index 17211f3399..ee45d19af8 100644 --- a/xen/include/xen/irq.h +++ b/xen/include/xen/irq.h @@ -186,7 +186,7 @@ extern struct pirq *pirq_get_info(struct domain *d, int pirq); void pirq_cleanup_check(struct pirq *pirq, struct domain *d); #define pirq_cleanup_check(pirq, d) \ - ((pirq)->evtchn ? pirq_cleanup_check(pirq, d) : (void)0) + (!(pirq)->evtchn ? pirq_cleanup_check(pirq, d) : (void)0) extern void pirq_guest_eoi(struct pirq *pirq); extern void desc_guest_eoi(struct irq_desc *desc, struct pirq *pirq);