|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] xen/arm: Fix deadlock in gic_set_guest_irq()
commit 0ddaefffbfed3512600f67adb2a26523956cb438
Author: Oleksandr Tyshchenko <oleksandr.tyshchenko@xxxxxxxxxxxxxxx>
AuthorDate: Mon Feb 3 19:33:48 2014 +0200
Commit: Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Thu Feb 6 12:48:12 2014 +0000
xen/arm: Fix deadlock in gic_set_guest_irq()
The possible deadlock scenario is explained below:
non interrupt context: interrupt contex interrupt context
(CPU0): (CPU1):
vgic_distr_mmio_write() do_trap_irq() do_softirq()
| | |
vgic_disable_irqs() ... ...
| | |
gic_remove_from_queues() vgic_vcpu_inject_irq() vgic_vcpu_inject_irq()
| ... | |
| spin_lock(...) gic_set_guest_irq() gic_set_guest_irq()
| ... ... ...
| ... <----------------.---- spin_lock_irqsave(...) ...
| ...
<----------------.-.---------------------------spin_lock_irqsave(...)
| ... . . Oops! The lock has already taken.
| spin_unlock(...) . .
| ... . .
gic_irq_disable() . .
... . .
spin_lock(...) . .
... . .
... <----------------. .
... <------------------.
...
spin_unlock(...)
Since the gic_remove_from_queues() and gic_irq_disable() called from
non interrupt context and they acquire the same lock as gic_set_guest_irq()
which called from interrupt context we must disable interrupts in these
functions to avoid possible deadlocks.
Change-Id: Ia354d87bb44418956e30cd7e49cc76616c359cc9
Signed-off-by: Oleksandr Tyshchenko <oleksandr.tyshchenko@xxxxxxxxxxxxxxx>
Acked-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Acked-by: Julien Grall <julien.grall@xxxxxxxxxx>
Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
xen/arch/arm/gic.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index e6257a7..13bbf48 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -147,14 +147,15 @@ static void gic_irq_enable(struct irq_desc *desc)
static void gic_irq_disable(struct irq_desc *desc)
{
int irq = desc->irq;
+ unsigned long flags;
- spin_lock(&desc->lock);
+ spin_lock_irqsave(&desc->lock, flags);
spin_lock(&gic.lock);
/* Disable routing */
GICD[GICD_ICENABLER + irq / 32] = (1u << (irq % 32));
desc->status |= IRQ_DISABLED;
spin_unlock(&gic.lock);
- spin_unlock(&desc->lock);
+ spin_unlock_irqrestore(&desc->lock, flags);
}
static unsigned int gic_irq_startup(struct irq_desc *desc)
@@ -652,11 +653,12 @@ static inline void gic_add_to_lr_pending(struct vcpu *v,
unsigned int irq,
void gic_remove_from_queues(struct vcpu *v, unsigned int virtual_irq)
{
struct pending_irq *p = irq_to_pending(v, virtual_irq);
+ unsigned long flags;
- spin_lock(&gic.lock);
+ spin_lock_irqsave(&gic.lock, flags);
if ( !list_empty(&p->lr_queue) )
list_del_init(&p->lr_queue);
- spin_unlock(&gic.lock);
+ spin_unlock_irqrestore(&gic.lock, flags);
}
void gic_set_guest_irq(struct vcpu *v, unsigned int virtual_irq,
--
generated by git-patchbot for /home/xen/git/xen.git#master
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |