Comment 13 for bug 1598312

Revision history for this message
Vladimir Marko (swelef) wrote :

The revert of the offending commit does not apply cleanly to the Ubuntu-4.4.0-47.68 kernel. The closest we can get to a revert is this patch:

diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 64f233a..aec995c 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2523,7 +2523,6 @@ void __init setup_ioapic_dest(void)
        const struct cpumask *mask;
        struct irq_desc *desc;
        struct irq_data *idata;
- struct irq_chip *chip;

        if (skip_ioapic_setup == 1)
                return;
@@ -2538,7 +2537,6 @@ void __init setup_ioapic_dest(void)
                        continue;

                desc = irq_to_desc(irq);
- raw_spin_lock_irq(&desc->lock);
                idata = irq_desc_get_irq_data(desc);

                /*
@@ -2549,11 +2547,7 @@ void __init setup_ioapic_dest(void)
                else
                        mask = apic->target_cpus();

- chip = irq_data_get_irq_chip(idata);
- /* Might be lapic_chip for irq 0 */
- if (chip->irq_set_affinity)
- chip->irq_set_affinity(idata, mask, false);
- raw_spin_unlock_irq(&desc->lock);
+ irq_set_affinity(irq, mask);
        }
 }
 #endif

I tried this and it works. Another option is this smaller patch:

diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 64f233a..f185a1e 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -2523,7 +2523,6 @@ void __init setup_ioapic_dest(void)
        const struct cpumask *mask;
        struct irq_desc *desc;
        struct irq_data *idata;
- struct irq_chip *chip;

        if (skip_ioapic_setup == 1)
                return;
@@ -2549,10 +2548,7 @@ void __init setup_ioapic_dest(void)
                else
                        mask = apic->target_cpus();

- chip = irq_data_get_irq_chip(idata);
- /* Might be lapic_chip for irq 0 */
- if (chip->irq_set_affinity)
- chip->irq_set_affinity(idata, mask, false);
+ irq_set_affinity_locked(idata, mask, false);
                raw_spin_unlock_irq(&desc->lock);
        }
 }

which essentially keeps the raw_spin_lock_irq()/raw_spin_unlock_irq() rather than raw_spin_lock_irqsave()/raw_spin_unlock_irqrestore() used by __irq_set_affinity() in kernel/irq/manage.c .

I tested both patches on top of Ubuntu-4.4.0-47.68 and they work.
They also apply cleanly to Ubuntu-4.2.0-42.49 but I didn't actually check that it builds/works.

I tried manually inlining the irq_set_affinity_locked() (which required further inlining of some helper functions and providing a declaration of irq_do_set_affinity()) and it still worked. However, forcing the "if (irq_can_move_pcntxt())" path that immediately performs "chip->irq_set_affinity(idata, mask, false)" exposes the bug.

This confirms what I expected after reading https://lkml.org/lkml/2012/3/26/392 . Basically, when the hardware says that you cannot do something right away, you really cannot. And the offending commit just ignores this.