2005-09-21 15:43:43

by Nick Piggin

[permalink] [raw]
Subject: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

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?

Signed-off-by: Nick Piggin <[email protected]>

Index: linux-2.6/init/main.c
===================================================================
--- linux-2.6.orig/init/main.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/init/main.c 2005-09-22 01:04:03.000000000 +1000
@@ -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();
}

Index: linux-2.6/arch/i386/kernel/smpboot.c
===================================================================
--- linux-2.6.orig/arch/i386/kernel/smpboot.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/i386/kernel/smpboot.c 2005-09-22 01:04:03.000000000 +1000
@@ -478,6 +478,8 @@ set_cpu_sibling_map(int cpu)
*/
static void __devinit start_secondary(void *unused)
{
+ preempt_disable();
+
/*
* Dont put anything before smp_callin(), SMP
* booting is too fragile that we want to limit the
Index: linux-2.6/arch/ia64/kernel/smpboot.c
===================================================================
--- linux-2.6.orig/arch/ia64/kernel/smpboot.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/ia64/kernel/smpboot.c 2005-09-22 01:04:03.000000000 +1000
@@ -394,6 +394,8 @@ smp_callin (void)
int __devinit
start_secondary (void *unused)
{
+ preempt_disable();
+
/* Early console may use I/O ports */
ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase));
Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
Index: linux-2.6/arch/ppc64/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/ppc64/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/ppc64/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -545,7 +545,10 @@ 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;
+
+ preempt_disable();
+ cpu = smp_processor_id();

atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
Index: linux-2.6/arch/sparc64/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/sparc64/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/sparc64/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -147,6 +147,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)
Index: linux-2.6/arch/s390/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/s390/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/s390/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -531,6 +531,8 @@ extern void pfault_fini(void);

int __devinit start_secondary(void *cpuvoid)
{
+ preempt_disable();
+
/* Setup the cpu */
cpu_init();
/* init per CPU timer */
Index: linux-2.6/arch/m32r/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/m32r/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/m32r/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -104,7 +104,9 @@ void cpu_idle (void)

idle();
}
+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
}
}

Index: linux-2.6/arch/frv/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/frv/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/frv/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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();
}
}

Index: linux-2.6/arch/cris/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/cris/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/cris/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -218,7 +218,9 @@ void cpu_idle (void)
idle = default_idle;
idle();
}
+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
}
}

Index: linux-2.6/arch/mips/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/mips/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/mips/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -83,7 +83,11 @@ extern ATTRIB_NORET void cpu_idle(void);
*/
asmlinkage void start_secondary(void)
{
- unsigned int cpu = smp_processor_id();
+ unsigned int cpu;
+
+ preempt_disable();
+
+ cpu = smp_processor_id();

cpu_probe();
cpu_report();
Index: linux-2.6/arch/ppc/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/ppc/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/ppc/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -339,6 +339,8 @@ int __devinit start_secondary(void *unus
{
int cpu;

+ preempt_disable();
+
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;

Index: linux-2.6/arch/m68k/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/m68k/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/m68k/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -102,7 +102,9 @@ void cpu_idle(void)
while (1) {
while (!need_resched())
idle();
+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
}
}

Index: linux-2.6/arch/mips/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/mips/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/mips/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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()
}
}

Index: linux-2.6/arch/sh/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/sh/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/sh/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -109,7 +109,11 @@ int __cpu_up(unsigned int cpu)

