diff options
author | Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com> | 2012-05-28 05:09:18 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-06-06 06:03:25 -0400 |
commit | f6175f5bfb4c9f2ed32758c95f765b529b1a7f15 (patch) | |
tree | 7c33b47cea87463f4d51f80064b699bafeb2a178 /arch/x86/kernel/apic | |
parent | 55c844a4dd16a4d1fdc0cf2a283ec631a02ec448 (diff) |
x86/ioapic: Fix NULL pointer dereference on CPU hotplug after disabling irqs
In current Linux, percpu variable `vector_irq' is not cleared on
offlined cpus while disabling devices' irqs. If the cpu that has
the disabled irqs in vector_irq is hotplugged,
__setup_vector_irq() hits invalid irq vector and may crash.
This bug can be reproduced as following;
# echo 0 > /sys/devices/system/cpu/cpu7/online
# modprobe -r some_driver_using_interrupts # vector_irq@cpu7 uncleared
# echo 1 > /sys/devices/system/cpu/cpu7/online # kernel may crash
This patch fixes this bug by clearing vector_irq in
__clear_irq_vector() even if the cpu is offlined.
Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: yrl.pp-manager.tt@hitachi.com
Cc: ltc-kernel@ml.yrl.intra.hitachi.co.jp
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Alexander Gordeev <agordeev@redhat.com>
Link: http://lkml.kernel.org/r/4FC340BE.7080101@hitachi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel/apic')
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index ac96561d1a99..5f0ff597437c 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -1195,7 +1195,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg) | |||
1195 | BUG_ON(!cfg->vector); | 1195 | BUG_ON(!cfg->vector); |
1196 | 1196 | ||
1197 | vector = cfg->vector; | 1197 | vector = cfg->vector; |
1198 | for_each_cpu_and(cpu, cfg->domain, cpu_online_mask) | 1198 | for_each_cpu(cpu, cfg->domain) |
1199 | per_cpu(vector_irq, cpu)[vector] = -1; | 1199 | per_cpu(vector_irq, cpu)[vector] = -1; |
1200 | 1200 | ||
1201 | cfg->vector = 0; | 1201 | cfg->vector = 0; |
@@ -1203,7 +1203,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg) | |||
1203 | 1203 | ||
1204 | if (likely(!cfg->move_in_progress)) | 1204 | if (likely(!cfg->move_in_progress)) |
1205 | return; | 1205 | return; |
1206 | for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) { | 1206 | for_each_cpu(cpu, cfg->old_domain) { |
1207 | for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; | 1207 | for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; |
1208 | vector++) { | 1208 | vector++) { |
1209 | if (per_cpu(vector_irq, cpu)[vector] != irq) | 1209 | if (per_cpu(vector_irq, cpu)[vector] != irq) |