tracing: Fix race of function probes counting
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>
Tue, 18 Nov 2014 04:08:24 +0000 (23:08 -0500)
committerSteven Rostedt <rostedt@goodmis.org>
Wed, 19 Nov 2014 04:06:35 +0000 (23:06 -0500)
commita9ce7c36aa4256019180c590d60e2fad7431c749
treefe45059ee1cabf08885823a8db12d56038a28e86
parent4526d0676a150dce7a93ad93e03bef7f77e7c906
tracing: Fix race of function probes counting

The function probe counting for traceon and traceoff suffered a race
condition where if the probe was executing on two or more CPUs at the
same time, it could decrement the counter by more than one when
disabling (or enabling) the tracer only once.

The way the traceon and traceoff probes are suppose to work is that
they disable (or enable) tracing once per count. If a user were to
echo 'schedule:traceoff:3' into set_ftrace_filter, then when the
schedule function was called, it would disable tracing. But the count
should only be decremented once (to 2). Then if the user enabled tracing
again (via tracing_on file), the next call to schedule would disable
tracing again and the count would be decremented to 1.

But if multiple CPUS called schedule at the same time, it is possible
that the count would be decremented more than once because of the
simple "count--" used.

By reading the count into a local variable and using memory barriers
we can guarantee that the count would only be decremented once per
disable (or enable).

The stack trace probe had a similar race, but here the stack trace will
decrement for each time it is called. But this had the read-modify-
write race, where it could stack trace more than the number of times
that was specified. This case we use a cmpxchg to stack trace only the
number of times specified.

The dump probes can still use the old "update_count()" function as
they only run once, and that is controlled by the dump logic
itself.

Link: http://lkml.kernel.org/r/20141118134643.4b550ee4@gandalf.local.home
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
kernel/trace/trace_functions.c