int start_secondary(void *unused)
{
- unsigned int cpu = smp_processor_id();
+ unsigned int cpu;
+
+ preempt_disable();
+
+ cpu = smp_processor_id();

atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
Index: linux-2.6/arch/parisc/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/parisc/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/parisc/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -462,6 +462,8 @@ void __init smp_callin(void)
void *istack;
#endif

+ preempt_disable();
+
smp_cpu_init(slave_id);

#if 0 /* NOT WORKING YET - see entry.S */
Index: linux-2.6/arch/m32r/kernel/smpboot.c
===================================================================
--- linux-2.6.orig/arch/m32r/kernel/smpboot.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/m32r/kernel/smpboot.c 2005-09-22 01:04:03.000000000 +1000
@@ -425,6 +425,7 @@ void __init smp_cpus_done(unsigned int m
*==========================================================================*/
int __init start_secondary(void *unused)
{
+ preempt_disable();
cpu_init();
smp_callin();
while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
Index: linux-2.6/arch/arm26/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/arm26/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/arm26/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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';
Index: linux-2.6/arch/arm/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/arm/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/arm/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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();
}
}

Index: linux-2.6/arch/h8300/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/h8300/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/h8300/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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)
Index: linux-2.6/arch/xtensa/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/xtensa/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/xtensa/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -96,8 +96,9 @@ void cpu_idle(void)
while (1) {
while (!need_resched())
platform_idle();
- preempt_enable();
+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
}
}

Index: linux-2.6/arch/v850/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/v850/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/v850/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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();
+ }
}

/*
Index: linux-2.6/arch/ppc64/kernel/iSeries_setup.c
===================================================================
--- linux-2.6.orig/arch/ppc64/kernel/iSeries_setup.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/ppc64/kernel/iSeries_setup.c 2005-09-22 01:04:03.000000000 +1000
@@ -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;
Index: linux-2.6/arch/x86_64/kernel/smpboot.c
===================================================================
--- linux-2.6.orig/arch/x86_64/kernel/smpboot.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/x86_64/kernel/smpboot.c 2005-09-22 01:04:03.000000000 +1000
@@ -473,6 +473,7 @@ void __cpuinit start_secondary(void)
* booting is too fragile that we want to limit the
* things done here to the most necessary things.
*/
+ preempt_disable();
cpu_init();
smp_callin();

Index: linux-2.6/arch/arm/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/arm/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/arm/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -162,7 +162,10 @@ 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;
+
+ preempt_disable();
+ cpu = smp_processor_id();

printk("CPU%u: Booted secondary processor\n", cpu);

Index: linux-2.6/arch/cris/arch-v32/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/cris/arch-v32/kernel/smp.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/cris/arch-v32/kernel/smp.c 2005-09-22 01:04:03.000000000 +1000
@@ -144,6 +144,8 @@ void __init smp_callin(void)
int cpu = cpu_now_booting;
reg_intr_vect_rw_mask vect_mask = {0};

+ preempt_disable();
+
/* Initialise the idle task for this CPU */
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
Index: linux-2.6/arch/i386/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/i386/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/i386/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -181,7 +181,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) {
@@ -203,7 +203,9 @@ void cpu_idle(void)
__get_cpu_var(irq_stat).idle_timestamp = jiffies;
idle();
}
+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
}
}

Index: linux-2.6/arch/ia64/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/ia64/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/ia64/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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();
Index: linux-2.6/arch/parisc/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/parisc/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/parisc/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -92,7 +92,9 @@ void cpu_idle(void)
while (1) {
while (!need_resched())
barrier();
+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
check_pgt_cache();
}
}
Index: linux-2.6/arch/s390/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/s390/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/s390/kernel/process.c 2005-09-22 01:05:06.000000000 +1000
@@ -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)
Index: linux-2.6/arch/sh/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/sh/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/sh/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -64,7 +64,9 @@ void default_idle(void)
cpu_sleep();
}

+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
}
}

Index: linux-2.6/arch/sh64/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/sh64/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/sh64/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -334,7 +334,9 @@ void default_idle(void)
}
local_irq_enable();
}
+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
}
}

Index: linux-2.6/arch/sparc/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/sparc/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/sparc/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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... */
Index: linux-2.6/arch/sparc64/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/sparc64/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/sparc64/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -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();
}
Index: linux-2.6/arch/x86_64/kernel/process.c
===================================================================
--- linux-2.6.orig/arch/x86_64/kernel/process.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/x86_64/kernel/process.c 2005-09-22 01:04:03.000000000 +1000
@@ -204,7 +204,9 @@ void cpu_idle (void)
idle();
}

+ preempt_enable_no_resched();
schedule();
+ preempt_disable();
}
}

