From: George Dunlap Date: Mon, 22 Aug 2011 15:15:33 +0000 (+0100) Subject: x86: Fix up irq vector map logic X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~9946 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=45627433b2c0eec655bef8d02a48f75bc9b80fc2;p=xen.git x86: Fix up irq vector map logic We need to make sure that cfg->used_vector is only cleared once; otherwise there may be a race condition that allows the same vector to be assigned twice, defeating the whole purpose of the map. This makes two changes: * __clear_irq_vector() only clears the vector if the irq is not being moved * smp_iqr_move_cleanup_interrupt() only clears used_vector if this is the last place it's being used (move_cleanup_count==0 after decrement). Also make use of asserts more consistent, to catch this kind of logic bug in the future. Signed-off-by: George Dunlap --- diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index f9565df58b..dd45ff414e 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -485,12 +485,14 @@ fastcall void smp_irq_move_cleanup_interrupt(struct cpu_user_regs *regs) irq, vector, smp_processor_id()); __get_cpu_var(vector_irq)[vector] = -1; - if ( cfg->used_vectors ) + cfg->move_cleanup_count--; + + if ( cfg->move_cleanup_count == 0 + && cfg->used_vectors ) { ASSERT(test_bit(vector, cfg->used_vectors)); clear_bit(vector, cfg->used_vectors); } - cfg->move_cleanup_count--; unlock: spin_unlock(&desc->lock); } diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 8d598c28ca..22de938a5f 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -113,7 +113,10 @@ static int __init __bind_irq_vector(int irq, int vector, cpumask_t cpu_mask) cfg->vector = vector; cfg->cpu_mask = online_mask; if ( cfg->used_vectors ) + { + ASSERT(!test_bit(vector, cfg->used_vectors)); set_bit(vector, cfg->used_vectors); + } irq_status[irq] = IRQ_USED; if (IO_APIC_IRQ(irq)) irq_vector[irq] = vector; @@ -207,15 +210,13 @@ static void __clear_irq_vector(int irq) for_each_cpu_mask(cpu, tmp_mask) per_cpu(vector_irq, cpu)[vector] = -1; - if ( cfg->used_vectors ) - clear_bit(vector, cfg->used_vectors); - cfg->vector = IRQ_VECTOR_UNASSIGNED; cpus_clear(cfg->cpu_mask); init_one_irq_status(irq); if (likely(!cfg->move_in_progress)) return; + cpus_and(tmp_mask, cfg->old_cpu_mask, cpu_online_map); for_each_cpu_mask(cpu, tmp_mask) { for (vector = FIRST_DYNAMIC_VECTOR; vector <= LAST_DYNAMIC_VECTOR; @@ -229,6 +230,12 @@ static void __clear_irq_vector(int irq) } } + if ( cfg->used_vectors ) + { + ASSERT(test_bit(vector, cfg->used_vectors)); + clear_bit(vector, cfg->used_vectors); + } + cfg->move_in_progress = 0; }