diff options
author | David Vrabel <david.vrabel@citrix.com> | 2015-05-19 18:40:49 +0100 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2015-08-07 00:32:12 +0100 |
commit | 14204ab641926fca1fed8afb61dcf8f4dc382166 (patch) | |
tree | 3cdb7fd0ea0eefb20464f47bb1d2c88fcfac7354 | |
parent | fd6b72574fcdaee123768804d8f1ac28c2a5b3de (diff) | |
download | kernel_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.c | 2 | ||||
-rw-r--r-- | drivers/xen/events.c | 12 | ||||
-rw-r--r-- | include/xen/events.h | 2 |
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, |