- Update to 2.6.25-rc3.
[linux-flexiantxendom0-3.2.10.git] / arch / x86 / kernel / alternative.c
index d6405e0..45d79ea 100644 (file)
@@ -273,6 +273,7 @@ struct smp_alt_module {
 };
 static LIST_HEAD(smp_alt_modules);
 static DEFINE_SPINLOCK(smp_alt);
+static int smp_mode = 1;       /* protected by smp_alt */
 
 void alternatives_smp_module_add(struct module *mod, char *name,
                                 void *locks, void *locks_end,
@@ -341,12 +342,13 @@ void alternatives_smp_switch(int smp)
 
 #ifdef CONFIG_LOCKDEP
        /*
-        * A not yet fixed binutils section handling bug prevents
-        * alternatives-replacement from working reliably, so turn
-        * it off:
+        * Older binutils section handling bug prevented
+        * alternatives-replacement from working reliably.
+        *
+        * If this still occurs then you should see a hang
+        * or crash shortly after this line:
         */
-       printk("lockdep: not fixing up alternatives.\n");
-       return;
+       printk("lockdep: fixing up alternatives.\n");
 #endif
 
        if (noreplace_smp || smp_alt_once)
@@ -354,21 +356,29 @@ void alternatives_smp_switch(int smp)
        BUG_ON(!smp && (num_online_cpus() > 1));
 
        spin_lock_irqsave(&smp_alt, flags);
-       if (smp) {
+
+       /*
+        * Avoid unnecessary switches because it forces JIT based VMs to
+        * throw away all cached translations, which can be quite costly.
+        */
+       if (smp == smp_mode) {
+               /* nothing */
+       } else if (smp) {
                printk(KERN_INFO "SMP alternatives: switching to SMP code\n");
-               clear_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
-               clear_bit(X86_FEATURE_UP, cpu_data(0).x86_capability);
+               clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
+               clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
                list_for_each_entry(mod, &smp_alt_modules, next)
                        alternatives_smp_lock(mod->locks, mod->locks_end,
                                              mod->text, mod->text_end);
        } else {
                printk(KERN_INFO "SMP alternatives: switching to UP code\n");
-               set_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
-               set_bit(X86_FEATURE_UP, cpu_data(0).x86_capability);
+               set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
+               set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
                list_for_each_entry(mod, &smp_alt_modules, next)
                        alternatives_smp_unlock(mod->locks, mod->locks_end,
                                                mod->text, mod->text_end);
        }
+       smp_mode = smp;
        spin_unlock_irqrestore(&smp_alt, flags);
 }
 
@@ -431,8 +441,9 @@ void __init alternative_instructions(void)
        if (smp_alt_once) {
                if (1 == num_possible_cpus()) {
                        printk(KERN_INFO "SMP alternatives: switching to UP code\n");
-                       set_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
-                       set_bit(X86_FEATURE_UP, cpu_data(0).x86_capability);
+                       set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
+                       set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
+
                        alternatives_smp_unlock(__smp_locks, __smp_locks_end,
                                                _text, _etext);
                }
@@ -440,7 +451,10 @@ void __init alternative_instructions(void)
                alternatives_smp_module_add(NULL, "core kernel",
                                            __smp_locks, __smp_locks_end,
                                            _text, _etext);
-               alternatives_smp_switch(0);
+
+               /* Only switch to UP mode if we don't immediately boot others */
+               if (num_possible_cpus() == 1 || setup_max_cpus <= 1)
+                       alternatives_smp_switch(0);
        }
 #endif
        apply_paravirt(__parainstructions, __parainstructions_end);