diff mbox

[SRU,Wily,1/1] x86/ioapic: Disable interrupts when re-routing legacy IRQs

Message ID 6d7e52f46daa71df5e4c05a6fbfb661bf0eb6ba6.1447867806.git.joseph.salisbury@canonical.com
State New
Headers show

Commit Message

Joseph Salisbury Nov. 20, 2015, 8:32 p.m. UTC
From: Vitaly Kuznetsov <vkuznets@redhat.com>

BugLink: http://bugs.launchpad.net/bugs/1508593

A sporadic hang with consequent crash is observed when booting Hyper-V Gen1
guests:

 Call Trace:
  <IRQ>
  [<ffffffff810ab68d>] ? trace_hardirqs_off+0xd/0x10
  [<ffffffff8107b616>] queue_work_on+0x46/0x90
  [<ffffffff81365696>] ? add_interrupt_randomness+0x176/0x1d0
  ...
  <EOI>
  [<ffffffff81471ddb>] ? _raw_spin_unlock_irqrestore+0x3b/0x60
  [<ffffffff810c295e>] __irq_put_desc_unlock+0x1e/0x40
  [<ffffffff810c5c35>] irq_modify_status+0xb5/0xd0
  [<ffffffff8104adbb>] mp_register_handler+0x4b/0x70
  [<ffffffff8104c55a>] mp_irqdomain_alloc+0x1ea/0x2a0
  [<ffffffff810c7f10>] irq_domain_alloc_irqs_recursive+0x40/0xa0
  [<ffffffff810c860c>] __irq_domain_alloc_irqs+0x13c/0x2b0
  [<ffffffff8104b070>] alloc_isa_irq_from_domain.isra.1+0xc0/0xe0
  [<ffffffff8104bfa5>] mp_map_pin_to_irq+0x165/0x2d0
  [<ffffffff8104c157>] pin_2_irq+0x47/0x80
  [<ffffffff81744253>] setup_IO_APIC+0xfe/0x802
  ...
  [<ffffffff814631c0>] ? rest_init+0x140/0x140

The issue is easily reproducible with a simple instrumentation: if
mdelay(10) is put between mp_setup_entry() and mp_register_handler() calls
in mp_irqdomain_alloc() Hyper-V guest always fails to boot when re-routing
IRQ0. The issue seems to be caused by the fact that we don't disable
interrupts while doing IOPIC programming for legacy IRQs and IRQ0 actually
happens.

Protect the setup sequence against concurrent interrupts.

[ tglx: Make the protection unconditional and not only for legacy
  	interrupts ]

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Cc: Jiang Liu <jiang.liu@linux.intel.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Link: http://lkml.kernel.org/r/1444930943-19336-1-git-send-email-vkuznets@redhat.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
(cherry picked from commit c0ff971ef9acacd4d2caa508e444edad958dead9)
Signed-off-by: Joseph Salisbury <joseph.salisbury@canonical.com>
---
 arch/x86/kernel/apic/io_apic.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Tim Gardner Nov. 20, 2015, 8:47 p.m. UTC | #1
