x86, ioapic: Fix non atomic allocation with interrupts disabled
authorSuresh Siddha <suresh.b.siddha@intel.com>
Tue, 17 Mar 2009 00:05:03 +0000 (17:05 -0700)
committerH. Peter Anvin <hpa@linux.intel.com>
Tue, 17 Mar 2009 22:45:29 +0000 (15:45 -0700)
Impact: fix possible race

save_mask_IO_APIC_setup() was using non atomic memory allocation while getting
called with interrupts disabled. Fix this by splitting this into two different
function. Allocation part save_IO_APIC_setup() now happens before
disabling interrupts.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
arch/x86/include/asm/io_apic.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c

index ffcd08f96e47dfbf2d62676d3a5fb9feafacf47d..373cc2bbcad2cdfb17ef4e0448921da892691d0e 100644 (file)
@@ -162,7 +162,8 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
 
 #ifdef CONFIG_X86_64
-extern int save_mask_IO_APIC_setup(void);
+extern int save_IO_APIC_setup(void);
+extern void mask_IO_APIC_setup(void);
 extern void restore_IO_APIC_setup(void);
 extern void reinit_intr_remapped_IO_APIC(int);
 #endif
index 699f8cf76bbb6d9e0c7751044cedf7f6bced7314..85eb8e100818d2dfef0bae935684e6fe0253c888 100644 (file)
@@ -1334,15 +1334,16 @@ void __init enable_IR_x2apic(void)
                return;
        }
 
-       local_irq_save(flags);
-       mask_8259A();
-
-       ret = save_mask_IO_APIC_setup();
+       ret = save_IO_APIC_setup();
        if (ret) {
                pr_info("Saving IO-APIC state failed: %d\n", ret);
                goto end;
        }
 
+       local_irq_save(flags);
+       mask_IO_APIC_setup();
+       mask_8259A();
+
        ret = enable_intr_remapping(1);
 
        if (ret && x2apic_preenabled) {
@@ -1367,10 +1368,10 @@ end_restore:
        else
                reinit_intr_remapped_IO_APIC(x2apic_preenabled);
 
-end:
        unmask_8259A();
        local_irq_restore(flags);
 
+end:
        if (!ret) {
                if (!x2apic_preenabled)
                        pr_info("Enabled x2apic and interrupt-remapping\n");
index cf27795c641c8907efa4d06397c06bbd3116b7c5..ff1759a1128e367e7ae128992dde25bbf0336e03 100644 (file)
@@ -853,9 +853,9 @@ __setup("pirq=", ioapic_pirq_setup);
 static struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
 
 /*
- * Saves and masks all the unmasked IO-APIC RTE's
+ * Saves all the IO-APIC RTE's
  */
-int save_mask_IO_APIC_setup(void)
+int save_IO_APIC_setup(void)
 {
        union IO_APIC_reg_01 reg_01;
        unsigned long flags;
@@ -880,16 +880,9 @@ int save_mask_IO_APIC_setup(void)
        }
 
        for (apic = 0; apic < nr_ioapics; apic++)
-               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
-                       struct IO_APIC_route_entry entry;
-
-                       entry = early_ioapic_entries[apic][pin] =
+               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+                       early_ioapic_entries[apic][pin] =
                                ioapic_read_entry(apic, pin);
-                       if (!entry.mask) {
-                               entry.mask = 1;
-                               ioapic_write_entry(apic, pin, entry);
-                       }
-               }
 
        return 0;
 
@@ -902,6 +895,25 @@ nomem:
        return -ENOMEM;
 }
 
+void mask_IO_APIC_setup(void)
+{
+       int apic, pin;
+
+       for (apic = 0; apic < nr_ioapics; apic++) {
+               if (!early_ioapic_entries[apic])
+                       break;
+               for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+                       struct IO_APIC_route_entry entry;
+
+                       entry = early_ioapic_entries[apic][pin];
+                       if (!entry.mask) {
+                               entry.mask = 1;
+                               ioapic_write_entry(apic, pin, entry);
+                       }
+               }
+       }
+}
+
 void restore_IO_APIC_setup(void)
 {
        int apic, pin;