From: Nick Piggin Run idle threads with preempt disabled. Also corrected a bugs in arm26's cpu_idle (make it actually call schedule()). How did it ever work before? Might fix the CPU hotplugging hang which Nigel Cunningham noted. We think the bug hits if the idle thread is preempted after checking need_resched() and before going to sleep, then the CPU offlined. After calling stop_machine_run, the CPU eventually returns from preemption and into the idle thread and goes to sleep. The CPU will continue executing previous idle and have no chance to call play_dead. By disabling preemption until we are ready to explicitly schedule, this bug is fixed and the idle threads generally become more robust. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton --- arch/arm/kernel/process.c | 4 ++-- arch/arm/kernel/smp.c | 5 ++++- arch/arm26/kernel/process.c | 12 +++++------- arch/cris/arch-v32/kernel/smp.c | 1 + arch/cris/kernel/process.c | 2 ++ arch/frv/kernel/process.c | 6 +++++- arch/h8300/kernel/process.c | 28 +++++++++++++++------------- arch/i386/kernel/process.c | 4 +++- arch/i386/kernel/smpboot.c | 1 + arch/ia64/kernel/process.c | 2 ++ arch/ia64/kernel/smpboot.c | 1 + arch/m32r/kernel/process.c | 2 ++ arch/m32r/kernel/smpboot.c | 1 + arch/m68k/kernel/process.c | 2 ++ arch/mips/kernel/process.c | 2 ++ arch/mips/kernel/smp.c | 4 +++- arch/parisc/kernel/process.c | 2 ++ arch/parisc/kernel/smp.c | 1 + arch/ppc/kernel/idle.c | 15 ++++++++++----- arch/ppc/kernel/smp.c | 1 + arch/ppc64/kernel/iSeries_setup.c | 4 ++++ arch/ppc64/kernel/idle.c | 4 ++++ arch/ppc64/kernel/pSeries_setup.c | 4 ++++ arch/ppc64/kernel/smp.c | 5 ++++- arch/s390/kernel/process.c | 11 ++++++++--- arch/s390/kernel/smp.c | 1 + arch/sh/kernel/process.c | 2 ++ arch/sh/kernel/smp.c | 5 ++++- arch/sh64/kernel/process.c | 2 ++ arch/sparc/kernel/process.c | 4 ++++ arch/sparc64/kernel/process.c | 4 ++++ arch/sparc64/kernel/smp.c | 3 +++ arch/v850/kernel/process.c | 16 ++++++++++------ arch/x86_64/kernel/process.c | 2 ++ arch/x86_64/kernel/smpboot.c | 1 + arch/xtensa/kernel/process.c | 3 ++- init/main.c | 4 +++- 37 files changed, 127 insertions(+), 44 deletions(-) diff -puN arch/arm26/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/arm26/kernel/process.c --- devel/arch/arm26/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/arm26/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -74,15 +74,13 @@ __setup("hlt", hlt_setup); void cpu_idle(void) { /* endless idle loop with no priority at all */ - preempt_disable(); while (1) { - while (!need_resched()) { - local_irq_disable(); - if (!need_resched() && !hlt_counter) - local_irq_enable(); - } + while (!need_resched()) + cpu_relax(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); } - schedule(); } static char reboot_mode = 'h'; diff -puN arch/arm/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/arm/kernel/process.c --- devel/arch/arm/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/arm/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -107,13 +107,13 @@ void cpu_idle(void) void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; - preempt_disable(); leds_event(led_idle_start); while (!need_resched()) idle(); leds_event(led_idle_end); - preempt_enable(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/arm/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/arm/kernel/smp.c --- devel/arch/arm/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/arm/kernel/smp.c 2005-10-11 00:35:00.000000000 -0700 @@ -162,7 +162,9 @@ int __cpuinit __cpu_up(unsigned int cpu) asmlinkage void __cpuinit secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; - unsigned int cpu = smp_processor_id(); + unsigned int cpu; + + cpu = smp_processor_id(); printk("CPU%u: Booted secondary processor\n", cpu); @@ -179,6 +181,7 @@ asmlinkage void __cpuinit secondary_star local_flush_tlb_all(); cpu_init(); + preempt_disable(); /* * Give the platform a chance to do its own initialisation. diff -puN arch/cris/arch-v32/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/cris/arch-v32/kernel/smp.c --- devel/arch/cris/arch-v32/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/cris/arch-v32/kernel/smp.c 2005-10-11 00:35:00.000000000 -0700 @@ -159,6 +159,7 @@ void __init smp_callin(void) REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask); unmask_irq(IPI_INTR_VECT); unmask_irq(TIMER_INTR_VECT); + preempt_disable(); local_irq_enable(); cpu_set(cpu, cpu_online_map); diff -puN arch/cris/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/cris/kernel/process.c --- devel/arch/cris/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/cris/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -218,7 +218,9 @@ void cpu_idle (void) idle = default_idle; idle(); } + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/frv/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/frv/kernel/process.c --- devel/arch/frv/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/frv/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -77,16 +77,20 @@ void (*idle)(void) = core_sleep_idle; */ void cpu_idle(void) { + int cpu = smp_processor_id(); + /* endless idle loop with no priority at all */ while (1) { while (!need_resched()) { - irq_stat[smp_processor_id()].idle_timestamp = jiffies; + irq_stat[cpu].idle_timestamp = jiffies; if (!frv_dma_inprogress && idle) idle(); } + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/h8300/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/h8300/kernel/process.c --- devel/arch/h8300/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/h8300/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -53,22 +53,18 @@ asmlinkage void ret_from_fork(void); #if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM) void default_idle(void) { - while(1) { - if (!need_resched()) { - local_irq_enable(); - __asm__("sleep"); - local_irq_disable(); - } - schedule(); - } + local_irq_disable(); + if (!need_resched()) { + local_irq_enable(); + /* XXX: race here! What if need_resched() gets set now? */ + __asm__("sleep"); + } else + local_irq_enable(); } #else void default_idle(void) { - while(1) { - if (need_resched()) - schedule(); - } + cpu_relax(); } #endif void (*idle)(void) = default_idle; @@ -81,7 +77,13 @@ void (*idle)(void) = default_idle; */ void cpu_idle(void) { - idle(); + while (1) { + while (!need_resched()) + idle(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } } void machine_restart(char * __unused) diff -puN arch/i386/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/i386/kernel/process.c --- devel/arch/i386/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/i386/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -179,7 +179,7 @@ static inline void play_dead(void) */ void cpu_idle(void) { - int cpu = raw_smp_processor_id(); + int cpu = smp_processor_id(); /* endless idle loop with no priority at all */ while (1) { @@ -201,7 +201,9 @@ void cpu_idle(void) __get_cpu_var(irq_stat).idle_timestamp = jiffies; idle(); } + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/i386/kernel/smpboot.c~sched-disable-preempt-in-idle-tasks-2 arch/i386/kernel/smpboot.c --- devel/arch/i386/kernel/smpboot.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/i386/kernel/smpboot.c 2005-10-11 00:35:00.000000000 -0700 @@ -488,6 +488,7 @@ static void __devinit start_secondary(vo * things done here to the most necessary things. */ cpu_init(); + preempt_disable(); smp_callin(); while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) rep_nop(); diff -puN arch/ia64/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/ia64/kernel/process.c --- devel/arch/ia64/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/ia64/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -292,7 +292,9 @@ cpu_idle (void) #ifdef CONFIG_SMP normal_xtp(); #endif + preempt_enable_no_resched(); schedule(); + preempt_disable(); check_pgt_cache(); if (cpu_is_offline(smp_processor_id())) play_dead(); diff -puN arch/ia64/kernel/smpboot.c~sched-disable-preempt-in-idle-tasks-2 arch/ia64/kernel/smpboot.c --- devel/arch/ia64/kernel/smpboot.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/ia64/kernel/smpboot.c 2005-10-11 00:35:00.000000000 -0700 @@ -399,6 +399,7 @@ start_secondary (void *unused) Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id()); efi_map_pal_code(); cpu_init(); + preempt_disable(); smp_callin(); cpu_idle(); diff -puN arch/m32r/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/m32r/kernel/process.c --- devel/arch/m32r/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/m32r/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -104,7 +104,9 @@ void cpu_idle (void) idle(); } + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/m32r/kernel/smpboot.c~sched-disable-preempt-in-idle-tasks-2 arch/m32r/kernel/smpboot.c --- devel/arch/m32r/kernel/smpboot.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/m32r/kernel/smpboot.c 2005-10-11 00:35:00.000000000 -0700 @@ -426,6 +426,7 @@ void __init smp_cpus_done(unsigned int m int __init start_secondary(void *unused) { cpu_init(); + preempt_disable(); smp_callin(); while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) cpu_relax(); diff -puN arch/m68k/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/m68k/kernel/process.c --- devel/arch/m68k/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/m68k/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -102,7 +102,9 @@ void cpu_idle(void) while (1) { while (!need_resched()) idle(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/mips/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/mips/kernel/process.c --- devel/arch/mips/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/mips/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -58,7 +58,9 @@ ATTRIB_NORET void cpu_idle(void) while (!need_resched()) if (cpu_wait) (*cpu_wait)(); + preempt_enable_no_resched(); schedule(); + preempt_disable() } } diff -puN arch/mips/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/mips/kernel/smp.c --- devel/arch/mips/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/mips/kernel/smp.c 2005-10-11 00:35:00.000000000 -0700 @@ -83,7 +83,7 @@ extern ATTRIB_NORET void cpu_idle(void); */ asmlinkage void start_secondary(void) { - unsigned int cpu = smp_processor_id(); + unsigned int cpu; cpu_probe(); cpu_report(); @@ -96,6 +96,8 @@ asmlinkage void start_secondary(void) */ calibrate_delay(); + preempt_disable(); + cpu = smp_processor_id(); cpu_data[cpu].udelay_val = loops_per_jiffy; prom_smp_finish(); diff -puN arch/parisc/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/parisc/kernel/process.c --- devel/arch/parisc/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/parisc/kernel/process.c 2005-10-11 00:35:00.000000000 -0700 @@ -92,7 +92,9 @@ void cpu_idle(void) while (1) { while (!need_resched()) barrier(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); check_pgt_cache(); } } diff -puN arch/parisc/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/parisc/kernel/smp.c --- devel/arch/parisc/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/parisc/kernel/smp.c 2005-10-11 00:35:00.000000000 -0700 @@ -463,6 +463,7 @@ void __init smp_callin(void) #endif smp_cpu_init(slave_id); + preempt_disable(); #if 0 /* NOT WORKING YET - see entry.S */ istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER); diff -puN arch/ppc64/kernel/idle.c~sched-disable-preempt-in-idle-tasks-2 arch/ppc64/kernel/idle.c --- devel/arch/ppc64/kernel/idle.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/ppc64/kernel/idle.c 2005-10-11 00:35:00.000000000 -0700 @@ -60,7 +60,9 @@ int default_idle(void) } ppc64_runlatch_on(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); } @@ -78,7 +80,9 @@ int native_idle(void) if (need_resched()) { ppc64_runlatch_on(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); } if (cpu_is_offline(smp_processor_id()) && diff -puN arch/ppc64/kernel/iSeries_setup.c~sched-disable-preempt-in-idle-tasks-2 arch/ppc64/kernel/iSeries_setup.c --- devel/arch/ppc64/kernel/iSeries_setup.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/ppc64/kernel/iSeries_setup.c 2005-10-11 00:35:00.000000000 -0700 @@ -898,7 +898,9 @@ static int iseries_shared_idle(void) if (hvlpevent_is_pending()) process_iSeries_events(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); } return 0; @@ -932,7 +934,9 @@ static int iseries_dedicated_idle(void) } ppc64_runlatch_on(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); } return 0; diff -puN arch/ppc64/kernel/pSeries_setup.c~sched-disable-preempt-in-idle-tasks-2 arch/ppc64/kernel/pSeries_setup.c --- devel/arch/ppc64/kernel/pSeries_setup.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/ppc64/kernel/pSeries_setup.c 2005-10-11 00:35:00.000000000 -0700 @@ -537,7 +537,9 @@ static int pseries_dedicated_idle(void) lpaca->lppaca.idle = 0; ppc64_runlatch_on(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); @@ -581,7 +583,9 @@ static int pseries_shared_idle(void) lpaca->lppaca.idle = 0; ppc64_runlatch_on(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); diff -puN arch/ppc64/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/ppc64/kernel/smp.c --- devel/arch/ppc64/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/ppc64/kernel/smp.c 2005-10-11 00:35:01.000000000 -0700 @@ -545,13 +545,16 @@ int __devinit __cpu_up(unsigned int cpu) /* Activate a secondary processor. */ int __devinit start_secondary(void *unused) { - unsigned int cpu = smp_processor_id(); + unsigned int cpu; + + cpu = smp_processor_id(); atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; smp_store_cpu_info(cpu); set_dec(paca[cpu].default_decr); + preempt_disable(); cpu_callin_map[cpu] = 1; smp_ops->setup_cpu(cpu); diff -puN arch/ppc/kernel/idle.c~sched-disable-preempt-in-idle-tasks-2 arch/ppc/kernel/idle.c --- devel/arch/ppc/kernel/idle.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/ppc/kernel/idle.c 2005-10-11 00:35:01.000000000 -0700 @@ -52,10 +52,6 @@ void default_idle(void) } #endif } - if (need_resched()) - schedule(); - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); } /* @@ -63,11 +59,20 @@ void default_idle(void) */ void cpu_idle(void) { - for (;;) + for (;;) { if (ppc_md.idle != NULL) ppc_md.idle(); else default_idle(); + if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) + cpu_die(); + if (need_resched()) { + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } + + } } #if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx) diff -puN arch/ppc/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/ppc/kernel/smp.c --- devel/arch/ppc/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/ppc/kernel/smp.c 2005-10-11 00:35:01.000000000 -0700 @@ -345,6 +345,7 @@ int __devinit start_secondary(void *unus cpu = smp_processor_id(); smp_store_cpu_info(cpu); set_dec(tb_ticks_per_jiffy); + preempt_disable(); cpu_callin_map[cpu] = 1; printk("CPU %d done callin...\n", cpu); diff -puN arch/s390/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/s390/kernel/process.c --- devel/arch/s390/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/s390/kernel/process.c 2005-10-11 00:35:01.000000000 -0700 @@ -102,7 +102,6 @@ void default_idle(void) local_irq_disable(); if (need_resched()) { local_irq_enable(); - schedule(); return; } @@ -139,8 +138,14 @@ void default_idle(void) void cpu_idle(void) { - for (;;) - default_idle(); + for (;;) { + while (!need_resched()) + default_idle(); + + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } } void show_regs(struct pt_regs *regs) diff -puN arch/s390/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/s390/kernel/smp.c --- devel/arch/s390/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/s390/kernel/smp.c 2005-10-11 00:35:01.000000000 -0700 @@ -533,6 +533,7 @@ int __devinit start_secondary(void *cpuv { /* Setup the cpu */ cpu_init(); + preempt_disable(); /* init per CPU timer */ init_cpu_timer(); #ifdef CONFIG_VIRT_TIMER diff -puN arch/sh64/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/sh64/kernel/process.c --- devel/arch/sh64/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/sh64/kernel/process.c 2005-10-11 00:35:01.000000000 -0700 @@ -334,7 +334,9 @@ void default_idle(void) } local_irq_enable(); } + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/sh/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/sh/kernel/process.c --- devel/arch/sh/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/sh/kernel/process.c 2005-10-11 00:35:01.000000000 -0700 @@ -64,7 +64,9 @@ void default_idle(void) cpu_sleep(); } + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/sh/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/sh/kernel/smp.c --- devel/arch/sh/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/sh/kernel/smp.c 2005-10-11 00:35:01.000000000 -0700 @@ -109,7 +109,9 @@ int __cpu_up(unsigned int cpu) int start_secondary(void *unused) { - unsigned int cpu = smp_processor_id(); + unsigned int cpu; + + cpu = smp_processor_id(); atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; @@ -117,6 +119,7 @@ int start_secondary(void *unused) smp_store_cpu_info(cpu); __smp_slave_init(cpu); + preempt_disable(); per_cpu_trap_init(); atomic_inc(&cpus_booted); diff -puN arch/sparc64/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/sparc64/kernel/process.c --- devel/arch/sparc64/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/sparc64/kernel/process.c 2005-10-11 00:35:01.000000000 -0700 @@ -74,7 +74,9 @@ void cpu_idle(void) while (!need_resched()) barrier(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); check_pgt_cache(); } } @@ -93,7 +95,9 @@ void cpu_idle(void) if (need_resched()) { unidle_me(); clear_thread_flag(TIF_POLLING_NRFLAG); + preempt_enable_no_resched(); schedule(); + preempt_disable(); set_thread_flag(TIF_POLLING_NRFLAG); check_pgt_cache(); } diff -puN arch/sparc64/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 arch/sparc64/kernel/smp.c --- devel/arch/sparc64/kernel/smp.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/sparc64/kernel/smp.c 2005-10-11 00:35:01.000000000 -0700 @@ -168,6 +168,9 @@ void __init smp_callin(void) rmb(); cpu_set(cpuid, cpu_online_map); + + /* idle thread is expected to have preempt disabled */ + preempt_disable(); } void cpu_panic(void) diff -puN arch/sparc/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/sparc/kernel/process.c --- devel/arch/sparc/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/sparc/kernel/process.c 2005-10-11 00:35:01.000000000 -0700 @@ -120,7 +120,9 @@ void cpu_idle(void) (*pm_idle)(); } + preempt_enable_no_resched(); schedule(); + preempt_disable(); check_pgt_cache(); } } @@ -133,7 +135,9 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while(1) { if(need_resched()) { + preempt_enable_no_resched(); schedule(); + preempt_disable(); check_pgt_cache(); } barrier(); /* or else gcc optimizes... */ diff -puN arch/v850/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/v850/kernel/process.c --- devel/arch/v850/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/v850/kernel/process.c 2005-10-11 00:35:01.000000000 -0700 @@ -36,11 +36,8 @@ extern void ret_from_fork (void); /* The idle loop. */ void default_idle (void) { - while (1) { - while (! need_resched ()) - asm ("halt; nop; nop; nop; nop; nop" ::: "cc"); - schedule (); - } + while (! need_resched ()) + asm ("halt; nop; nop; nop; nop; nop" ::: "cc"); } void (*idle)(void) = default_idle; @@ -54,7 +51,14 @@ void (*idle)(void) = default_idle; void cpu_idle (void) { /* endless idle loop with no priority at all */ - (*idle) (); + while (1) { + while (!need_resched()) + (*idle) (); + + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } } /* diff -puN arch/x86_64/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/x86_64/kernel/process.c --- devel/arch/x86_64/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/x86_64/kernel/process.c 2005-10-11 00:35:01.000000000 -0700 @@ -235,7 +235,9 @@ void cpu_idle (void) exit_idle(); } + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN arch/x86_64/kernel/smpboot.c~sched-disable-preempt-in-idle-tasks-2 arch/x86_64/kernel/smpboot.c --- devel/arch/x86_64/kernel/smpboot.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/x86_64/kernel/smpboot.c 2005-10-11 00:35:01.000000000 -0700 @@ -475,6 +475,7 @@ void __cpuinit start_secondary(void) * things done here to the most necessary things. */ cpu_init(); + preempt_disable(); smp_callin(); /* otherwise gcc will move up the smp_processor_id before the cpu_init */ diff -puN arch/xtensa/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 arch/xtensa/kernel/process.c --- devel/arch/xtensa/kernel/process.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/arch/xtensa/kernel/process.c 2005-10-11 00:35:01.000000000 -0700 @@ -96,8 +96,9 @@ void cpu_idle(void) while (1) { while (!need_resched()) platform_idle(); - preempt_enable(); + preempt_enable_no_resched(); schedule(); + preempt_disable(); } } diff -puN init/main.c~sched-disable-preempt-in-idle-tasks-2 init/main.c --- devel/init/main.c~sched-disable-preempt-in-idle-tasks-2 2005-10-11 00:35:00.000000000 -0700 +++ devel-akpm/init/main.c 2005-10-11 00:35:01.000000000 -0700 @@ -394,14 +394,16 @@ static void noinline rest_init(void) kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND); numa_default_policy(); unlock_kernel(); - preempt_enable_no_resched(); /* * The boot idle thread must execute schedule() * at least one to get things moving: */ + preempt_enable_no_resched(); schedule(); + preempt_disable(); + /* Call into cpu_idle with preempt disabled */ cpu_idle(); } _