From: Jan Beulich Date: Thu, 12 Oct 2017 12:37:26 +0000 (+0200) Subject: x86/IRQ: conditionally preserve irq <-> pirq mapping on map error paths X-Git-Tag: archive/raspbian/4.11.1-1+rpi1~1^2~66^2~1102 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=573ac7b22aba9e5b8d40d9cdccd744af57cd5928;p=xen.git x86/IRQ: conditionally preserve irq <-> pirq mapping on map error paths Mappings that had been set up before should not be torn down when handling unrelated errors. This is part of XSA-237. Reported-by: HW42 Signed-off-by: Jan Beulich Reviewed-by: George Dunlap --- diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 382b1f3ed2..94c1267cef 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -1259,7 +1259,8 @@ static int prepare_domain_irq_pirq(struct domain *d, int irq, int pirq, return -ENOMEM; } *pinfo = info; - return 0; + + return !!err; } static void set_domain_irq_pirq(struct domain *d, int irq, struct pirq *pirq) @@ -1302,7 +1303,10 @@ int init_domain_irq_mapping(struct domain *d) continue; err = prepare_domain_irq_pirq(d, i, i, &info); if ( err ) + { + ASSERT(err < 0); break; + } set_domain_irq_pirq(d, i, info); } @@ -1903,6 +1907,8 @@ int get_free_pirqs(struct domain *d, unsigned int nr) return -ENOSPC; } +#define MAX_MSI_IRQS 32 /* limited by MSI capability struct properties */ + int map_domain_pirq( struct domain *d, int pirq, int irq, int type, void *data) { @@ -1911,6 +1917,7 @@ int map_domain_pirq( struct pirq *info; struct irq_desc *desc; unsigned long flags; + DECLARE_BITMAP(prepared, MAX_MSI_IRQS) = {}; ASSERT(spin_is_locked(&d->event_lock)); @@ -1954,8 +1961,10 @@ int map_domain_pirq( } ret = prepare_domain_irq_pirq(d, irq, pirq, &info); - if ( ret ) + if ( ret < 0 ) goto revoke; + if ( !ret ) + __set_bit(0, prepared); desc = irq_to_desc(irq); @@ -2027,8 +2036,10 @@ int map_domain_pirq( irq = create_irq(NUMA_NO_NODE); ret = irq >= 0 ? prepare_domain_irq_pirq(d, irq, pirq + nr, &info) : irq; - if ( ret ) + if ( ret < 0 ) break; + if ( !ret ) + __set_bit(nr, prepared); msi_desc[nr].irq = irq; if ( irq_permit_access(d, irq) != 0 ) @@ -2061,15 +2072,15 @@ int map_domain_pirq( desc->msi_desc = NULL; spin_unlock_irqrestore(&desc->lock, flags); } - while ( nr-- ) + while ( nr ) { if ( irq >= 0 && irq_deny_access(d, irq) ) printk(XENLOG_G_ERR "dom%d: could not revoke access to IRQ%d (pirq %d)\n", d->domain_id, irq, pirq); - if ( info ) + if ( info && test_bit(nr, prepared) ) cleanup_domain_irq_pirq(d, irq, info); - info = pirq_info(d, pirq + nr); + info = pirq_info(d, pirq + --nr); irq = info->arch.irq; } msi_desc->irq = -1; @@ -2085,12 +2096,14 @@ int map_domain_pirq( spin_lock_irqsave(&desc->lock, flags); set_domain_irq_pirq(d, irq, info); spin_unlock_irqrestore(&desc->lock, flags); + ret = 0; } done: if ( ret ) { - cleanup_domain_irq_pirq(d, irq, info); + if ( test_bit(0, prepared) ) + cleanup_domain_irq_pirq(d, irq, info); revoke: if ( irq_deny_access(d, irq) ) printk(XENLOG_G_ERR @@ -2565,7 +2578,7 @@ static int allocate_pirq(struct domain *d, int index, int pirq, int irq, } else if ( type == MAP_PIRQ_TYPE_MULTI_MSI ) { - if ( *nr <= 0 || *nr > 32 ) + if ( *nr <= 0 || *nr > MAX_MSI_IRQS ) return -EDOM; if ( *nr != 1 && !iommu_intremap ) return -EOPNOTSUPP;