summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-05-12 21:20:44 +0200
committerThomas Gleixner <tglx@linutronix.de>2008-05-23 20:39:30 +0200
commit361943ad0ba3f16e66859e30a408915e008ba91e (patch)
treea0d55b7f252e8b69d9c7809a7d2c9521461ab860
parent5568b139f4d196273958ae2947a736fdf1ffeece (diff)
downloadlinux-361943ad0ba3f16e66859e30a408915e008ba91e.tar.gz
linux-361943ad0ba3f16e66859e30a408915e008ba91e.tar.bz2
linux-361943ad0ba3f16e66859e30a408915e008ba91e.zip
ftrace: irqs off smp_processor_id() fix
The irqsoff function tracer did a __get_cpu_var to determine if it should trace the function or not. The problem is that __get_cpu_var can preempt between getting the CPU and reading the cpu variable. This means that the cpu variable that is being read is not from the cpu being run on. At worst, this can give a false positive, where we trace the function when we should not. It will never give a false negative since we only want to trace when interrupts are disabled and we never preempt when they are. This fix adds a check after reading the irq flags to only trace if the interrupts are actually disabled. It also changes the reading of the cpu variable to use a raw_smp_processor_id since we now don't care if we preempt. We still catch that fact. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--kernel/trace/trace_irqsoff.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 8b1231633dc5..bd3f88198308 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -74,12 +74,21 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip)
long disabled;
int cpu;
- if (likely(!__get_cpu_var(tracing_cpu)))
+ /*
+ * Does not matter if we preempt. We test the flags
+ * afterward, to see if irqs are disabled or not.
+ * If we preempt and get a false positive, the flags
+ * test will fail.
+ */
+ cpu = raw_smp_processor_id();
+ if (likely(!per_cpu(tracing_cpu, cpu)))
return;
local_save_flags(flags);
+ /* slight chance to get a false positive on tracing_cpu */
+ if (!irqs_disabled_flags(flags))
+ return;
- cpu = raw_smp_processor_id();
data = tr->data[cpu];
disabled = atomic_inc_return(&data->disabled);