aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@citrix.com>2015-05-19 18:40:49 +0100
committerBen Hutchings <ben@decadent.org.uk>2015-08-07 00:32:12 +0100
commit14204ab641926fca1fed8afb61dcf8f4dc382166 (patch)
tree3cdb7fd0ea0eefb20464f47bb1d2c88fcfac7354
parentfd6b72574fcdaee123768804d8f1ac28c2a5b3de (diff)
downloadkernel_samsung_smdk4412-14204ab641926fca1fed8afb61dcf8f4dc382166.zip
kernel_samsung_smdk4412-14204ab641926fca1fed8afb61dcf8f4dc382166.tar.gz
kernel_samsung_smdk4412-14204ab641926fca1fed8afb61dcf8f4dc382166.tar.bz2
xen/events: don't bind non-percpu VIRQs with percpu chip
commit 77bb3dfdc0d554befad58fdefbc41be5bc3ed38a upstream. A non-percpu VIRQ (e.g., VIRQ_CONSOLE) may be freed on a different VCPU than it is bound to. This can result in a race between handle_percpu_irq() and removing the action in __free_irq() because handle_percpu_irq() does not take desc->lock. The interrupt handler sees a NULL action and oopses. Only use the percpu chip/handler for per-CPU VIRQs (like VIRQ_TIMER). # cat /proc/interrupts | grep virq 40: 87246 0 xen-percpu-virq timer0 44: 0 0 xen-percpu-virq debug0 47: 0 20995 xen-percpu-virq timer1 51: 0 0 xen-percpu-virq debug1 69: 0 0 xen-dyn-virq xen-pcpu 74: 0 0 xen-dyn-virq mce 75: 29 0 xen-dyn-virq hvc_console Signed-off-by: David Vrabel <david.vrabel@citrix.com> [bwh: Backported to 3.2: adjust filename, context, indentation] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--drivers/tty/hvc/hvc_xen.c2
-rw-r--r--drivers/xen/events.c12
-rw-r--r--include/xen/events.h2
3 files changed, 10 insertions, 6 deletions
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 52fdf60..df8f8e0 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -167,7 +167,7 @@ static int __init xen_hvc_init(void)
if (xen_initial_domain()) {
ops = &dom0_hvc_ops;
- xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
+ xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);
} else {
if (!xen_start_info->console.domU.evtchn)
return -ENODEV;
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index f6227cc..bcf7711 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -895,7 +895,7 @@ static int find_virq(unsigned int virq, unsigned int cpu)
return rc;
}
-int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu)
{
struct evtchn_bind_virq bind_virq;
int evtchn, irq, ret;
@@ -909,8 +909,12 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
if (irq == -1)
goto out;
- irq_set_chip_and_handler_name(irq, &xen_percpu_chip,
- handle_percpu_irq, "virq");
+ if (percpu)
+ irq_set_chip_and_handler_name(irq, &xen_percpu_chip,
+ handle_percpu_irq, "virq");
+ else
+ irq_set_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_edge_irq, "virq");
bind_virq.virq = virq;
bind_virq.vcpu = cpu;
@@ -1023,7 +1027,7 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
{
int irq, retval;
- irq = bind_virq_to_irq(virq, cpu);
+ irq = bind_virq_to_irq(virq, cpu, irqflags & IRQF_PERCPU);
if (irq < 0)
return irq;
retval = request_irq(irq, handler, irqflags, devname, dev_id);
diff --git a/include/xen/events.h b/include/xen/events.h
index 8f3d622..89b672d 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -12,7 +12,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
irq_handler_t handler,
unsigned long irqflags, const char *devname,
void *dev_id);
-int bind_virq_to_irq(unsigned int virq, unsigned int cpu);
+int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu);
int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
irq_handler_t handler,
unsigned long irqflags, const char *devname,