Index: linux-2.6/arch/ppc/kernel/idle.c
===================================================================
--- linux-2.6.orig/arch/ppc/kernel/idle.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/ppc/kernel/idle.c 2005-09-22 01:04:03.000000000 +1000
@@ -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)
Index: linux-2.6/arch/ppc64/kernel/pSeries_setup.c
===================================================================
--- linux-2.6.orig/arch/ppc64/kernel/pSeries_setup.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/ppc64/kernel/pSeries_setup.c 2005-09-22 01:04:03.000000000 +1000
@@ -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();
Index: linux-2.6/arch/ppc64/kernel/idle.c
===================================================================
--- linux-2.6.orig/arch/ppc64/kernel/idle.c 2005-09-22 01:03:51.000000000 +1000
+++ linux-2.6/arch/ppc64/kernel/idle.c 2005-09-22 01:04:03.000000000 +1000
@@ -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()) &&


Attachments:
sched-no-preempt-idle.patch (21.46 kB)

2005-09-21 21:44:05

by Nigel Cunningham

[permalink] [raw]
Subject: Re: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

Hi Nick et al.

On Thu, 2005-09-22 at 01:41, Nick Piggin wrote:
> This patch should hopefully fix Nigel's bug.
>
> Split out from sched-resched-opt.patch. Tested on i386 with acpi idle
> and poll idle (previous iterations tested on various other architectures).
>
> CCed Ian because I am amazed that arm26 ever managed to reschedule
> out of the idle task without this... what am I missing?
>
> Andrew please apply

I'll give it a whirl when I get into work and let you know how I go.

Regards,

Nigel

2005-09-22 01:32:59

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

Nick Piggin <[email protected]> wrote:
>
> This patch should hopefully fix Nigel's bug.
>
> Split out from sched-resched-opt.patch. Tested on i386 with acpi idle
> and poll idle (previous iterations tested on various other architectures).

This makes the emt64 machine reboot itself, which iirc was the behaviour in
the failing patch from which this one was split out.

The machine is using acpi_processor_idle().


Wed Sep 21 16:15:07 PDT 2005
Bootdata ok (command line is ro root=/dev/sda3 console=ttyS0)
Linux version 2.6.14-rc2-mm1 (akpm@x) (gcc version 3.4.2 20041017 (Red Hat 3.4.5
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009fc00 (usable)
BIOS-e820: 000000000009fc00 - 00000000000a0000 (reserved)
BIOS-e820: 00000000000ebbd0 - 0000000000100000 (reserved)
BIOS-e820: 0000000000100000 - 000000007ffd0000 (usable)
BIOS-e820: 000000007ffd0000 - 000000007ffdf000 (ACPI data)
BIOS-e820: 000000007ffdf000 - 0000000080000000 (ACPI NVS)
BIOS-e820: 00000000e0000000 - 00000000f0000000 (reserved)
BIOS-e820: 00000000ffc00000 - 0000000100000000 (reserved)
BIOS-e820: 0000000100000000 - 0000000180000000 (usable)
ACPI: PM-Timer IO Port: 0x408
ACPI: LAPIC (acpi_id[0x01] lapic_id[0x00] enabled)
Processor #0 15:3 APIC version 20
ACPI: LAPIC (acpi_id[0x02] lapic_id[0x06] enabled)
Processor #6 15:3 APIC version 20
ACPI: LAPIC (acpi_id[0x03] lapic_id[0x01] enabled)
Processor #1 15:3 APIC version 20
ACPI: LAPIC (acpi_id[0x04] lapic_id[0x07] enabled)
Processor #7 15:3 APIC version 20
ACPI: IOAPIC (id[0x08] address[0xfec00000] gsi_base[0])
IOAPIC[0]: apic_id 8, version 32, address 0xfec00000, GSI 0-23
ACPI: IOAPIC (id[0x09] address[0xfec81000] gsi_base[24])
IOAPIC[1]: apic_id 9, version 32, address 0xfec81000, GSI 24-47
ACPI: IOAPIC (id[0x0a] address[0xfec81400] gsi_base[48])
IOAPIC[2]: apic_id 10, version 32, address 0xfec81400, GSI 48-71
ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 dfl dfl)
ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 high level)
Setting APIC routing to flat
ACPI: HPET id: 0x8086a202 base: 0xfed00000
Using ACPI (MADT) for SMP configuration information
Allocating PCI resources starting at 88000000 (gap: 80000000:60000000)
Checking aperture...
Built 1 zonelists
Initializing CPU#0
Kernel command line: ro root=/dev/sda3 console=ttyS0
PID hash table entries: 4096 (order: 12, 131072 bytes)
time.c: Using 3.579545 MHz PM timer.
time.c: Detected 3400.276 MHz processor.
Console: colour VGA+ 80x25
Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes)
Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes)
Placing software IO TLB between 0x6a81000 - 0xaa81000
Memory: 4029344k/6291456k available (3009k kernel code, 164152k reserved, 1758k)
Calibrating delay using timer specific routine.. 6810.03 BogoMIPS (lpj=13620075)
Mount-cache hash table entries: 256
CPU: Trace cache: 12K uops, L1 D cache: 16K
CPU: L2 cache: 1024K
using mwait in idle threads.
CPU: Physical Processor ID: 0
CPU0: Thermal monitoring enabled (TM1)
mtrr: v2.0 (20020519)
tbxface-0109 [02] load_tables : ACPI Tables successfully acquired
Parsing all Control Methods:....................................................
Table [DSDT](id 0005) - 461 Objects with 50 Devices 130 Methods 11 Regions
ACPI Namespace successfully loaded at root ffffffff806078c0
evxfevnt-0091 [03] enable : Transition to ACPI mode successful
Using local APIC timer interrupts.
Detected 12.500 MHz APIC timer.
setup_APIC_timer
done
softlockup thread 0 started up.
Booting processor 1/4 APIC 0x6


