From: Ian Campbell Date: Wed, 17 Apr 2013 12:52:34 +0000 (+0100) Subject: arm: vgic: fix race in vgic_vcpu_inject_irq X-Git-Tag: 4.3.0-rc1~68 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=e83d6b9432af603200f065b499b8e4b78e92842d;p=people%2Fiwj%2Fxen.git arm: vgic: fix race in vgic_vcpu_inject_irq The initial check for a still pending interrupt (!list_empty(&n->inflight)) needs to be covered by the vgic lock to avoid trying to insert the IRQ into the inflight list simultaneously on 2 pCPUS. Expand the area covered by the lock appropriately. Also consolidate the unlocks on the exit path into one location. Signed-off-by: Ian Campbell Acked-by: Stefano Stabellini --- diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index d9ceaaaec0..4d8da0242e 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -584,9 +584,14 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual) struct pending_irq *iter, *n = irq_to_pending(v, irq); unsigned long flags; - /* irq still pending */ + spin_lock_irqsave(&v->arch.vgic.lock, flags); + + /* irq already pending */ if (!list_empty(&n->inflight)) + { + spin_unlock_irqrestore(&v->arch.vgic.lock, flags); return; + } priority = byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, byte); @@ -601,17 +606,16 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual) if ( rank->ienable & (1 << (irq % 32)) ) gic_set_guest_irq(v, irq, GICH_LR_PENDING, priority); - spin_lock_irqsave(&v->arch.vgic.lock, flags); list_for_each_entry ( iter, &v->arch.vgic.inflight_irqs, inflight ) { if ( iter->priority > priority ) { list_add_tail(&n->inflight, &iter->inflight); - spin_unlock_irqrestore(&v->arch.vgic.lock, flags); - return; + goto out; } } list_add_tail(&n->inflight, &v->arch.vgic.inflight_irqs); +out: spin_unlock_irqrestore(&v->arch.vgic.lock, flags); /* we have a new higher priority irq, inject it into the guest */ }