Looks safe, clean cherry pick
Andy Whitcroft Nov. 21, 2015, 11:13 a.m. UTC | #2
On Fri, Nov 20, 2015 at 03:32:18PM -0500, Joseph Salisbury wrote:
> From: Vitaly Kuznetsov <vkuznets@redhat.com>
> 
> BugLink: http://bugs.launchpad.net/bugs/1508593
> 
> A sporadic hang with consequent crash is observed when booting Hyper-V Gen1
> guests:
> 
>  Call Trace:
>   <IRQ>
>   [<ffffffff810ab68d>] ? trace_hardirqs_off+0xd/0x10
>   [<ffffffff8107b616>] queue_work_on+0x46/0x90
>   [<ffffffff81365696>] ? add_interrupt_randomness+0x176/0x1d0
>   ...
>   <EOI>
>   [<ffffffff81471ddb>] ? _raw_spin_unlock_irqrestore+0x3b/0x60
>   [<ffffffff810c295e>] __irq_put_desc_unlock+0x1e/0x40
>   [<ffffffff810c5c35>] irq_modify_status+0xb5/0xd0
>   [<ffffffff8104adbb>] mp_register_handler+0x4b/0x70
>   [<ffffffff8104c55a>] mp_irqdomain_alloc+0x1ea/0x2a0
>   [<ffffffff810c7f10>] irq_domain_alloc_irqs_recursive+0x40/0xa0
>   [<ffffffff810c860c>] __irq_domain_alloc_irqs+0x13c/0x2b0
>   [<ffffffff8104b070>] alloc_isa_irq_from_domain.isra.1+0xc0/0xe0
>   [<ffffffff8104bfa5>] mp_map_pin_to_irq+0x165/0x2d0
>   [<ffffffff8104c157>] pin_2_irq+0x47/0x80
>   [<ffffffff81744253>] setup_IO_APIC+0xfe/0x802
>   ...
>   [<ffffffff814631c0>] ? rest_init+0x140/0x140
> 
> The issue is easily reproducible with a simple instrumentation: if
> mdelay(10) is put between mp_setup_entry() and mp_register_handler() calls
> in mp_irqdomain_alloc() Hyper-V guest always fails to boot when re-routing
> IRQ0. The issue seems to be caused by the fact that we don't disable
> interrupts while doing IOPIC programming for legacy IRQs and IRQ0 actually
> happens.
> 
> Protect the setup sequence against concurrent interrupts.
> 
> [ tglx: Make the protection unconditional and not only for legacy
>   	interrupts ]
> 
> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> Cc: Jiang Liu <jiang.liu@linux.intel.com>
> Cc: Yinghai Lu <yinghai@kernel.org>
> Cc: K. Y. Srinivasan <kys@microsoft.com>
> Link: http://lkml.kernel.org/r/1444930943-19336-1-git-send-email-vkuznets@redhat.com
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> (cherry picked from commit c0ff971ef9acacd4d2caa508e444edad958dead9)
> Signed-off-by: Joseph Salisbury <joseph.salisbury@canonical.com>
> ---
>  arch/x86/kernel/apic/io_apic.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
> index 206052e..b15b924 100644
> --- a/arch/x86/kernel/apic/io_apic.c
> +++ b/arch/x86/kernel/apic/io_apic.c
> @@ -2906,6 +2906,7 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
>  	struct irq_data *irq_data;
>  	struct mp_chip_data *data;
>  	struct irq_alloc_info *info = arg;
> +	unsigned long flags;
>  
>  	if (!info || nr_irqs > 1)
>  		return -EINVAL;
> @@ -2938,11 +2939,14 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
>  
>  	cfg = irqd_cfg(irq_data);
>  	add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
> +
> +	local_irq_save(flags);
>  	if (info->ioapic_entry)
>  		mp_setup_entry(cfg, data, info->ioapic_entry);
>  	mp_register_handler(virq, data->trigger);
>  	if (virq < nr_legacy_irqs())
>  		legacy_pic->mask(virq);
> +	local_irq_restore(flags);
>  
>  	apic_printk(APIC_VERBOSE, KERN_DEBUG
>  		    "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n",

Look to do what is claimed, clean cherry pick.

Acked-by: Andy Whitcroft <apw@canonical.com>

-apw
diff mbox

Patch

diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 206052e..b15b924 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2906,6 +2906,7 @@  int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
 	struct irq_data *irq_data;
 	struct mp_chip_data *data;
 	struct irq_alloc_info *info = arg;
+	unsigned long flags;
 
 	if (!info || nr_irqs > 1)
 		return -EINVAL;
@@ -2938,11 +2939,14 @@  int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
 
 	cfg = irqd_cfg(irq_data);
 	add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
+
+	local_irq_save(flags);
 	if (info->ioapic_entry)
 		mp_setup_entry(cfg, data, info->ioapic_entry);
 	mp_register_handler(virq, data->trigger);
 	if (virq < nr_legacy_irqs())
 		legacy_pic->mask(virq);
+	local_irq_restore(flags);
 
 	apic_printk(APIC_VERBOSE, KERN_DEBUG
 		    "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n",