Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tracing, x86/irq: Do not trace arch_local_{*,irq_*}() functions

I triggered a triple fault with gcc 4.5.1 because it did not
honor the inline annotation to arch_local_save_flags() function
and that function was added to the pool of functions traced by
the function tracer.

When preempt_schedule() called arch_local_save_flags() (called
by irqs_disabled()), it was traced, but the first thing the
function tracer does is disable preemption. When it enables
preemption, the NEED_RESCHED flag will not have been cleared and
the preemption check will trigger the call to preempt_schedule()
again.

Although the dynamic function tracer crashed immediately, the
static version of the function tracer (CONFIG_DYNAMIC_FTRACE is
not set) actually was able to show where the problem was.

swapper-1 3.N.. 103885us : arch_local_save_flags <-preempt_schedule
swapper-1 3.N.. 103886us : arch_local_save_flags <-preempt_schedule
swapper-1 3.N.. 103886us : arch_local_save_flags <-preempt_schedule
swapper-1 3.N.. 103887us : arch_local_save_flags <-preempt_schedule
swapper-1 3.N.. 103887us : arch_local_save_flags <-preempt_schedule
swapper-1 3.N.. 103888us : arch_local_save_flags <-preempt_schedule
swapper-1 3.N.. 103888us : arch_local_save_flags <-preempt_schedule

It went on for a while before it triple faulted with a corrupted
stack.

The arch_local_save_flags and arch_local_irq_* functions should
not be traced. Even though they are marked as inline, gcc may
still make them a function and enable tracing of them.

The simple solution is to just mark them as notrace. I had to
add the <linux/types.h> for this file to include the notrace
tag.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/20110702033852.733414762@goodmis.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Steven Rostedt and committed by
Ingo Molnar
e08fbb78 931da613

+6 -5
+6 -5
arch/x86/include/asm/irqflags.h
··· 60 60 #include <asm/paravirt.h> 61 61 #else 62 62 #ifndef __ASSEMBLY__ 63 + #include <linux/types.h> 63 64 64 - static inline unsigned long arch_local_save_flags(void) 65 + static inline notrace unsigned long arch_local_save_flags(void) 65 66 { 66 67 return native_save_fl(); 67 68 } 68 69 69 - static inline void arch_local_irq_restore(unsigned long flags) 70 + static inline notrace void arch_local_irq_restore(unsigned long flags) 70 71 { 71 72 native_restore_fl(flags); 72 73 } 73 74 74 - static inline void arch_local_irq_disable(void) 75 + static inline notrace void arch_local_irq_disable(void) 75 76 { 76 77 native_irq_disable(); 77 78 } 78 79 79 - static inline void arch_local_irq_enable(void) 80 + static inline notrace void arch_local_irq_enable(void) 80 81 { 81 82 native_irq_enable(); 82 83 } ··· 103 102 /* 104 103 * For spinlocks, etc: 105 104 */ 106 - static inline unsigned long arch_local_irq_save(void) 105 + static inline notrace unsigned long arch_local_irq_save(void) 107 106 { 108 107 unsigned long flags = arch_local_save_flags(); 109 108 arch_local_irq_disable();