[PATCH] x86: cpu_init(): avoid GFP_KERNEL allocation while atomic
authorShaohua Li <shaohua.li@intel.com>
Tue, 27 Jun 2006 09:53:43 +0000 (02:53 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 28 Jun 2006 00:32:37 +0000 (17:32 -0700)
The patch fixes two issues:

1.  cpu_init is called with interrupt disabled.  Allocating gdt table
   there isn't good at runtime.

2. gdt table page cause memory leak in CPU hotplug case.

Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Cc: Ashok Raj <ashok.raj@intel.com>
Cc: Zachary Amsden <zach@vmware.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/i386/kernel/cpu/common.c
arch/i386/kernel/smpboot.c

index 44f2c5f..640364d 100644 (file)
@@ -613,6 +613,12 @@ void __cpuinit cpu_init(void)
                set_in_cr4(X86_CR4_TSD);
        }
 
+       /* The CPU hotplug case */
+       if (cpu_gdt_descr->address) {
+               gdt = (struct desc_struct *)cpu_gdt_descr->address;
+               memset(gdt, 0, PAGE_SIZE);
+               goto old_gdt;
+       }
        /*
         * This is a horrible hack to allocate the GDT.  The problem
         * is that cpu_init() is called really early for the boot CPU
@@ -631,7 +637,7 @@ void __cpuinit cpu_init(void)
                                local_irq_enable();
                }
        }
-
+old_gdt:
        /*
         * Initialize the per-CPU GDT with the boot GDT,
         * and set up the GDT descriptor:
index bce5470..9466a3c 100644 (file)
@@ -1056,6 +1056,7 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
        struct warm_boot_cpu_info info;
        struct work_struct task;
        int     apicid, ret;
+       struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
 
        apicid = x86_cpu_to_apicid[cpu];
        if (apicid == BAD_APICID) {
@@ -1063,6 +1064,18 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
                goto exit;
        }
 
+       /*
+        * the CPU isn't initialized at boot time, allocate gdt table here.
+        * cpu_init will initialize it
+        */
+       if (!cpu_gdt_descr->address) {
+               cpu_gdt_descr->address = get_zeroed_page(GFP_KERNEL);
+               if (!cpu_gdt_descr->address)
+                       printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
+                       ret = -ENOMEM;
+                       goto exit;
+       }
+
        info.complete = &done;
        info.apicid = apicid;
        info.cpu = cpu;