2005-09-22 03:25:38

by Nick Piggin

[permalink] [raw]
Subject: Re: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

Index: linux-2.6/arch/x86_64/kernel/smpboot.c
===================================================================
--- linux-2.6.orig/arch/x86_64/kernel/smpboot.c 2005-09-22 01:04:03.000000000 +1000
+++ linux-2.6/arch/x86_64/kernel/smpboot.c 2005-09-22 13:24:11.000000000 +1000
@@ -473,8 +473,8 @@ void __cpuinit start_secondary(void)
* booting is too fragile that we want to limit the
* things done here to the most necessary things.
*/
- preempt_disable();
cpu_init();
+ preempt_disable();
smp_callin();

/* otherwise gcc will move up the smp_processor_id before the cpu_init */


Attachments:
sched-no-preempt-idle-x86-64-fix.patch (596.00 B)

2005-09-22 09:03:17

by Andi Kleen

[permalink] [raw]
Subject: Re: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

On Thursday 22 September 2005 05:25, Nick Piggin wrote:

>
> OK, thanks. That must be the preempt_disable() being called in
> start_secondary(). Maybe I should have listened to the comment.
>
> Can you try the following patch?

The reason it broke was that current doesn't work before cpu_init() -
and preempt_disable does just that.

-Andi

2005-09-25 23:25:47

by Nigel Cunningham

[permalink] [raw]
Subject: Re: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

Hi.

On Thu, 2005-09-22 at 13:25, Nick Piggin wrote:
> Andrew Morton wrote:
> > Nick Piggin <[email protected]> wrote:
> >
> >>This patch should hopefully fix Nigel's bug.
> >>
> >> Split out from sched-resched-opt.patch. Tested on i386 with acpi idle
> >> and poll idle (previous iterations tested on various other architectures).
> >
> >
> > This makes the emt64 machine reboot itself, which iirc was the behaviour in
> > the failing patch from which this one was split out.
> >
> > The machine is using acpi_processor_idle().
> >
>
> OK, thanks. That must be the preempt_disable() being called in
> start_secondary(). Maybe I should have listened to the comment.
>
> Can you try the following patch?


