From: Andi Kleen Date: Tue, 14 Nov 2006 15:57:46 +0000 (+0100) Subject: [PATCH] x86-64: Fix race in exit_idle X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=9446868b5383eb87f76b2d4389dea4bb968a6657;p=linux-beck.git [PATCH] x86-64: Fix race in exit_idle When another interrupt happens in exit_idle the exit idle notifier could be called an incorrect number of times. Add a test_and_clear_bit_pda and use it handle the bit atomically against interrupts to avoid this. Pointed out by Stephane Eranian Signed-off-by: Andi Kleen --- diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 49f7fac6229e..f6226055d53d 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -88,9 +88,8 @@ void enter_idle(void) static void __exit_idle(void) { - if (read_pda(isidle) == 0) + if (test_and_clear_bit_pda(0, isidle) == 0) return; - write_pda(isidle, 0); atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); } diff --git a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h index 14996d962bac..5642634843c4 100644 --- a/include/asm-x86_64/pda.h +++ b/include/asm-x86_64/pda.h @@ -109,6 +109,15 @@ extern struct x8664_pda _proxy_pda; #define sub_pda(field,val) pda_to_op("sub",field,val) #define or_pda(field,val) pda_to_op("or",field,val) +/* This is not atomic against other CPUs -- CPU preemption needs to be off */ +#define test_and_clear_bit_pda(bit,field) ({ \ + int old__; \ + asm volatile("btr %2,%%gs:%c3\n\tsbbl %0,%0" \ + : "=r" (old__), "+m" (_proxy_pda.field) \ + : "dIr" (bit), "i" (pda_offset(field)) : "memory"); \ + old__; \ +}) + #endif #define PDA_STACKOFFSET (5*8)