mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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 <hw42@ipsumj.de> Signed-off-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: George Dunlap <george.dunlap@citrix.com>
This commit is contained in:
1 parent
a46126fec2
commit
573ac7b22a
1 file changed
+21
-8
+21
-8
@@ -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;
|
||||
|
||||