xen/events: don't bind non-percpu VIRQs with percpu chip
commit 77bb3dfdc0
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
c018f62178
commit
8d3cbb9096
|
@ -289,7 +289,7 @@ static int xen_initial_domain_console_init(void)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
|
||||
info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);
|
||||
info->vtermno = HVC_COOKIE;
|
||||
|
||||
spin_lock(&xencons_lock);
|
||||
|
|
|
@ -973,7 +973,7 @@ unsigned xen_evtchn_nr_channels(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(xen_evtchn_nr_channels);
|
||||
|
||||
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;
|
||||
|
@ -987,8 +987,12 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
|
|||
if (irq < 0)
|
||||
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;
|
||||
|
@ -1078,7 +1082,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);
|
||||
|
|
|
@ -14,7 +14,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,
|
||||
|
|
Loading…
Reference in New Issue