Well, I did manage to reproduce the bug again without Nick's patches. It
seems it only occurs when I really want it to suspend because I'm going
home :). I'll apply Nick's patches now and give it some testing for a
few days.

Regards,

Nigel


2005-10-06 23:11:50

by Nigel Cunningham

[permalink] [raw]
Subject: Re: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

Hi.

On Thu, 2005-09-22 at 13:25, Nick Piggin wrote:
> Andrew Morton wrote:
> > Nick Piggin <[email protected]> wrote:
> >
> >>This patch should hopefully fix Nigel's bug.
> >>
> >> Split out from sched-resched-opt.patch. Tested on i386 with acpi idle
> >> and poll idle (previous iterations tested on various other architectures).
> >
> >
> > This makes the emt64 machine reboot itself, which iirc was the behaviour in
> > the failing patch from which this one was split out.
> >
> > The machine is using acpi_processor_idle().
> >
>
> OK, thanks. That must be the preempt_disable() being called in
> start_secondary(). Maybe I should have listened to the comment.
>
> Can you try the following patch?

Ok. Well I've fun with that patch for a couple of weeks and had no
recurrences of the issue whatsoever - until I upgraded my kernel
yesterday and forgot to apply it again. In short, it seems to fix the
problem here.

Regards,

Nigel

2005-11-02 02:33:44

by Shaohua Li

[permalink] [raw]
Subject: RE: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

Hi Nick,
>This patch should hopefully fix Nigel's bug.
>
>Split out from sched-resched-opt.patch. Tested on i386 with acpi idle
>and poll idle (previous iterations tested on various other
architectures).
>
>CCed Ian because I am amazed that arm26 ever managed to reschedule
>out of the idle task without this... what am I missing?
>
>Andrew please apply
What's the status of the patch? I didn't see it in base kernel.
We found another bug related with this issue. On UP system, if a CPU
enters
'mwait_idle', it never leaves it, as the 'mwait_idle' loop will never
end.
Disabling preempt fixes the bug. Should I submit a patch just disabling
preempt in 'mwait_idle' or wait for your patch?

Thanks,
Shaohua

2005-11-02 02:48:50

by Nick Piggin

[permalink] [raw]
Subject: Re: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks


Hi Shaohua,

Li, Shaohua wrote:

>
> What's the status of the patch? I didn't see it in base kernel.
> We found another bug related with this issue. On UP system, if a CPU
> enters
> 'mwait_idle', it never leaves it, as the 'mwait_idle' loop will never
> end.
> Disabling preempt fixes the bug. Should I submit a patch just disabling
> preempt in 'mwait_idle' or wait for your patch?
>

The patch is in Andrew's tree, and it should get merged for 2.6.15.
If you have verified that disabling preempt in mwait_idle fixes the
bug, then you may like to send that to the 2.6.14.stable guys.

Thanks,
Nick

--
SUSE Labs, Novell Inc.

Send instant messages to your online friends http://au.messenger.yahoo.com

2005-11-02 05:07:45

by Nigel Cunningham

[permalink] [raw]
Subject: Re: [PATCH 2.6.14-rc1-git5] sched: disable preempt in idle tasks

Hi Nick.

On Wed, 2005-11-02 at 13:46, Nick Piggin wrote:
> Hi Shaohua,
>
> Li, Shaohua wrote:
>
> >
> > What's the status of the patch? I didn't see it in base kernel.
> > We found another bug related with this issue. On UP system, if a CPU
> > enters
> > 'mwait_idle', it never leaves it, as the 'mwait_idle' loop will never
> > end.
> > Disabling preempt fixes the bug. Should I submit a patch just disabling
> > preempt in 'mwait_idle' or wait for your patch?
> >
>
> The patch is in Andrew's tree, and it should get merged for 2.6.15.
> If you have verified that disabling preempt in mwait_idle fixes the
> bug, then you may like to send that to the 2.6.14.stable guys.

I sent an email a couple of weeks ago saying that it looked like it did
the trick for me - no problems in two weeks of testing. (I would have
easily seen it within a day or two prior to this).

Regards,

Nigel

> Thanks,
> Nick
--