lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:	Thu, 28 Mar 2013 08:58:18 -0400
From:	Steven Rostedt <rostedt@...dmis.org>
To:	LKML <linux-kernel@...r.kernel.org>
Cc:	Ingo Molnar <mingo@...nel.org>,
	Andrew Morton <akpm@...ux-foundation.org>,
	Frederic Weisbecker <fweisbec@...il.com>,
	Namhyung Kim <namhyung@...nel.org>,
	Keun-O Park <kpark3469@...il.com>,
	David Sharp <dhsharp@...gle.com>
Subject: Re: [GIT PULL] tracing: multibuffers, new triggers, clocks, and more

Ping?

-- Steve


On Fri, 2013-03-22 at 17:30 -0400, Steven Rostedt wrote:
> Ingo,
> 
> A lot has changed and this has been in linux-next for a while. Instead
> of spamming LKML with a large patch set, as all changes have already
> been posted to LKML, I'm posting this as one big patch of all the
> changes involved. Here's the summary:
> 
> The biggest change was the addition of multiple tracing buffers and a
> new directory called "instances". Doing a mkdir here creates a new
> tracing directory that has its own buffers. Only trace events can be
> enabled and currently no tracers can (that's for 3.11 ;-). But its fully
> functional. It also includes the ability of snapshots and per cpu
> referencing, and buffer management.
> 
> Use of slabs have brought the memory footprint down a little.
> 
> The tracing files now block as they should and described in the read(2)
> man pages.
> 
> The max_tr has been replaced by the trace_array holding two buffer
> pointers that can now swap. This allows the multiple buffers to also
> take advantage of snapshots.
> 
> Added allocation of the snapshot buffer in the kernel command line.
> 
> Added trace_puts() and special macro magic to trace_printk() to use it
> when it has no arguments to the format string. This makes trace_printk()
> have an even smaller footprint to recording what is happening.
> 
> Added new function triggers, where the function tracer hits a specified
> function, it can enable/disable an event, cause a snapshot, or
> stacktrace.
> 
> Added new trace clocks: uptime and perf
> 
> Added new ring buffer self test, to make sure it doesn't lose any events
> (it never did, but something else caused events to be lost and I thought
> it was the ring buffer).
> 
> Updated some much needed documentation.
> 
> -- Steve
> 
> 
> Please pull the latest tip/perf/core tree, which can be found at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
> tip/perf/core
> 
> Head SHA1: 22f45649ce08642ad7df238d5c25fa5c86bfdd31
> 
> 
> Li Zefan (4):
>       tracing: Add a helper function for event print functions
>       tracing: Annotate event field-defining functions with __init
>       tracing/syscalls: Annotate field-defining functions with __init
>       tracing: Fix some section mismatch warnings
> 
> Steven Rostedt (13):
>       tracing: Separate out trace events from global variables
>       tracing: Use RING_BUFFER_ALL_CPUS for TRACE_PIPE_ALL_CPU
>       tracing: Encapsulate global_trace and remove dependencies on global vars
>       tracing: Pass the ftrace_file to the buffer lock reserve code
>       tracing: Replace the static global per_cpu arrays with allocated per_cpu
>       tracing: Make syscall events suitable for multiple buffers
>       tracing: Add interface to allow multiple trace buffers
>       tracing: Add rmdir to remove multibuffer instances
>       tracing: Get trace_events kernel command line working again
>       tracing: Use kmem_cache_alloc instead of kmalloc in trace_events.c
>       tracing: Use direct field, type and system names
>       tracing: Fix polling on trace_pipe_raw
>       tracing: Fix read blocking on trace_pipe_raw
> 
> Steven Rostedt (Red Hat) (50):
>       tracing: Do not block on splice if either file or splice NONBLOCK flag is set
>       tracing/ring-buffer: Move poll wake ups into ring buffer code
>       tracing: Add __per_cpu annotation to trace array percpu data pointer
>       tracing: Fix trace events build without modules
>       ring-buffer: Init waitqueue for blocked readers
>       tracing: Add comment for trace event flag IGNORE_ENABLE
>       tracing: Only clear trace buffer on module unload if event was traced
>       tracing: Clear all trace buffers when unloaded module event was used
>       tracing: Enable snapshot when any latency tracer is enabled
>       tracing: Consolidate max_tr into main trace_array structure
>       tracing: Add snapshot in the per_cpu trace directories
>       tracing: Add config option to allow snapshot to swap per cpu
>       tracing: Add snapshot_raw to extract the raw data from snapshot
>       tracing: Have trace_array keep track if snapshot buffer is allocated
>       tracing: Consolidate buffer allocation code
>       tracing: Add snapshot feature to instances
>       tracing: Add per_cpu directory into tracing instances
>       tracing: Prevent deleting instances when they are being read
>       tracing: Add internal tracing_snapshot() functions
>       ring-buffer: Do not use schedule_work_on() for current CPU
>       tracing: Move the tracing selftest code into its own function
>       tracing: Add alloc_snapshot kernel command line parameter
>       tracing: Fix the branch tracer that broke with buffer change
>       tracing: Add trace_puts() for even faster trace_printk() tracing
>       tracing: Optimize trace_printk() with one arg to use trace_puts()
>       tracing: Add internal ftrace trace_puts() for ftrace to use
>       tracing: Let tracing_snapshot() be used by modules but not NMI
>       tracing: Consolidate updating of count for traceon/off
>       tracing: Consolidate ftrace_trace_onoff_unreg() into callback
>       ftrace: Separate unlimited probes from count limited probes
>       ftrace: Fix function probe to only enable needed functions
>       tracing: Add alloc/free_snapshot() to replace duplicate code
>       tracing: Add snapshot trigger to function probes
>       tracing: Fix comments for ftrace_event_file/call flags
>       ftrace: Clean up function probe methods
>       ftrace: Use manual free after synchronize_sched() not call_rcu_sched()
>       tracing: Add a way to soft disable trace events
>       tracing: Add function probe triggers to enable/disable events
>       tracing: Add skip argument to trace_dump_stack()
>       tracing: Add function probe to trigger stack traces
>       tracing: Use stack of calling function for stack tracer
>       tracing: Fix stack tracer with fentry use
>       tracing: Remove most or all of stack tracer stack size from stack_max_size
>       tracing: Add function-trace option to disable function tracing of latency tracers
>       tracing: Add "uptime" trace clock that uses jiffies
>       tracing: Add "perf" trace_clock
>       tracing: Bring Documentation/trace/ftrace.txt up to date
>       ring-buffer: Add ring buffer startup selftest
>       tracing: Fix ftrace_dump()
>       tracing: Update debugfs README file
> 
> zhangwei(Jovi) (6):
>       tracing: Use pr_warn_once instead of open coded implementation
>       tracing: Use TRACE_MAX_PRINT instead of constant
>       tracing: Move find_event_field() into trace_events.c
>       tracing: Convert trace_destroy_fields() to static
>       tracing: Fix comment about prefix in arch_syscall_match_sym_name()
>       tracing: Rename trace_event_mutex to trace_event_sem
> 
> ----
>  Documentation/kernel-parameters.txt  |    7 +
>  Documentation/trace/ftrace.txt       | 2097 ++++++++++++++++++++++----------
>  include/linux/ftrace.h               |    6 +-
>  include/linux/ftrace_event.h         |  109 +-
>  include/linux/kernel.h               |   70 +-
>  include/linux/ring_buffer.h          |    6 +
>  include/linux/trace_clock.h          |    1 +
>  include/trace/ftrace.h               |   47 +-
>  kernel/trace/Kconfig                 |   49 +
>  kernel/trace/blktrace.c              |    4 +-
>  kernel/trace/ftrace.c                |   73 +-
>  kernel/trace/ring_buffer.c           |  500 +++++++-
>  kernel/trace/trace.c                 | 2204 ++++++++++++++++++++++++----------
>  kernel/trace/trace.h                 |  144 ++-
>  kernel/trace/trace_branch.c          |    8 +-
>  kernel/trace/trace_clock.c           |   10 +
>  kernel/trace/trace_entries.h         |   23 +-
>  kernel/trace/trace_events.c          | 1421 +++++++++++++++++-----
>  kernel/trace/trace_events_filter.c   |   34 +-
>  kernel/trace/trace_export.c          |    4 +-
>  kernel/trace/trace_functions.c       |  207 +++-
>  kernel/trace/trace_functions_graph.c |   12 +-
>  kernel/trace/trace_irqsoff.c         |   85 +-
>  kernel/trace/trace_kdb.c             |   12 +-
>  kernel/trace/trace_mmiotrace.c       |   12 +-
>  kernel/trace/trace_output.c          |  119 +-
>  kernel/trace/trace_output.h          |    4 +-
>  kernel/trace/trace_sched_switch.c    |    8 +-
>  kernel/trace/trace_sched_wakeup.c    |   87 +-
>  kernel/trace/trace_selftest.c        |   51 +-
>  kernel/trace/trace_stack.c           |   74 +-
>  kernel/trace/trace_syscalls.c        |   90 +-
>  32 files changed, 5672 insertions(+), 1906 deletions(-)
> ---------------------------
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index 6c72381..0edc409 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -320,6 +320,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>  			on: enable for both 32- and 64-bit processes
>  			off: disable for both 32- and 64-bit processes
>  
> +	alloc_snapshot	[FTRACE]
> +			Allocate the ftrace snapshot buffer on boot up when the
> +			main buffer is allocated. This is handy if debugging
> +			and you need to use tracing_snapshot() on boot up, and
> +			do not want to use tracing_snapshot_alloc() as it needs
> +			to be done where GFP_KERNEL allocations are allowed.
> +
>  	amd_iommu=	[HW,X86-64]
>  			Pass parameters to the AMD IOMMU driver in the system.
>  			Possible values are:
> diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
> index a372304..bfe8c29 100644
> --- a/Documentation/trace/ftrace.txt
> +++ b/Documentation/trace/ftrace.txt
> @@ -8,6 +8,7 @@ Copyright 2008 Red Hat Inc.
>  Reviewers:   Elias Oltmanns, Randy Dunlap, Andrew Morton,
>  	     John Kacur, and David Teigland.
>  Written for: 2.6.28-rc2
> +Updated for: 3.10
>  
>  Introduction
>  ------------
> @@ -17,13 +18,16 @@ designers of systems to find what is going on inside the kernel.
>  It can be used for debugging or analyzing latencies and
>  performance issues that take place outside of user-space.
>  
> -Although ftrace is the function tracer, it also includes an
> -infrastructure that allows for other types of tracing. Some of
> -the tracers that are currently in ftrace include a tracer to
> -trace context switches, the time it takes for a high priority
> -task to run after it was woken up, the time interrupts are
> -disabled, and more (ftrace allows for tracer plugins, which
> -means that the list of tracers can always grow).
> +Although ftrace is typically considered the function tracer, it
> +is really a frame work of several assorted tracing utilities.
> +There's latency tracing to examine what occurs between interrupts
> +disabled and enabled, as well as for preemption and from a time
> +a task is woken to the task is actually scheduled in.
> +
> +One of the most common uses of ftrace is the event tracing.
> +Through out the kernel is hundreds of static event points that
> +can be enabled via the debugfs file system to see what is
> +going on in certain parts of the kernel.
>  
> 
>  Implementation Details
> @@ -61,7 +65,7 @@ the extended "/sys/kernel/debug/tracing" path name.
>  
>  That's it! (assuming that you have ftrace configured into your kernel)
>  
> -After mounting the debugfs, you can see a directory called
> +After mounting debugfs, you can see a directory called
>  "tracing".  This directory contains the control and output files
>  of ftrace. Here is a list of some of the key files:
>  
> @@ -84,7 +88,9 @@ of ftrace. Here is a list of some of the key files:
>  
>  	This sets or displays whether writing to the trace
>  	ring buffer is enabled. Echo 0 into this file to disable
> -	the tracer or 1 to enable it.
> +	the tracer or 1 to enable it. Note, this only disables
> +	writing to the ring buffer, the tracing overhead may
> +	still be occurring.
>  
>    trace:
>  
> @@ -109,7 +115,15 @@ of ftrace. Here is a list of some of the key files:
>  
>  	This file lets the user control the amount of data
>  	that is displayed in one of the above output
> -	files.
> +	files. Options also exist to modify how a tracer
> +	or events work (stack traces, timestamps, etc).
> +
> +  options:
> +
> +	This is a directory that has a file for every available
> +	trace option (also in trace_options). Options may also be set
> +	or cleared by writing a "1" or "0" respectively into the
> +	corresponding file with the option name.
>  
>    tracing_max_latency:
>  
> @@ -121,10 +135,17 @@ of ftrace. Here is a list of some of the key files:
>  	latency is greater than the value in this
>  	file. (in microseconds)
>  
> +  tracing_thresh:
> +
> +	Some latency tracers will record a trace whenever the
> +	latency is greater than the number in this file.
> +	Only active when the file contains a number greater than 0.
> +	(in microseconds)
> +
>    buffer_size_kb:
>  
>  	This sets or displays the number of kilobytes each CPU
> -	buffer can hold. The tracer buffers are the same size
> +	buffer holds. By default, the trace buffers are the same size
>  	for each CPU. The displayed number is the size of the
>  	CPU buffer and not total size of all buffers. The
>  	trace buffers are allocated in pages (blocks of memory
> @@ -133,16 +154,30 @@ of ftrace. Here is a list of some of the key files:
>  	than requested, the rest of the page will be used,
>  	making the actual allocation bigger than requested.
>  	( Note, the size may not be a multiple of the page size
> -	  due to buffer management overhead. )
> +	  due to buffer management meta-data. )
>  
> -	This can only be updated when the current_tracer
> -	is set to "nop".
> +  buffer_total_size_kb:
> +
> +	This displays the total combined size of all the trace buffers.
> +
> +  free_buffer:
> +
> +	If a process is performing the tracing, and the ring buffer
> +	should be shrunk "freed" when the process is finished, even
> +	if it were to be killed by a signal, this file can be used
> +	for that purpose. On close of this file, the ring buffer will
> +	be resized to its minimum size. Having a process that is tracing
> +	also open this file, when the process exits its file descriptor
> +	for this file will be closed, and in doing so, the ring buffer
> +	will be "freed".
> +
> +	It may also stop tracing if disable_on_free option is set.
>  
>    tracing_cpumask:
>  
>  	This is a mask that lets the user only trace
> -	on specified CPUS. The format is a hex string
> -	representing the CPUS.
> +	on specified CPUs. The format is a hex string
> +	representing the CPUs.
>  
>    set_ftrace_filter:
>  
> @@ -183,6 +218,261 @@ of ftrace. Here is a list of some of the key files:
>  	"set_ftrace_notrace". (See the section "dynamic ftrace"
>  	below for more details.)
>  
> +  enabled_functions:
> +
> +	This file is more for debugging ftrace, but can also be useful
> +	in seeing if any function has a callback attached to it.
> +	Not only does the trace infrastructure use ftrace function
> +	trace utility, but other subsystems might too. This file
> +	displays all functions that have a callback attached to them
> +	as well as the number of callbacks that have been attached.
> +	Note, a callback may also call multiple functions which will
> +	not be listed in this count.
> +
> +	If the callback registered to be traced by a function with
> +	the "save regs" attribute (thus even more overhead), a 'R'
> +	will be displayed on the same line as the function that
> +	is returning registers.
> +
> +  function_profile_enabled:
> +
> +	When set it will enable all functions with either the function
> +	tracer, or if enabled, the function graph tracer. It will
> +	keep a histogram of the number of functions that were called
> +	and if run with the function graph tracer, it will also keep
> +	track of the time spent in those functions. The histogram
> +	content can be displayed in the files:
> +
> +	trace_stats/function<cpu> ( function0, function1, etc).
> +
> +  trace_stats:
> +
> +	A directory that holds different tracing stats.
> +
> +  kprobe_events:
> + 
> +	Enable dynamic trace points. See kprobetrace.txt.
> +
> +  kprobe_profile:
> +
> +	Dynamic trace points stats. See kprobetrace.txt.
> +
> +  max_graph_depth:
> +
> +	Used with the function graph tracer. This is the max depth
> +	it will trace into a function. Setting this to a value of
> +	one will show only the first kernel function that is called
> +	from user space.
> +
> +  printk_formats:
> +
> +	This is for tools that read the raw format files. If an event in
> +	the ring buffer references a string (currently only trace_printk()
> +	does this), only a pointer to the string is recorded into the buffer
> +	and not the string itself. This prevents tools from knowing what
> +	that string was. This file displays the string and address for
> +	the string allowing tools to map the pointers to what the
> +	strings were.
> +
> +  saved_cmdlines:
> +
> +	Only the pid of the task is recorded in a trace event unless
> +	the event specifically saves the task comm as well. Ftrace
> +	makes a cache of pid mappings to comms to try to display
> +	comms for events. If a pid for a comm is not listed, then
> +	"<...>" is displayed in the output.
> +
> +  snapshot:
> +
> +	This displays the "snapshot" buffer and also lets the user
> +	take a snapshot of the current running trace.
> +	See the "Snapshot" section below for more details.
> +
> +  stack_max_size:
> +
> +	When the stack tracer is activated, this will display the
> +	maximum stack size it has encountered.
> +	See the "Stack Trace" section below.
> +
> +  stack_trace:
> +
> +	This displays the stack back trace of the largest stack
> +	that was encountered when the stack tracer is activated.
> +	See the "Stack Trace" section below.
> +
> +  stack_trace_filter:
> +
> +	This is similar to "set_ftrace_filter" but it limits what
> +	functions the stack tracer will check.
> +
> +  trace_clock:
> +
> +	Whenever an event is recorded into the ring buffer, a
> +	"timestamp" is added. This stamp comes from a specified
> +	clock. By default, ftrace uses the "local" clock. This
> +	clock is very fast and strictly per cpu, but on some
> +	systems it may not be monotonic with respect to other
> +	CPUs. In other words, the local clocks may not be in sync
> +	with local clocks on other CPUs.
> +
> +	Usual clocks for tracing:
> +
> +	  # cat trace_clock
> +	  [local] global counter x86-tsc
> +
> +	  local: Default clock, but may not be in sync across CPUs
> +
> +	  global: This clock is in sync with all CPUs but may
> +	  	  be a bit slower than the local clock.
> +
> +	  counter: This is not a clock at all, but literally an atomic
> +	  	   counter. It counts up one by one, but is in sync
> +		   with all CPUs. This is useful when you need to
> +		   know exactly the order events occurred with respect to
> +		   each other on different CPUs.
> +
> +	  uptime: This uses the jiffies counter and the time stamp
> +	  	  is relative to the time since boot up.
> +
> +	  perf: This makes ftrace use the same clock that perf uses.
> +	  	Eventually perf will be able to read ftrace buffers
> +		and this will help out in interleaving the data.
> +
> +	  x86-tsc: Architectures may define their own clocks. For
> +	  	   example, x86 uses its own TSC cycle clock here.
> +
> +	To set a clock, simply echo the clock name into this file.
> +
> +	  echo global > trace_clock
> +
> +  trace_marker:
> +
> +	This is a very useful file for synchronizing user space
> +	with events happening in the kernel. Writing strings into
> +	this file will be written into the ftrace buffer.
> +
> +	It is useful in applications to open this file at the start
> +	of the application and just reference the file descriptor
> +	for the file.
> +
> +	void trace_write(const char *fmt, ...)
> +	{
> +		va_list ap;
> +		char buf[256];
> +		int n;
> +
> +		if (trace_fd < 0)
> +			return;
> +
> +		va_start(ap, fmt);
> +		n = vsnprintf(buf, 256, fmt, ap);
> +		va_end(ap);
> +
> +		write(trace_fd, buf, n);
> +	}
> +
> +	start:
> +
> +		trace_fd = open("trace_marker", WR_ONLY);
> +
> +  uprobe_events:
> + 
> +	Add dynamic tracepoints in programs.
> +	See uprobetracer.txt
> +
> +  uprobe_profile:
> +
> +	Uprobe statistics. See uprobetrace.txt
> +
> +  instances:
> +
> +	This is a way to make multiple trace buffers where different
> +	events can be recorded in different buffers.
> +	See "Instances" section below.
> +
> +  events:
> +
> +	This is the trace event directory. It holds event tracepoints
> +	(also known as static tracepoints) that have been compiled
> +	into the kernel. It shows what event tracepoints exist
> +	and how they are grouped by system. There are "enable"
> +	files at various levels that can enable the tracepoints
> +	when a "1" is written to them.
> +
> +	See events.txt for more information.
> +
> +  per_cpu:
> +
> +	This is a directory that contains the trace per_cpu information.
> +
> +  per_cpu/cpu0/buffer_size_kb:
> +
> +	The ftrace buffer is defined per_cpu. That is, there's a separate
> +	buffer for each CPU to allow writes to be done atomically,
> +	and free from cache bouncing. These buffers may have different
> +	size buffers. This file is similar to the buffer_size_kb
> +	file, but it only displays or sets the buffer size for the
> +	specific CPU. (here cpu0).
> +
> +  per_cpu/cpu0/trace:
> +
> +	This is similar to the "trace" file, but it will only display
> +	the data specific for the CPU. If written to, it only clears
> +	the specific CPU buffer.
> +
> +  per_cpu/cpu0/trace_pipe
> +
> +	This is similar to the "trace_pipe" file, and is a consuming
> +	read, but it will only display (and consume) the data specific
> +	for the CPU.
> +
> +  per_cpu/cpu0/trace_pipe_raw
> +
> +	For tools that can parse the ftrace ring buffer binary format,
> +	the trace_pipe_raw file can be used to extract the data
> +	from the ring buffer directly. With the use of the splice()
> +	system call, the buffer data can be quickly transferred to
> +	a file or to the network where a server is collecting the
> +	data.
> +
> +	Like trace_pipe, this is a consuming reader, where multiple
> +	reads will always produce different data.
> +
> +  per_cpu/cpu0/snapshot:
> +
> +	This is similar to the main "snapshot" file, but will only
> +	snapshot the current CPU (if supported). It only displays
> +	the content of the snapshot for a given CPU, and if
> +	written to, only clears this CPU buffer.
> +
> +  per_cpu/cpu0/snapshot_raw:
> +
> +	Similar to the trace_pipe_raw, but will read the binary format
> +	from the snapshot buffer for the given CPU.
> +
> +  per_cpu/cpu0/stats:
> +
> +	This displays certain stats about the ring buffer:
> +
> +	 entries: The number of events that are still in the buffer.
> +
> +	 overrun: The number of lost events due to overwriting when
> +	 	  the buffer was full.
> +
> +	 commit overrun: Should always be zero.
> +	 	This gets set if so many events happened within a nested
> +		event (ring buffer is re-entrant), that it fills the
> +		buffer and starts dropping events.
> +
> +	 bytes: Bytes actually read (not overwritten).
> +
> +	 oldest event ts: The oldest timestamp in the buffer
> +
> +	 now ts: The current timestamp
> +
> +	 dropped events: Events lost due to overwrite option being off.
> +
> +	 read events: The number of events read.
>  
>  The Tracers
>  -----------
> @@ -234,11 +524,6 @@ Here is the list of current tracers that may be configured.
>          RT tasks (as the current "wakeup" does). This is useful
>          for those interested in wake up timings of RT tasks.
>  
> -  "hw-branch-tracer"
> -
> -	Uses the BTS CPU feature on x86 CPUs to traces all
> -	branches executed.
> -
>    "nop"
>  
>  	This is the "trace nothing" tracer. To remove all
> @@ -261,70 +546,100 @@ Here is an example of the output format of the file "trace"
>                               --------
>  # tracer: function
>  #
> -#           TASK-PID   CPU#    TIMESTAMP  FUNCTION
> -#              | |      |          |         |
> -            bash-4251  [01] 10152.583854: path_put <-path_walk
> -            bash-4251  [01] 10152.583855: dput <-path_put
> -            bash-4251  [01] 10152.583855: _atomic_dec_and_lock <-dput
> +# entries-in-buffer/entries-written: 140080/250280   #P:4
> +#
> +#                              _-----=> irqs-off
> +#                             / _----=> need-resched
> +#                            | / _---=> hardirq/softirq
> +#                            || / _--=> preempt-depth
> +#                            ||| /     delay
> +#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> +#              | |       |   ||||       |         |
> +            bash-1977  [000] .... 17284.993652: sys_close <-system_call_fastpath
> +            bash-1977  [000] .... 17284.993653: __close_fd <-sys_close
> +            bash-1977  [000] .... 17284.993653: _raw_spin_lock <-__close_fd
> +            sshd-1974  [003] .... 17284.993653: __srcu_read_unlock <-fsnotify
> +            bash-1977  [000] .... 17284.993654: add_preempt_count <-_raw_spin_lock
> +            bash-1977  [000] ...1 17284.993655: _raw_spin_unlock <-__close_fd
> +            bash-1977  [000] ...1 17284.993656: sub_preempt_count <-_raw_spin_unlock
> +            bash-1977  [000] .... 17284.993657: filp_close <-__close_fd
> +            bash-1977  [000] .... 17284.993657: dnotify_flush <-filp_close
> +            sshd-1974  [003] .... 17284.993658: sys_select <-system_call_fastpath
>                               --------
>  
>  A header is printed with the tracer name that is represented by
> -the trace. In this case the tracer is "function". Then a header
> -showing the format. Task name "bash", the task PID "4251", the
> -CPU that it was running on "01", the timestamp in <secs>.<usecs>
> -format, the function name that was traced "path_put" and the
> -parent function that called this function "path_walk". The
> -timestamp is the time at which the function was entered.
> +the trace. In this case the tracer is "function". Then it shows the
> +number of events in the buffer as well as the total number of entries
> +that were written. The difference is the number of entries that were
> +lost due to the buffer filling up (250280 - 140080 = 110200 events
> +lost).
> +
> +The header explains the content of the events. Task name "bash", the task
> +PID "1977", the CPU that it was running on "000", the latency format
> +(explained below), the timestamp in <secs>.<usecs> format, the
> +function name that was traced "sys_close" and the parent function that
> +called this function "system_call_fastpath". The timestamp is the time
> +at which the function was entered.
>  
>  Latency trace format
>  --------------------
>  
> -When the latency-format option is enabled, the trace file gives
> -somewhat more information to see why a latency happened.
> -Here is a typical trace.
> +When the latency-format option is enabled or when one of the latency
> +tracers is set, the trace file gives somewhat more information to see
> +why a latency happened. Here is a typical trace.
>  
>  # tracer: irqsoff
>  #
> -irqsoff latency trace v1.1.5 on 2.6.26-rc8
> ---------------------------------------------------------------------
> - latency: 97 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: swapper-0 (uid:0 nice:0 policy:0 rt_prio:0)
> -    -----------------
> - => started at: apic_timer_interrupt
> - => ended at:   do_softirq
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -  <idle>-0     0d..1    0us+: trace_hardirqs_off_thunk (apic_timer_interrupt)
> -  <idle>-0     0d.s.   97us : __do_softirq (do_softirq)
> -  <idle>-0     0d.s1   98us : trace_hardirqs_on (do_softirq)
> +# irqsoff latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 259 us, #4/4, CPU#2 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: ps-6143 (uid:0 nice:0 policy:0 rt_prio:0)
> +#    -----------------
> +#  => started at: __lock_task_sighand
> +#  => ended at:   _raw_spin_unlock_irqrestore
> +#
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +      ps-6143    2d...    0us!: trace_hardirqs_off <-__lock_task_sighand
> +      ps-6143    2d..1  259us+: trace_hardirqs_on <-_raw_spin_unlock_irqrestore
> +      ps-6143    2d..1  263us+: time_hardirqs_on <-_raw_spin_unlock_irqrestore
> +      ps-6143    2d..1  306us : <stack trace>
> + => trace_hardirqs_on_caller
> + => trace_hardirqs_on
> + => _raw_spin_unlock_irqrestore
> + => do_task_stat
> + => proc_tgid_stat
> + => proc_single_show
> + => seq_read
> + => vfs_read
> + => sys_read
> + => system_call_fastpath
>  
> 
>  This shows that the current tracer is "irqsoff" tracing the time
> -for which interrupts were disabled. It gives the trace version
> -and the version of the kernel upon which this was executed on
> -(2.6.26-rc8). Then it displays the max latency in microsecs (97
> -us). The number of trace entries displayed and the total number
> -recorded (both are three: #3/3). The type of preemption that was
> -used (PREEMPT). VP, KP, SP, and HP are always zero and are
> -reserved for later use. #P is the number of online CPUS (#P:2).
> +for which interrupts were disabled. It gives the trace version (which
> +never changes) and the version of the kernel upon which this was executed on
> +(3.10). Then it displays the max latency in microseconds (259 us). The number
> +of trace entries displayed and the total number (both are four: #4/4).
> +VP, KP, SP, and HP are always zero and are reserved for later use.
> +#P is the number of online CPUs (#P:4).
>  
>  The task is the process that was running when the latency
> -occurred. (swapper pid: 0).
> +occurred. (ps pid: 6143).
>  
>  The start and stop (the functions in which the interrupts were
>  disabled and enabled respectively) that caused the latencies:
>  
> -  apic_timer_interrupt is where the interrupts were disabled.
> -  do_softirq is where they were enabled again.
> + __lock_task_sighand is where the interrupts were disabled.
> + _raw_spin_unlock_irqrestore is where they were enabled again.
>  
>  The next lines after the header are the trace itself. The header
>  explains which is which.
> @@ -367,16 +682,43 @@ The above is mostly meaningful for kernel developers.
>  
>    The rest is the same as the 'trace' file.
>  
> +  Note, the latency tracers will usually end with a back trace
> +  to easily find where the latency occurred.
>  
>  trace_options
>  -------------
>  
> -The trace_options file is used to control what gets printed in
> -the trace output. To see what is available, simply cat the file:
> +The trace_options file (or the options directory) is used to control
> +what gets printed in the trace output, or manipulate the tracers.
> +To see what is available, simply cat the file:
>  
>    cat trace_options
> -  print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \
> -  noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj
> +print-parent
> +nosym-offset
> +nosym-addr
> +noverbose
> +noraw
> +nohex
> +nobin
> +noblock
> +nostacktrace
> +trace_printk
> +noftrace_preempt
> +nobranch
> +annotate
> +nouserstacktrace
> +nosym-userobj
> +noprintk-msg-only
> +context-info
> +latency-format
> +sleep-time
> +graph-time
> +record-cmd
> +overwrite
> +nodisable_on_free
> +irq-info
> +markers
> +function-trace
>  
>  To disable one of the options, echo in the option prepended with
>  "no".
> @@ -428,13 +770,34 @@ Here are the available options:
>  
>    bin - This will print out the formats in raw binary.
>  
> -  block - TBD (needs update)
> +  block - When set, reading trace_pipe will not block when polled.
>  
>    stacktrace - This is one of the options that changes the trace
>  	       itself. When a trace is recorded, so is the stack
>  	       of functions. This allows for back traces of
>  	       trace sites.
>  
> +  trace_printk - Can disable trace_printk() from writing into the buffer.
> +
> +  branch - Enable branch tracing with the tracer.
> +
> +  annotate - It is sometimes confusing when the CPU buffers are full
> +  	     and one CPU buffer had a lot of events recently, thus
> +	     a shorter time frame, were another CPU may have only had
> +	     a few events, which lets it have older events. When
> +	     the trace is reported, it shows the oldest events first,
> +	     and it may look like only one CPU ran (the one with the
> +	     oldest events). When the annotate option is set, it will
> +	     display when a new CPU buffer started:
> +
> +          <idle>-0     [001] dNs4 21169.031481: wake_up_idle_cpu <-add_timer_on
> +          <idle>-0     [001] dNs4 21169.031482: _raw_spin_unlock_irqrestore <-add_timer_on
> +          <idle>-0     [001] .Ns4 21169.031484: sub_preempt_count <-_raw_spin_unlock_irqrestore
> +##### CPU 2 buffer started ####
> +          <idle>-0     [002] .N.1 21169.031484: rcu_idle_exit <-cpu_idle
> +          <idle>-0     [001] .Ns3 21169.031484: _raw_spin_unlock <-clocksource_watchdog
> +          <idle>-0     [001] .Ns3 21169.031485: sub_preempt_count <-_raw_spin_unlock
> +
>    userstacktrace - This option changes the trace. It records a
>  		   stacktrace of the current userspace thread.
>  
> @@ -451,9 +814,13 @@ Here are the available options:
>  		a.out-1623  [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0
>  x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
>  
> -  sched-tree - trace all tasks that are on the runqueue, at
> -	       every scheduling event. Will add overhead if
> -	       there's a lot of tasks running at once.
> +
> +  printk-msg-only - When set, trace_printk()s will only show the format
> +  		    and not their parameters (if trace_bprintk() or
> +		    trace_bputs() was used to save the trace_printk()).
> +
> +  context-info - Show only the event data. Hides the comm, PID,
> +  	         timestamp, CPU, and other useful data.
>  
>    latency-format - This option changes the trace. When
>                     it is enabled, the trace displays
> @@ -461,31 +828,61 @@ x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
>                     latencies, as described in "Latency
>                     trace format".
>  
> +  sleep-time - When running function graph tracer, to include
> +  	       the time a task schedules out in its function.
> +	       When enabled, it will account time the task has been
> +	       scheduled out as part of the function call.
> +
> +  graph-time - When running function graph tracer, to include the
> +  	       time to call nested functions. When this is not set,
> +	       the time reported for the function will only include
> +	       the time the function itself executed for, not the time
> +	       for functions that it called.
> +
> +  record-cmd - When any event or tracer is enabled, a hook is enabled
> +  	       in the sched_switch trace point to fill comm cache
> +	       with mapped pids and comms. But this may cause some
> +	       overhead, and if you only care about pids, and not the
> +	       name of the task, disabling this option can lower the
> +	       impact of tracing.
> +
>    overwrite - This controls what happens when the trace buffer is
>                full. If "1" (default), the oldest events are
>                discarded and overwritten. If "0", then the newest
>                events are discarded.
> +	        (see per_cpu/cpu0/stats for overrun and dropped)
>  
> -ftrace_enabled
> ---------------
> +  disable_on_free - When the free_buffer is closed, tracing will
> +  		    stop (tracing_on set to 0).
>  
> -The following tracers (listed below) give different output
> -depending on whether or not the sysctl ftrace_enabled is set. To
> -set ftrace_enabled, one can either use the sysctl function or
> -set it via the proc file system interface.
> +  irq-info - Shows the interrupt, preempt count, need resched data.
> +  	     When disabled, the trace looks like:
>  
> -  sysctl kernel.ftrace_enabled=1
> +# tracer: function
> +#
> +# entries-in-buffer/entries-written: 144405/9452052   #P:4
> +#
> +#           TASK-PID   CPU#      TIMESTAMP  FUNCTION
> +#              | |       |          |         |
> +          <idle>-0     [002]  23636.756054: ttwu_do_activate.constprop.89 <-try_to_wake_up
> +          <idle>-0     [002]  23636.756054: activate_task <-ttwu_do_activate.constprop.89
> +          <idle>-0     [002]  23636.756055: enqueue_task <-activate_task
>  
> - or
>  
> -  echo 1 > /proc/sys/kernel/ftrace_enabled
> +  markers - When set, the trace_marker is writable (only by root).
> +  	    When disabled, the trace_marker will error with EINVAL
> +	    on write.
> +
> +
> +  function-trace - The latency tracers will enable function tracing
> +  	    if this option is enabled (default it is). When
> +	    it is disabled, the latency tracers do not trace
> +	    functions. This keeps the overhead of the tracer down
> +	    when performing latency tests.
>  
> -To disable ftrace_enabled simply replace the '1' with '0' in the
> -above commands.
> + Note: Some tracers have their own options. They only appear
> +       when the tracer is active.
>  
> -When ftrace_enabled is set the tracers will also record the
> -functions that are within the trace. The descriptions of the
> -tracers will also show an example with ftrace enabled.
>  
> 
>  irqsoff
> @@ -506,95 +903,133 @@ new trace is saved.
>  To reset the maximum, echo 0 into tracing_max_latency. Here is
>  an example:
>  
> + # echo 0 > options/function-trace
>   # echo irqsoff > current_tracer
> - # echo latency-format > trace_options
> - # echo 0 > tracing_max_latency
>   # echo 1 > tracing_on
> + # echo 0 > tracing_max_latency
>   # ls -ltr
>   [...]
>   # echo 0 > tracing_on
>   # cat trace
>  # tracer: irqsoff
>  #
> -irqsoff latency trace v1.1.5 on 2.6.26
> ---------------------------------------------------------------------
> - latency: 12 us, #3/3, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: bash-3730 (uid:0 nice:0 policy:0 rt_prio:0)
> -    -----------------
> - => started at: sys_setpgid
> - => ended at:   sys_setpgid
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -    bash-3730  1d...    0us : _write_lock_irq (sys_setpgid)
> -    bash-3730  1d..1    1us+: _write_unlock_irq (sys_setpgid)
> -    bash-3730  1d..2   14us : trace_hardirqs_on (sys_setpgid)
> -
> -
> -Here we see that that we had a latency of 12 microsecs (which is
> -very good). The _write_lock_irq in sys_setpgid disabled
> -interrupts. The difference between the 12 and the displayed
> -timestamp 14us occurred because the clock was incremented
> +# irqsoff latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 16 us, #4/4, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: swapper/0-0 (uid:0 nice:0 policy:0 rt_prio:0)
> +#    -----------------
> +#  => started at: run_timer_softirq
> +#  => ended at:   run_timer_softirq
> +#
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +  <idle>-0       0d.s2    0us+: _raw_spin_lock_irq <-run_timer_softirq
> +  <idle>-0       0dNs3   17us : _raw_spin_unlock_irq <-run_timer_softirq
> +  <idle>-0       0dNs3   17us+: trace_hardirqs_on <-run_timer_softirq
> +  <idle>-0       0dNs3   25us : <stack trace>
> + => _raw_spin_unlock_irq
> + => run_timer_softirq
> + => __do_softirq
> + => call_softirq
> + => do_softirq
> + => irq_exit
> + => smp_apic_timer_interrupt
> + => apic_timer_interrupt
> + => rcu_idle_exit
> + => cpu_idle
> + => rest_init
> + => start_kernel
> + => x86_64_start_reservations
> + => x86_64_start_kernel
> +
> +Here we see that that we had a latency of 16 microseconds (which is
> +very good). The _raw_spin_lock_irq in run_timer_softirq disabled
> +interrupts. The difference between the 16 and the displayed
> +timestamp 25us occurred because the clock was incremented
>  between the time of recording the max latency and the time of
>  recording the function that had that latency.
>  
> -Note the above example had ftrace_enabled not set. If we set the
> -ftrace_enabled, we get a much larger output:
> +Note the above example had function-trace not set. If we set
> +function-trace, we get a much larger output:
> +
> + with echo 1 > options/function-trace
>  
>  # tracer: irqsoff
>  #
> -irqsoff latency trace v1.1.5 on 2.6.26-rc8
> ---------------------------------------------------------------------
> - latency: 50 us, #101/101, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: ls-4339 (uid:0 nice:0 policy:0 rt_prio:0)
> -    -----------------
> - => started at: __alloc_pages_internal
> - => ended at:   __alloc_pages_internal
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -      ls-4339  0...1    0us+: get_page_from_freelist (__alloc_pages_internal)
> -      ls-4339  0d..1    3us : rmqueue_bulk (get_page_from_freelist)
> -      ls-4339  0d..1    3us : _spin_lock (rmqueue_bulk)
> -      ls-4339  0d..1    4us : add_preempt_count (_spin_lock)
> -      ls-4339  0d..2    4us : __rmqueue (rmqueue_bulk)
> -      ls-4339  0d..2    5us : __rmqueue_smallest (__rmqueue)
> -      ls-4339  0d..2    5us : __mod_zone_page_state (__rmqueue_smallest)
> -      ls-4339  0d..2    6us : __rmqueue (rmqueue_bulk)
> -      ls-4339  0d..2    6us : __rmqueue_smallest (__rmqueue)
> -      ls-4339  0d..2    7us : __mod_zone_page_state (__rmqueue_smallest)
> -      ls-4339  0d..2    7us : __rmqueue (rmqueue_bulk)
> -      ls-4339  0d..2    8us : __rmqueue_smallest (__rmqueue)
> +# irqsoff latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 71 us, #168/168, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: bash-2042 (uid:0 nice:0 policy:0 rt_prio:0)
> +#    -----------------
> +#  => started at: ata_scsi_queuecmd
> +#  => ended at:   ata_scsi_queuecmd
> +#
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +    bash-2042    3d...    0us : _raw_spin_lock_irqsave <-ata_scsi_queuecmd
> +    bash-2042    3d...    0us : add_preempt_count <-_raw_spin_lock_irqsave
> +    bash-2042    3d..1    1us : ata_scsi_find_dev <-ata_scsi_queuecmd
> +    bash-2042    3d..1    1us : __ata_scsi_find_dev <-ata_scsi_find_dev
> +    bash-2042    3d..1    2us : ata_find_dev.part.14 <-__ata_scsi_find_dev
> +    bash-2042    3d..1    2us : ata_qc_new_init <-__ata_scsi_queuecmd
> +    bash-2042    3d..1    3us : ata_sg_init <-__ata_scsi_queuecmd
> +    bash-2042    3d..1    4us : ata_scsi_rw_xlat <-__ata_scsi_queuecmd
> +    bash-2042    3d..1    4us : ata_build_rw_tf <-ata_scsi_rw_xlat
>  [...]
> -      ls-4339  0d..2   46us : __rmqueue_smallest (__rmqueue)
> -      ls-4339  0d..2   47us : __mod_zone_page_state (__rmqueue_smallest)
> -      ls-4339  0d..2   47us : __rmqueue (rmqueue_bulk)
> -      ls-4339  0d..2   48us : __rmqueue_smallest (__rmqueue)
> -      ls-4339  0d..2   48us : __mod_zone_page_state (__rmqueue_smallest)
> -      ls-4339  0d..2   49us : _spin_unlock (rmqueue_bulk)
> -      ls-4339  0d..2   49us : sub_preempt_count (_spin_unlock)
> -      ls-4339  0d..1   50us : get_page_from_freelist (__alloc_pages_internal)
> -      ls-4339  0d..2   51us : trace_hardirqs_on (__alloc_pages_internal)
> -
> -
> -
> -Here we traced a 50 microsecond latency. But we also see all the
> +    bash-2042    3d..1   67us : delay_tsc <-__delay
> +    bash-2042    3d..1   67us : add_preempt_count <-delay_tsc
> +    bash-2042    3d..2   67us : sub_preempt_count <-delay_tsc
> +    bash-2042    3d..1   67us : add_preempt_count <-delay_tsc
> +    bash-2042    3d..2   68us : sub_preempt_count <-delay_tsc
> +    bash-2042    3d..1   68us+: ata_bmdma_start <-ata_bmdma_qc_issue
> +    bash-2042    3d..1   71us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
> +    bash-2042    3d..1   71us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
> +    bash-2042    3d..1   72us+: trace_hardirqs_on <-ata_scsi_queuecmd
> +    bash-2042    3d..1  120us : <stack trace>
> + => _raw_spin_unlock_irqrestore
> + => ata_scsi_queuecmd
> + => scsi_dispatch_cmd
> + => scsi_request_fn
> + => __blk_run_queue_uncond
> + => __blk_run_queue
> + => blk_queue_bio
> + => generic_make_request
> + => submit_bio
> + => submit_bh
> + => __ext3_get_inode_loc
> + => ext3_iget
> + => ext3_lookup
> + => lookup_real
> + => __lookup_hash
> + => walk_component
> + => lookup_last
> + => path_lookupat
> + => filename_lookup
> + => user_path_at_empty
> + => user_path_at
> + => vfs_fstatat
> + => vfs_stat
> + => sys_newstat
> + => system_call_fastpath
> +
> +
> +Here we traced a 71 microsecond latency. But we also see all the
>  functions that were called during that time. Note that by
>  enabling function tracing, we incur an added overhead. This
>  overhead may extend the latency times. But nevertheless, this
> @@ -614,120 +1049,122 @@ Like the irqsoff tracer, it records the maximum latency for
>  which preemption was disabled. The control of preemptoff tracer
>  is much like the irqsoff tracer.
>  
> + # echo 0 > options/function-trace
>   # echo preemptoff > current_tracer
> - # echo latency-format > trace_options
> - # echo 0 > tracing_max_latency
>   # echo 1 > tracing_on
> + # echo 0 > tracing_max_latency
>   # ls -ltr
>   [...]
>   # echo 0 > tracing_on
>   # cat trace
>  # tracer: preemptoff
>  #
> -preemptoff latency trace v1.1.5 on 2.6.26-rc8
> ---------------------------------------------------------------------
> - latency: 29 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0)
> -    -----------------
> - => started at: do_IRQ
> - => ended at:   __do_softirq
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -    sshd-4261  0d.h.    0us+: irq_enter (do_IRQ)
> -    sshd-4261  0d.s.   29us : _local_bh_enable (__do_softirq)
> -    sshd-4261  0d.s1   30us : trace_preempt_on (__do_softirq)
> +# preemptoff latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 46 us, #4/4, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: sshd-1991 (uid:0 nice:0 policy:0 rt_prio:0)
> +#    -----------------
> +#  => started at: do_IRQ
> +#  => ended at:   do_IRQ
> +#
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +    sshd-1991    1d.h.    0us+: irq_enter <-do_IRQ
> +    sshd-1991    1d..1   46us : irq_exit <-do_IRQ
> +    sshd-1991    1d..1   47us+: trace_preempt_on <-do_IRQ
> +    sshd-1991    1d..1   52us : <stack trace>
> + => sub_preempt_count
> + => irq_exit
> + => do_IRQ
> + => ret_from_intr
>  
> 
>  This has some more changes. Preemption was disabled when an
> -interrupt came in (notice the 'h'), and was enabled while doing
> -a softirq. (notice the 's'). But we also see that interrupts
> -have been disabled when entering the preempt off section and
> -leaving it (the 'd'). We do not know if interrupts were enabled
> -in the mean time.
> +interrupt came in (notice the 'h'), and was enabled on exit.
> +But we also see that interrupts have been disabled when entering
> +the preempt off section and leaving it (the 'd'). We do not know if
> +interrupts were enabled in the mean time or shortly after this
> +was over.
>  
>  # tracer: preemptoff
>  #
> -preemptoff latency trace v1.1.5 on 2.6.26-rc8
> ---------------------------------------------------------------------
> - latency: 63 us, #87/87, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0)
> -    -----------------
> - => started at: remove_wait_queue
> - => ended at:   __do_softirq
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -    sshd-4261  0d..1    0us : _spin_lock_irqsave (remove_wait_queue)
> -    sshd-4261  0d..1    1us : _spin_unlock_irqrestore (remove_wait_queue)
> -    sshd-4261  0d..1    2us : do_IRQ (common_interrupt)
> -    sshd-4261  0d..1    2us : irq_enter (do_IRQ)
> -    sshd-4261  0d..1    2us : idle_cpu (irq_enter)
> -    sshd-4261  0d..1    3us : add_preempt_count (irq_enter)
> -    sshd-4261  0d.h1    3us : idle_cpu (irq_enter)
> -    sshd-4261  0d.h.    4us : handle_fasteoi_irq (do_IRQ)
> +# preemptoff latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 83 us, #241/241, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: bash-1994 (uid:0 nice:0 policy:0 rt_prio:0)
> +#    -----------------
> +#  => started at: wake_up_new_task
> +#  => ended at:   task_rq_unlock
> +#
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +    bash-1994    1d..1    0us : _raw_spin_lock_irqsave <-wake_up_new_task
> +    bash-1994    1d..1    0us : select_task_rq_fair <-select_task_rq
> +    bash-1994    1d..1    1us : __rcu_read_lock <-select_task_rq_fair
> +    bash-1994    1d..1    1us : source_load <-select_task_rq_fair
> +    bash-1994    1d..1    1us : source_load <-select_task_rq_fair
>  [...]
> -    sshd-4261  0d.h.   12us : add_preempt_count (_spin_lock)
> -    sshd-4261  0d.h1   12us : ack_ioapic_quirk_irq (handle_fasteoi_irq)
> -    sshd-4261  0d.h1   13us : move_native_irq (ack_ioapic_quirk_irq)
> -    sshd-4261  0d.h1   13us : _spin_unlock (handle_fasteoi_irq)
> -    sshd-4261  0d.h1   14us : sub_preempt_count (_spin_unlock)
> -    sshd-4261  0d.h1   14us : irq_exit (do_IRQ)
> -    sshd-4261  0d.h1   15us : sub_preempt_count (irq_exit)
> -    sshd-4261  0d..2   15us : do_softirq (irq_exit)
> -    sshd-4261  0d...   15us : __do_softirq (do_softirq)
> -    sshd-4261  0d...   16us : __local_bh_disable (__do_softirq)
> -    sshd-4261  0d...   16us+: add_preempt_count (__local_bh_disable)
> -    sshd-4261  0d.s4   20us : add_preempt_count (__local_bh_disable)
> -    sshd-4261  0d.s4   21us : sub_preempt_count (local_bh_enable)
> -    sshd-4261  0d.s5   21us : sub_preempt_count (local_bh_enable)
> +    bash-1994    1d..1   12us : irq_enter <-smp_apic_timer_interrupt
> +    bash-1994    1d..1   12us : rcu_irq_enter <-irq_enter
> +    bash-1994    1d..1   13us : add_preempt_count <-irq_enter
> +    bash-1994    1d.h1   13us : exit_idle <-smp_apic_timer_interrupt
> +    bash-1994    1d.h1   13us : hrtimer_interrupt <-smp_apic_timer_interrupt
> +    bash-1994    1d.h1   13us : _raw_spin_lock <-hrtimer_interrupt
> +    bash-1994    1d.h1   14us : add_preempt_count <-_raw_spin_lock
> +    bash-1994    1d.h2   14us : ktime_get_update_offsets <-hrtimer_interrupt
>  [...]
> -    sshd-4261  0d.s6   41us : add_preempt_count (__local_bh_disable)
> -    sshd-4261  0d.s6   42us : sub_preempt_count (local_bh_enable)
> -    sshd-4261  0d.s7   42us : sub_preempt_count (local_bh_enable)
> -    sshd-4261  0d.s5   43us : add_preempt_count (__local_bh_disable)
> -    sshd-4261  0d.s5   43us : sub_preempt_count (local_bh_enable_ip)
> -    sshd-4261  0d.s6   44us : sub_preempt_count (local_bh_enable_ip)
> -    sshd-4261  0d.s5   44us : add_preempt_count (__local_bh_disable)
> -    sshd-4261  0d.s5   45us : sub_preempt_count (local_bh_enable)
> +    bash-1994    1d.h1   35us : lapic_next_event <-clockevents_program_event
> +    bash-1994    1d.h1   35us : irq_exit <-smp_apic_timer_interrupt
> +    bash-1994    1d.h1   36us : sub_preempt_count <-irq_exit
> +    bash-1994    1d..2   36us : do_softirq <-irq_exit
> +    bash-1994    1d..2   36us : __do_softirq <-call_softirq
> +    bash-1994    1d..2   36us : __local_bh_disable <-__do_softirq
> +    bash-1994    1d.s2   37us : add_preempt_count <-_raw_spin_lock_irq
> +    bash-1994    1d.s3   38us : _raw_spin_unlock <-run_timer_softirq
> +    bash-1994    1d.s3   39us : sub_preempt_count <-_raw_spin_unlock
> +    bash-1994    1d.s2   39us : call_timer_fn <-run_timer_softirq
>  [...]
> -    sshd-4261  0d.s.   63us : _local_bh_enable (__do_softirq)
> -    sshd-4261  0d.s1   64us : trace_preempt_on (__do_softirq)
> +    bash-1994    1dNs2   81us : cpu_needs_another_gp <-rcu_process_callbacks
> +    bash-1994    1dNs2   82us : __local_bh_enable <-__do_softirq
> +    bash-1994    1dNs2   82us : sub_preempt_count <-__local_bh_enable
> +    bash-1994    1dN.2   82us : idle_cpu <-irq_exit
> +    bash-1994    1dN.2   83us : rcu_irq_exit <-irq_exit
> +    bash-1994    1dN.2   83us : sub_preempt_count <-irq_exit
> +    bash-1994    1.N.1   84us : _raw_spin_unlock_irqrestore <-task_rq_unlock
> +    bash-1994    1.N.1   84us+: trace_preempt_on <-task_rq_unlock
> +    bash-1994    1.N.1  104us : <stack trace>
> + => sub_preempt_count
> + => _raw_spin_unlock_irqrestore
> + => task_rq_unlock
> + => wake_up_new_task
> + => do_fork
> + => sys_clone
> + => stub_clone
>  
> 
>  The above is an example of the preemptoff trace with
> -ftrace_enabled set. Here we see that interrupts were disabled
> +function-trace set. Here we see that interrupts were not disabled
>  the entire time. The irq_enter code lets us know that we entered
>  an interrupt 'h'. Before that, the functions being traced still
>  show that it is not in an interrupt, but we can see from the
>  functions themselves that this is not the case.
>  
> -Notice that __do_softirq when called does not have a
> -preempt_count. It may seem that we missed a preempt enabling.
> -What really happened is that the preempt count is held on the
> -thread's stack and we switched to the softirq stack (4K stacks
> -in effect). The code does not copy the preempt count, but
> -because interrupts are disabled, we do not need to worry about
> -it. Having a tracer like this is good for letting people know
> -what really happens inside the kernel.
> -
> -
>  preemptirqsoff
>  --------------
>  
> @@ -762,38 +1199,57 @@ tracer.
>  Again, using this trace is much like the irqsoff and preemptoff
>  tracers.
>  
> + # echo 0 > options/function-trace
>   # echo preemptirqsoff > current_tracer
> - # echo latency-format > trace_options
> - # echo 0 > tracing_max_latency
>   # echo 1 > tracing_on
> + # echo 0 > tracing_max_latency
>   # ls -ltr
>   [...]
>   # echo 0 > tracing_on
>   # cat trace
>  # tracer: preemptirqsoff
>  #
> -preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8
> ---------------------------------------------------------------------
> - latency: 293 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: ls-4860 (uid:0 nice:0 policy:0 rt_prio:0)
> -    -----------------
> - => started at: apic_timer_interrupt
> - => ended at:   __do_softirq
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -      ls-4860  0d...    0us!: trace_hardirqs_off_thunk (apic_timer_interrupt)
> -      ls-4860  0d.s.  294us : _local_bh_enable (__do_softirq)
> -      ls-4860  0d.s1  294us : trace_preempt_on (__do_softirq)
> -
> +# preemptirqsoff latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 100 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: ls-2230 (uid:0 nice:0 policy:0 rt_prio:0)
> +#    -----------------
> +#  => started at: ata_scsi_queuecmd
> +#  => ended at:   ata_scsi_queuecmd
> +#
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +      ls-2230    3d...    0us+: _raw_spin_lock_irqsave <-ata_scsi_queuecmd
> +      ls-2230    3...1  100us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
> +      ls-2230    3...1  101us+: trace_preempt_on <-ata_scsi_queuecmd
> +      ls-2230    3...1  111us : <stack trace>
> + => sub_preempt_count
> + => _raw_spin_unlock_irqrestore
> + => ata_scsi_queuecmd
> + => scsi_dispatch_cmd
> + => scsi_request_fn
> + => __blk_run_queue_uncond
> + => __blk_run_queue
> + => blk_queue_bio
> + => generic_make_request
> + => submit_bio
> + => submit_bh
> + => ext3_bread
> + => ext3_dir_bread
> + => htree_dirblock_to_tree
> + => ext3_htree_fill_tree
> + => ext3_readdir
> + => vfs_readdir
> + => sys_getdents
> + => system_call_fastpath
>  
> 
>  The trace_hardirqs_off_thunk is called from assembly on x86 when
> @@ -802,105 +1258,158 @@ function tracing, we do not know if interrupts were enabled
>  within the preemption points. We do see that it started with
>  preemption enabled.
>  
> -Here is a trace with ftrace_enabled set:
> -
> +Here is a trace with function-trace set:
>  
>  # tracer: preemptirqsoff
>  #
> -preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8
> ---------------------------------------------------------------------
> - latency: 105 us, #183/183, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0)
> -    -----------------
> - => started at: write_chan
> - => ended at:   __do_softirq
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -      ls-4473  0.N..    0us : preempt_schedule (write_chan)
> -      ls-4473  0dN.1    1us : _spin_lock (schedule)
> -      ls-4473  0dN.1    2us : add_preempt_count (_spin_lock)
> -      ls-4473  0d..2    2us : put_prev_task_fair (schedule)
> -[...]
> -      ls-4473  0d..2   13us : set_normalized_timespec (ktime_get_ts)
> -      ls-4473  0d..2   13us : __switch_to (schedule)
> -    sshd-4261  0d..2   14us : finish_task_switch (schedule)
> -    sshd-4261  0d..2   14us : _spin_unlock_irq (finish_task_switch)
> -    sshd-4261  0d..1   15us : add_preempt_count (_spin_lock_irqsave)
> -    sshd-4261  0d..2   16us : _spin_unlock_irqrestore (hrtick_set)
> -    sshd-4261  0d..2   16us : do_IRQ (common_interrupt)
> -    sshd-4261  0d..2   17us : irq_enter (do_IRQ)
> -    sshd-4261  0d..2   17us : idle_cpu (irq_enter)
> -    sshd-4261  0d..2   18us : add_preempt_count (irq_enter)
> -    sshd-4261  0d.h2   18us : idle_cpu (irq_enter)
> -    sshd-4261  0d.h.   18us : handle_fasteoi_irq (do_IRQ)
> -    sshd-4261  0d.h.   19us : _spin_lock (handle_fasteoi_irq)
> -    sshd-4261  0d.h.   19us : add_preempt_count (_spin_lock)
> -    sshd-4261  0d.h1   20us : _spin_unlock (handle_fasteoi_irq)
> -    sshd-4261  0d.h1   20us : sub_preempt_count (_spin_unlock)
> -[...]
> -    sshd-4261  0d.h1   28us : _spin_unlock (handle_fasteoi_irq)
> -    sshd-4261  0d.h1   29us : sub_preempt_count (_spin_unlock)
> -    sshd-4261  0d.h2   29us : irq_exit (do_IRQ)
> -    sshd-4261  0d.h2   29us : sub_preempt_count (irq_exit)
> -    sshd-4261  0d..3   30us : do_softirq (irq_exit)
> -    sshd-4261  0d...   30us : __do_softirq (do_softirq)
> -    sshd-4261  0d...   31us : __local_bh_disable (__do_softirq)
> -    sshd-4261  0d...   31us+: add_preempt_count (__local_bh_disable)
> -    sshd-4261  0d.s4   34us : add_preempt_count (__local_bh_disable)
> +# preemptirqsoff latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 161 us, #339/339, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: ls-2269 (uid:0 nice:0 policy:0 rt_prio:0)
> +#    -----------------
> +#  => started at: schedule
> +#  => ended at:   mutex_unlock
> +#
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +kworker/-59      3...1    0us : __schedule <-schedule
> +kworker/-59      3d..1    0us : rcu_preempt_qs <-rcu_note_context_switch
> +kworker/-59      3d..1    1us : add_preempt_count <-_raw_spin_lock_irq
> +kworker/-59      3d..2    1us : deactivate_task <-__schedule
> +kworker/-59      3d..2    1us : dequeue_task <-deactivate_task
> +kworker/-59      3d..2    2us : update_rq_clock <-dequeue_task
> +kworker/-59      3d..2    2us : dequeue_task_fair <-dequeue_task
> +kworker/-59      3d..2    2us : update_curr <-dequeue_task_fair
> +kworker/-59      3d..2    2us : update_min_vruntime <-update_curr
> +kworker/-59      3d..2    3us : cpuacct_charge <-update_curr
> +kworker/-59      3d..2    3us : __rcu_read_lock <-cpuacct_charge
> +kworker/-59      3d..2    3us : __rcu_read_unlock <-cpuacct_charge
> +kworker/-59      3d..2    3us : update_cfs_rq_blocked_load <-dequeue_task_fair
> +kworker/-59      3d..2    4us : clear_buddies <-dequeue_task_fair
> +kworker/-59      3d..2    4us : account_entity_dequeue <-dequeue_task_fair
> +kworker/-59      3d..2    4us : update_min_vruntime <-dequeue_task_fair
> +kworker/-59      3d..2    4us : update_cfs_shares <-dequeue_task_fair
> +kworker/-59      3d..2    5us : hrtick_update <-dequeue_task_fair
> +kworker/-59      3d..2    5us : wq_worker_sleeping <-__schedule
> +kworker/-59      3d..2    5us : kthread_data <-wq_worker_sleeping
> +kworker/-59      3d..2    5us : put_prev_task_fair <-__schedule
> +kworker/-59      3d..2    6us : pick_next_task_fair <-pick_next_task
> +kworker/-59      3d..2    6us : clear_buddies <-pick_next_task_fair
> +kworker/-59      3d..2    6us : set_next_entity <-pick_next_task_fair
> +kworker/-59      3d..2    6us : update_stats_wait_end <-set_next_entity
> +      ls-2269    3d..2    7us : finish_task_switch <-__schedule
> +      ls-2269    3d..2    7us : _raw_spin_unlock_irq <-finish_task_switch
> +      ls-2269    3d..2    8us : do_IRQ <-ret_from_intr
> +      ls-2269    3d..2    8us : irq_enter <-do_IRQ
> +      ls-2269    3d..2    8us : rcu_irq_enter <-irq_enter
> +      ls-2269    3d..2    9us : add_preempt_count <-irq_enter
> +      ls-2269    3d.h2    9us : exit_idle <-do_IRQ
>  [...]
> -    sshd-4261  0d.s3   43us : sub_preempt_count (local_bh_enable_ip)
> -    sshd-4261  0d.s4   44us : sub_preempt_count (local_bh_enable_ip)
> -    sshd-4261  0d.s3   44us : smp_apic_timer_interrupt (apic_timer_interrupt)
> -    sshd-4261  0d.s3   45us : irq_enter (smp_apic_timer_interrupt)
> -    sshd-4261  0d.s3   45us : idle_cpu (irq_enter)
> -    sshd-4261  0d.s3   46us : add_preempt_count (irq_enter)
> -    sshd-4261  0d.H3   46us : idle_cpu (irq_enter)
> -    sshd-4261  0d.H3   47us : hrtimer_interrupt (smp_apic_timer_interrupt)
> -    sshd-4261  0d.H3   47us : ktime_get (hrtimer_interrupt)
> +      ls-2269    3d.h3   20us : sub_preempt_count <-_raw_spin_unlock
> +      ls-2269    3d.h2   20us : irq_exit <-do_IRQ
> +      ls-2269    3d.h2   21us : sub_preempt_count <-irq_exit
> +      ls-2269    3d..3   21us : do_softirq <-irq_exit
> +      ls-2269    3d..3   21us : __do_softirq <-call_softirq
> +      ls-2269    3d..3   21us+: __local_bh_disable <-__do_softirq
> +      ls-2269    3d.s4   29us : sub_preempt_count <-_local_bh_enable_ip
> +      ls-2269    3d.s5   29us : sub_preempt_count <-_local_bh_enable_ip
> +      ls-2269    3d.s5   31us : do_IRQ <-ret_from_intr
> +      ls-2269    3d.s5   31us : irq_enter <-do_IRQ
> +      ls-2269    3d.s5   31us : rcu_irq_enter <-irq_enter
>  [...]
> -    sshd-4261  0d.H3   81us : tick_program_event (hrtimer_interrupt)
> -    sshd-4261  0d.H3   82us : ktime_get (tick_program_event)
> -    sshd-4261  0d.H3   82us : ktime_get_ts (ktime_get)
> -    sshd-4261  0d.H3   83us : getnstimeofday (ktime_get_ts)
> -    sshd-4261  0d.H3   83us : set_normalized_timespec (ktime_get_ts)
> -    sshd-4261  0d.H3   84us : clockevents_program_event (tick_program_event)
> -    sshd-4261  0d.H3   84us : lapic_next_event (clockevents_program_event)
> -    sshd-4261  0d.H3   85us : irq_exit (smp_apic_timer_interrupt)
> -    sshd-4261  0d.H3   85us : sub_preempt_count (irq_exit)
> -    sshd-4261  0d.s4   86us : sub_preempt_count (irq_exit)
> -    sshd-4261  0d.s3   86us : add_preempt_count (__local_bh_disable)
> +      ls-2269    3d.s5   31us : rcu_irq_enter <-irq_enter
> +      ls-2269    3d.s5   32us : add_preempt_count <-irq_enter
> +      ls-2269    3d.H5   32us : exit_idle <-do_IRQ
> +      ls-2269    3d.H5   32us : handle_irq <-do_IRQ
> +      ls-2269    3d.H5   32us : irq_to_desc <-handle_irq
> +      ls-2269    3d.H5   33us : handle_fasteoi_irq <-handle_irq
>  [...]
> -    sshd-4261  0d.s1   98us : sub_preempt_count (net_rx_action)
> -    sshd-4261  0d.s.   99us : add_preempt_count (_spin_lock_irq)
> -    sshd-4261  0d.s1   99us+: _spin_unlock_irq (run_timer_softirq)
> -    sshd-4261  0d.s.  104us : _local_bh_enable (__do_softirq)
> -    sshd-4261  0d.s.  104us : sub_preempt_count (_local_bh_enable)
> -    sshd-4261  0d.s.  105us : _local_bh_enable (__do_softirq)
> -    sshd-4261  0d.s1  105us : trace_preempt_on (__do_softirq)
> -
> -
> -This is a very interesting trace. It started with the preemption
> -of the ls task. We see that the task had the "need_resched" bit
> -set via the 'N' in the trace.  Interrupts were disabled before
> -the spin_lock at the beginning of the trace. We see that a
> -schedule took place to run sshd.  When the interrupts were
> -enabled, we took an interrupt. On return from the interrupt
> -handler, the softirq ran. We took another interrupt while
> -running the softirq as we see from the capital 'H'.
> +      ls-2269    3d.s5  158us : _raw_spin_unlock_irqrestore <-rtl8139_poll
> +      ls-2269    3d.s3  158us : net_rps_action_and_irq_enable.isra.65 <-net_rx_action
> +      ls-2269    3d.s3  159us : __local_bh_enable <-__do_softirq
> +      ls-2269    3d.s3  159us : sub_preempt_count <-__local_bh_enable
> +      ls-2269    3d..3  159us : idle_cpu <-irq_exit
> +      ls-2269    3d..3  159us : rcu_irq_exit <-irq_exit
> +      ls-2269    3d..3  160us : sub_preempt_count <-irq_exit
> +      ls-2269    3d...  161us : __mutex_unlock_slowpath <-mutex_unlock
> +      ls-2269    3d...  162us+: trace_hardirqs_on <-mutex_unlock
> +      ls-2269    3d...  186us : <stack trace>
> + => __mutex_unlock_slowpath
> + => mutex_unlock
> + => process_output
> + => n_tty_write
> + => tty_write
> + => vfs_write
> + => sys_write
> + => system_call_fastpath
> +
> +This is an interesting trace. It started with kworker running and
> +scheduling out and ls taking over. But as soon as ls released the
> +rq lock and enabled interrupts (but not preemption) an interrupt
> +triggered. When the interrupt finished, it started running softirqs.
> +But while the softirq was running, another interrupt triggered.
> +When an interrupt is running inside a softirq, the annotation is 'H'.
>  
> 
>  wakeup
>  ------
>  
> +One common case that people are interested in tracing is the
> +time it takes for a task that is woken to actually wake up.
> +Now for non Real-Time tasks, this can be arbitrary. But tracing
> +it none the less can be interesting. 
> +
> +Without function tracing:
> +
> + # echo 0 > options/function-trace
> + # echo wakeup > current_tracer
> + # echo 1 > tracing_on
> + # echo 0 > tracing_max_latency
> + # chrt -f 5 sleep 1
> + # echo 0 > tracing_on
> + # cat trace
> +# tracer: wakeup
> +#
> +# wakeup latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 15 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: kworker/3:1H-312 (uid:0 nice:-20 policy:0 rt_prio:0)
> +#    -----------------
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +  <idle>-0       3dNs7    0us :      0:120:R   + [003]   312:100:R kworker/3:1H
> +  <idle>-0       3dNs7    1us+: ttwu_do_activate.constprop.87 <-try_to_wake_up
> +  <idle>-0       3d..3   15us : __schedule <-schedule
> +  <idle>-0       3d..3   15us :      0:120:R ==> [003]   312:100:R kworker/3:1H
> +
> +The tracer only traces the highest priority task in the system
> +to avoid tracing the normal circumstances. Here we see that
> +the kworker with a nice priority of -20 (not very nice), took
> +just 15 microseconds from the time it woke up, to the time it
> +ran.
> +
> +Non Real-Time tasks are not that interesting. A more interesting
> +trace is to concentrate only on Real-Time tasks.
> +
> +wakeup_rt
> +---------
> +
>  In a Real-Time environment it is very important to know the
>  wakeup time it takes for the highest priority task that is woken
>  up to the time that it executes. This is also known as "schedule
> @@ -914,124 +1423,229 @@ Real-Time environments are interested in the worst case latency.
>  That is the longest latency it takes for something to happen,
>  and not the average. We can have a very fast scheduler that may
>  only have a large latency once in a while, but that would not
> -work well with Real-Time tasks.  The wakeup tracer was designed
> +work well with Real-Time tasks.  The wakeup_rt tracer was designed
>  to record the worst case wakeups of RT tasks. Non-RT tasks are
>  not recorded because the tracer only records one worst case and
>  tracing non-RT tasks that are unpredictable will overwrite the
> -worst case latency of RT tasks.
> +worst case latency of RT tasks (just run the normal wakeup
> +tracer for a while to see that effect).
>  
>  Since this tracer only deals with RT tasks, we will run this
>  slightly differently than we did with the previous tracers.
>  Instead of performing an 'ls', we will run 'sleep 1' under
>  'chrt' which changes the priority of the task.
>  
> - # echo wakeup > current_tracer
> - # echo latency-format > trace_options
> - # echo 0 > tracing_max_latency
> + # echo 0 > options/function-trace
> + # echo wakeup_rt > current_tracer
>   # echo 1 > tracing_on
> + # echo 0 > tracing_max_latency
>   # chrt -f 5 sleep 1
>   # echo 0 > tracing_on
>   # cat trace
>  # tracer: wakeup
>  #
> -wakeup latency trace v1.1.5 on 2.6.26-rc8
> ---------------------------------------------------------------------
> - latency: 4 us, #2/2, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: sleep-4901 (uid:0 nice:0 policy:1 rt_prio:5)
> -    -----------------
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -  <idle>-0     1d.h4    0us+: try_to_wake_up (wake_up_process)
> -  <idle>-0     1d..4    4us : schedule (cpu_idle)
> -
> -
> -Running this on an idle system, we see that it only took 4
> -microseconds to perform the task switch.  Note, since the trace
> -marker in the schedule is before the actual "switch", we stop
> -the tracing when the recorded task is about to schedule in. This
> -may change if we add a new marker at the end of the scheduler.
> -
> -Notice that the recorded task is 'sleep' with the PID of 4901
> +# tracer: wakeup_rt
> +#
> +# wakeup_rt latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 5 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: sleep-2389 (uid:0 nice:0 policy:1 rt_prio:5)
> +#    -----------------
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +  <idle>-0       3d.h4    0us :      0:120:R   + [003]  2389: 94:R sleep
> +  <idle>-0       3d.h4    1us+: ttwu_do_activate.constprop.87 <-try_to_wake_up
> +  <idle>-0       3d..3    5us : __schedule <-schedule
> +  <idle>-0       3d..3    5us :      0:120:R ==> [003]  2389: 94:R sleep
> +
> +
> +Running this on an idle system, we see that it only took 5 microseconds
> +to perform the task switch.  Note, since the trace point in the schedule
> +is before the actual "switch", we stop the tracing when the recorded task
> +is about to schedule in. This may change if we add a new marker at the
> +end of the scheduler.
> +
> +Notice that the recorded task is 'sleep' with the PID of 2389
>  and it has an rt_prio of 5. This priority is user-space priority
>  and not the internal kernel priority. The policy is 1 for
>  SCHED_FIFO and 2 for SCHED_RR.
>  
> -Doing the same with chrt -r 5 and ftrace_enabled set.
> +Note, that the trace data shows the internal priority (99 - rtprio).
>  
> -# tracer: wakeup
> +  <idle>-0       3d..3    5us :      0:120:R ==> [003]  2389: 94:R sleep
> +
> +The 0:120:R means idle was running with a nice priority of 0 (120 - 20)
> +and in the running state 'R'. The sleep task was scheduled in with
> +2389: 94:R. That is the priority is the kernel rtprio (99 - 5 = 94)
> +and it too is in the running state.
> +
> +Doing the same with chrt -r 5 and function-trace set.
> +
> +  echo 1 > options/function-trace
> +
> +# tracer: wakeup_rt
>  #
> -wakeup latency trace v1.1.5 on 2.6.26-rc8
> ---------------------------------------------------------------------
> - latency: 50 us, #60/60, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
> -    -----------------
> -    | task: sleep-4068 (uid:0 nice:0 policy:2 rt_prio:5)
> -    -----------------
> -
> -#                _------=> CPU#
> -#               / _-----=> irqs-off
> -#              | / _----=> need-resched
> -#              || / _---=> hardirq/softirq
> -#              ||| / _--=> preempt-depth
> -#              |||| /
> -#              |||||     delay
> -#  cmd     pid ||||| time  |   caller
> -#     \   /    |||||   \   |   /
> -ksoftirq-7     1d.H3    0us : try_to_wake_up (wake_up_process)
> -ksoftirq-7     1d.H4    1us : sub_preempt_count (marker_probe_cb)
> -ksoftirq-7     1d.H3    2us : check_preempt_wakeup (try_to_wake_up)
> -ksoftirq-7     1d.H3    3us : update_curr (check_preempt_wakeup)
> -ksoftirq-7     1d.H3    4us : calc_delta_mine (update_curr)
> -ksoftirq-7     1d.H3    5us : __resched_task (check_preempt_wakeup)
> -ksoftirq-7     1d.H3    6us : task_wake_up_rt (try_to_wake_up)
> -ksoftirq-7     1d.H3    7us : _spin_unlock_irqrestore (try_to_wake_up)
> -[...]
> -ksoftirq-7     1d.H2   17us : irq_exit (smp_apic_timer_interrupt)
> -ksoftirq-7     1d.H2   18us : sub_preempt_count (irq_exit)
> -ksoftirq-7     1d.s3   19us : sub_preempt_count (irq_exit)
> -ksoftirq-7     1..s2   20us : rcu_process_callbacks (__do_softirq)
> -[...]
> -ksoftirq-7     1..s2   26us : __rcu_process_callbacks (rcu_process_callbacks)
> -ksoftirq-7     1d.s2   27us : _local_bh_enable (__do_softirq)
> -ksoftirq-7     1d.s2   28us : sub_preempt_count (_local_bh_enable)
> -ksoftirq-7     1.N.3   29us : sub_preempt_count (ksoftirqd)
> -ksoftirq-7     1.N.2   30us : _cond_resched (ksoftirqd)
> -ksoftirq-7     1.N.2   31us : __cond_resched (_cond_resched)
> -ksoftirq-7     1.N.2   32us : add_preempt_count (__cond_resched)
> -ksoftirq-7     1.N.2   33us : schedule (__cond_resched)
> -ksoftirq-7     1.N.2   33us : add_preempt_count (schedule)
> -ksoftirq-7     1.N.3   34us : hrtick_clear (schedule)
> -ksoftirq-7     1dN.3   35us : _spin_lock (schedule)
> -ksoftirq-7     1dN.3   36us : add_preempt_count (_spin_lock)
> -ksoftirq-7     1d..4   37us : put_prev_task_fair (schedule)
> -ksoftirq-7     1d..4   38us : update_curr (put_prev_task_fair)
> -[...]
> -ksoftirq-7     1d..5   47us : _spin_trylock (tracing_record_cmdline)
> -ksoftirq-7     1d..5   48us : add_preempt_count (_spin_trylock)
> -ksoftirq-7     1d..6   49us : _spin_unlock (tracing_record_cmdline)
> -ksoftirq-7     1d..6   49us : sub_preempt_count (_spin_unlock)
> -ksoftirq-7     1d..4   50us : schedule (__cond_resched)
> -
> -The interrupt went off while running ksoftirqd. This task runs
> -at SCHED_OTHER. Why did not we see the 'N' set early? This may
> -be a harmless bug with x86_32 and 4K stacks. On x86_32 with 4K
> -stacks configured, the interrupt and softirq run with their own
> -stack. Some information is held on the top of the task's stack
> -(need_resched and preempt_count are both stored there). The
> -setting of the NEED_RESCHED bit is done directly to the task's
> -stack, but the reading of the NEED_RESCHED is done by looking at
> -the current stack, which in this case is the stack for the hard
> -interrupt. This hides the fact that NEED_RESCHED has been set.
> -We do not see the 'N' until we switch back to the task's
> -assigned stack.
> +# wakeup_rt latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 29 us, #85/85, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: sleep-2448 (uid:0 nice:0 policy:1 rt_prio:5)
> +#    -----------------
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +  <idle>-0       3d.h4    1us+:      0:120:R   + [003]  2448: 94:R sleep
> +  <idle>-0       3d.h4    2us : ttwu_do_activate.constprop.87 <-try_to_wake_up
> +  <idle>-0       3d.h3    3us : check_preempt_curr <-ttwu_do_wakeup
> +  <idle>-0       3d.h3    3us : resched_task <-check_preempt_curr
> +  <idle>-0       3dNh3    4us : task_woken_rt <-ttwu_do_wakeup
> +  <idle>-0       3dNh3    4us : _raw_spin_unlock <-try_to_wake_up
> +  <idle>-0       3dNh3    4us : sub_preempt_count <-_raw_spin_unlock
> +  <idle>-0       3dNh2    5us : ttwu_stat <-try_to_wake_up
> +  <idle>-0       3dNh2    5us : _raw_spin_unlock_irqrestore <-try_to_wake_up
> +  <idle>-0       3dNh2    6us : sub_preempt_count <-_raw_spin_unlock_irqrestore
> +  <idle>-0       3dNh1    6us : _raw_spin_lock <-__run_hrtimer
> +  <idle>-0       3dNh1    6us : add_preempt_count <-_raw_spin_lock
> +  <idle>-0       3dNh2    7us : _raw_spin_unlock <-hrtimer_interrupt
> +  <idle>-0       3dNh2    7us : sub_preempt_count <-_raw_spin_unlock
> +  <idle>-0       3dNh1    7us : tick_program_event <-hrtimer_interrupt
> +  <idle>-0       3dNh1    7us : clockevents_program_event <-tick_program_event
> +  <idle>-0       3dNh1    8us : ktime_get <-clockevents_program_event
> +  <idle>-0       3dNh1    8us : lapic_next_event <-clockevents_program_event
> +  <idle>-0       3dNh1    8us : irq_exit <-smp_apic_timer_interrupt
> +  <idle>-0       3dNh1    9us : sub_preempt_count <-irq_exit
> +  <idle>-0       3dN.2    9us : idle_cpu <-irq_exit
> +  <idle>-0       3dN.2    9us : rcu_irq_exit <-irq_exit
> +  <idle>-0       3dN.2   10us : rcu_eqs_enter_common.isra.45 <-rcu_irq_exit
> +  <idle>-0       3dN.2   10us : sub_preempt_count <-irq_exit
> +  <idle>-0       3.N.1   11us : rcu_idle_exit <-cpu_idle
> +  <idle>-0       3dN.1   11us : rcu_eqs_exit_common.isra.43 <-rcu_idle_exit
> +  <idle>-0       3.N.1   11us : tick_nohz_idle_exit <-cpu_idle
> +  <idle>-0       3dN.1   12us : menu_hrtimer_cancel <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   12us : ktime_get <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   12us : tick_do_update_jiffies64 <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   13us : update_cpu_load_nohz <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   13us : _raw_spin_lock <-update_cpu_load_nohz
> +  <idle>-0       3dN.1   13us : add_preempt_count <-_raw_spin_lock
> +  <idle>-0       3dN.2   13us : __update_cpu_load <-update_cpu_load_nohz
> +  <idle>-0       3dN.2   14us : sched_avg_update <-__update_cpu_load
> +  <idle>-0       3dN.2   14us : _raw_spin_unlock <-update_cpu_load_nohz
> +  <idle>-0       3dN.2   14us : sub_preempt_count <-_raw_spin_unlock
> +  <idle>-0       3dN.1   15us : calc_load_exit_idle <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   15us : touch_softlockup_watchdog <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   15us : hrtimer_cancel <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   15us : hrtimer_try_to_cancel <-hrtimer_cancel
> +  <idle>-0       3dN.1   16us : lock_hrtimer_base.isra.18 <-hrtimer_try_to_cancel
> +  <idle>-0       3dN.1   16us : _raw_spin_lock_irqsave <-lock_hrtimer_base.isra.18
> +  <idle>-0       3dN.1   16us : add_preempt_count <-_raw_spin_lock_irqsave
> +  <idle>-0       3dN.2   17us : __remove_hrtimer <-remove_hrtimer.part.16
> +  <idle>-0       3dN.2   17us : hrtimer_force_reprogram <-__remove_hrtimer
> +  <idle>-0       3dN.2   17us : tick_program_event <-hrtimer_force_reprogram
> +  <idle>-0       3dN.2   18us : clockevents_program_event <-tick_program_event
> +  <idle>-0       3dN.2   18us : ktime_get <-clockevents_program_event
> +  <idle>-0       3dN.2   18us : lapic_next_event <-clockevents_program_event
> +  <idle>-0       3dN.2   19us : _raw_spin_unlock_irqrestore <-hrtimer_try_to_cancel
> +  <idle>-0       3dN.2   19us : sub_preempt_count <-_raw_spin_unlock_irqrestore
> +  <idle>-0       3dN.1   19us : hrtimer_forward <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   20us : ktime_add_safe <-hrtimer_forward
> +  <idle>-0       3dN.1   20us : ktime_add_safe <-hrtimer_forward
> +  <idle>-0       3dN.1   20us : hrtimer_start_range_ns <-hrtimer_start_expires.constprop.11
> +  <idle>-0       3dN.1   20us : __hrtimer_start_range_ns <-hrtimer_start_range_ns
> +  <idle>-0       3dN.1   21us : lock_hrtimer_base.isra.18 <-__hrtimer_start_range_ns
> +  <idle>-0       3dN.1   21us : _raw_spin_lock_irqsave <-lock_hrtimer_base.isra.18
> +  <idle>-0       3dN.1   21us : add_preempt_count <-_raw_spin_lock_irqsave
> +  <idle>-0       3dN.2   22us : ktime_add_safe <-__hrtimer_start_range_ns
> +  <idle>-0       3dN.2   22us : enqueue_hrtimer <-__hrtimer_start_range_ns
> +  <idle>-0       3dN.2   22us : tick_program_event <-__hrtimer_start_range_ns
> +  <idle>-0       3dN.2   23us : clockevents_program_event <-tick_program_event
> +  <idle>-0       3dN.2   23us : ktime_get <-clockevents_program_event
> +  <idle>-0       3dN.2   23us : lapic_next_event <-clockevents_program_event
> +  <idle>-0       3dN.2   24us : _raw_spin_unlock_irqrestore <-__hrtimer_start_range_ns
> +  <idle>-0       3dN.2   24us : sub_preempt_count <-_raw_spin_unlock_irqrestore
> +  <idle>-0       3dN.1   24us : account_idle_ticks <-tick_nohz_idle_exit
> +  <idle>-0       3dN.1   24us : account_idle_time <-account_idle_ticks
> +  <idle>-0       3.N.1   25us : sub_preempt_count <-cpu_idle
> +  <idle>-0       3.N..   25us : schedule <-cpu_idle
> +  <idle>-0       3.N..   25us : __schedule <-preempt_schedule
> +  <idle>-0       3.N..   26us : add_preempt_count <-__schedule
> +  <idle>-0       3.N.1   26us : rcu_note_context_switch <-__schedule
> +  <idle>-0       3.N.1   26us : rcu_sched_qs <-rcu_note_context_switch
> +  <idle>-0       3dN.1   27us : rcu_preempt_qs <-rcu_note_context_switch
> +  <idle>-0       3.N.1   27us : _raw_spin_lock_irq <-__schedule
> +  <idle>-0       3dN.1   27us : add_preempt_count <-_raw_spin_lock_irq
> +  <idle>-0       3dN.2   28us : put_prev_task_idle <-__schedule
> +  <idle>-0       3dN.2   28us : pick_next_task_stop <-pick_next_task
> +  <idle>-0       3dN.2   28us : pick_next_task_rt <-pick_next_task
> +  <idle>-0       3dN.2   29us : dequeue_pushable_task <-pick_next_task_rt
> +  <idle>-0       3d..3   29us : __schedule <-preempt_schedule
> +  <idle>-0       3d..3   30us :      0:120:R ==> [003]  2448: 94:R sleep
> +
> +This isn't that big of a trace, even with function tracing enabled,
> +so I included the entire trace.
> +
> +The interrupt went off while when the system was idle. Somewhere
> +before task_woken_rt() was called, the NEED_RESCHED flag was set,
> +this is indicated by the first occurrence of the 'N' flag.
> +
> +Latency tracing and events
> +--------------------------
> +As function tracing can induce a much larger latency, but without
> +seeing what happens within the latency it is hard to know what
> +caused it. There is a middle ground, and that is with enabling
> +events.
> +
> + # echo 0 > options/function-trace
> + # echo wakeup_rt > current_tracer
> + # echo 1 > events/enable
> + # echo 1 > tracing_on
> + # echo 0 > tracing_max_latency
> + # chrt -f 5 sleep 1
> + # echo 0 > tracing_on
> + # cat trace
> +# tracer: wakeup_rt
> +#
> +# wakeup_rt latency trace v1.1.5 on 3.8.0-test+
> +# --------------------------------------------------------------------
> +# latency: 6 us, #12/12, CPU#2 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
> +#    -----------------
> +#    | task: sleep-5882 (uid:0 nice:0 policy:1 rt_prio:5)
> +#    -----------------
> +#
> +#                  _------=> CPU#            
> +#                 / _-----=> irqs-off        
> +#                | / _----=> need-resched    
> +#                || / _---=> hardirq/softirq 
> +#                ||| / _--=> preempt-depth   
> +#                |||| /     delay             
> +#  cmd     pid   ||||| time  |   caller      
> +#     \   /      |||||  \    |   /           
> +  <idle>-0       2d.h4    0us :      0:120:R   + [002]  5882: 94:R sleep
> +  <idle>-0       2d.h4    0us : ttwu_do_activate.constprop.87 <-try_to_wake_up
> +  <idle>-0       2d.h4    1us : sched_wakeup: comm=sleep pid=5882 prio=94 success=1 target_cpu=002
> +  <idle>-0       2dNh2    1us : hrtimer_expire_exit: hrtimer=ffff88007796feb8
> +  <idle>-0       2.N.2    2us : power_end: cpu_id=2
> +  <idle>-0       2.N.2    3us : cpu_idle: state=4294967295 cpu_id=2
> +  <idle>-0       2dN.3    4us : hrtimer_cancel: hrtimer=ffff88007d50d5e0
> +  <idle>-0       2dN.3    4us : hrtimer_start: hrtimer=ffff88007d50d5e0 function=tick_sched_timer expires=34311211000000 softexpires=34311211000000
> +  <idle>-0       2.N.2    5us : rcu_utilization: Start context switch
> +  <idle>-0       2.N.2    5us : rcu_utilization: End context switch
> +  <idle>-0       2d..3    6us : __schedule <-schedule
> +  <idle>-0       2d..3    6us :      0:120:R ==> [002]  5882: 94:R sleep
> +
>  
>  function
>  --------
> @@ -1039,6 +1653,7 @@ function
>  This tracer is the function tracer. Enabling the function tracer
>  can be done from the debug file system. Make sure the
>  ftrace_enabled is set; otherwise this tracer is a nop.
> +See the "ftrace_enabled" section below.
>  
>   # sysctl kernel.ftrace_enabled=1
>   # echo function > current_tracer
> @@ -1048,23 +1663,23 @@ ftrace_enabled is set; otherwise this tracer is a nop.
>   # cat trace
>  # tracer: function
>  #
> -#           TASK-PID   CPU#    TIMESTAMP  FUNCTION
> -#              | |      |          |         |
> -            bash-4003  [00]   123.638713: finish_task_switch <-schedule
> -            bash-4003  [00]   123.638714: _spin_unlock_irq <-finish_task_switch
> -            bash-4003  [00]   123.638714: sub_preempt_count <-_spin_unlock_irq
> -            bash-4003  [00]   123.638715: hrtick_set <-schedule
> -            bash-4003  [00]   123.638715: _spin_lock_irqsave <-hrtick_set
> -            bash-4003  [00]   123.638716: add_preempt_count <-_spin_lock_irqsave
> -            bash-4003  [00]   123.638716: _spin_unlock_irqrestore <-hrtick_set
> -            bash-4003  [00]   123.638717: sub_preempt_count <-_spin_unlock_irqrestore
> -            bash-4003  [00]   123.638717: hrtick_clear <-hrtick_set
> -            bash-4003  [00]   123.638718: sub_preempt_count <-schedule
> -            bash-4003  [00]   123.638718: sub_preempt_count <-preempt_schedule
> -            bash-4003  [00]   123.638719: wait_for_completion <-__stop_machine_run
> -            bash-4003  [00]   123.638719: wait_for_common <-wait_for_completion
> -            bash-4003  [00]   123.638720: _spin_lock_irq <-wait_for_common
> -            bash-4003  [00]   123.638720: add_preempt_count <-_spin_lock_irq
> +# entries-in-buffer/entries-written: 24799/24799   #P:4
> +#
> +#                              _-----=> irqs-off
> +#                             / _----=> need-resched
> +#                            | / _---=> hardirq/softirq
> +#                            || / _--=> preempt-depth
> +#                            ||| /     delay
> +#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> +#              | |       |   ||||       |         |
> +            bash-1994  [002] ....  3082.063030: mutex_unlock <-rb_simple_write
> +            bash-1994  [002] ....  3082.063031: __mutex_unlock_slowpath <-mutex_unlock
> +            bash-1994  [002] ....  3082.063031: __fsnotify_parent <-fsnotify_modify
> +            bash-1994  [002] ....  3082.063032: fsnotify <-fsnotify_modify
> +            bash-1994  [002] ....  3082.063032: __srcu_read_lock <-fsnotify
> +            bash-1994  [002] ....  3082.063032: add_preempt_count <-__srcu_read_lock
> +            bash-1994  [002] ...1  3082.063032: sub_preempt_count <-__srcu_read_lock
> +            bash-1994  [002] ....  3082.063033: __srcu_read_unlock <-fsnotify
>  [...]
>  
> 
> @@ -1214,79 +1829,19 @@ int main (int argc, char **argv)
>          return 0;
>  }
>  
> +Or this simple script!
>  
> -hw-branch-tracer (x86 only)
> ----------------------------
> -
> -This tracer uses the x86 last branch tracing hardware feature to
> -collect a branch trace on all cpus with relatively low overhead.
> -
> -The tracer uses a fixed-size circular buffer per cpu and only
> -traces ring 0 branches. The trace file dumps that buffer in the
> -following format:
> -
> -# tracer: hw-branch-tracer
> -#
> -# CPU#        TO  <-  FROM
> -   0  scheduler_tick+0xb5/0x1bf	  <-  task_tick_idle+0x5/0x6
> -   2  run_posix_cpu_timers+0x2b/0x72a	  <-  run_posix_cpu_timers+0x25/0x72a
> -   0  scheduler_tick+0x139/0x1bf	  <-  scheduler_tick+0xed/0x1bf
> -   0  scheduler_tick+0x17c/0x1bf	  <-  scheduler_tick+0x148/0x1bf
> -   2  run_posix_cpu_timers+0x9e/0x72a	  <-  run_posix_cpu_timers+0x5e/0x72a
> -   0  scheduler_tick+0x1b6/0x1bf	  <-  scheduler_tick+0x1aa/0x1bf
> -
> -
> -The tracer may be used to dump the trace for the oops'ing cpu on
> -a kernel oops into the system log. To enable this,
> -ftrace_dump_on_oops must be set. To set ftrace_dump_on_oops, one
> -can either use the sysctl function or set it via the proc system
> -interface.
> -
> -  sysctl kernel.ftrace_dump_on_oops=n
> -
> -or
> -
> -  echo n > /proc/sys/kernel/ftrace_dump_on_oops
> -
> -If n = 1, ftrace will dump buffers of all CPUs, if n = 2 ftrace will
> -only dump the buffer of the CPU that triggered the oops.
> -
> -Here's an example of such a dump after a null pointer
> -dereference in a kernel module:
> -
> -[57848.105921] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
> -[57848.106019] IP: [<ffffffffa0000006>] open+0x6/0x14 [oops]
> -[57848.106019] PGD 2354e9067 PUD 2375e7067 PMD 0
> -[57848.106019] Oops: 0002 [#1] SMP
> -[57848.106019] last sysfs file: /sys/devices/pci0000:00/0000:00:1e.0/0000:20:05.0/local_cpus
> -[57848.106019] Dumping ftrace buffer:
> -[57848.106019] ---------------------------------
> -[...]
> -[57848.106019]    0  chrdev_open+0xe6/0x165	  <-  cdev_put+0x23/0x24
> -[57848.106019]    0  chrdev_open+0x117/0x165	  <-  chrdev_open+0xfa/0x165
> -[57848.106019]    0  chrdev_open+0x120/0x165	  <-  chrdev_open+0x11c/0x165
> -[57848.106019]    0  chrdev_open+0x134/0x165	  <-  chrdev_open+0x12b/0x165
> -[57848.106019]    0  open+0x0/0x14 [oops]	  <-  chrdev_open+0x144/0x165
> -[57848.106019]    0  page_fault+0x0/0x30	  <-  open+0x6/0x14 [oops]
> -[57848.106019]    0  error_entry+0x0/0x5b	  <-  page_fault+0x4/0x30
> -[57848.106019]    0  error_kernelspace+0x0/0x31	  <-  error_entry+0x59/0x5b
> -[57848.106019]    0  error_sti+0x0/0x1	  <-  error_kernelspace+0x2d/0x31
> -[57848.106019]    0  page_fault+0x9/0x30	  <-  error_sti+0x0/0x1
> -[57848.106019]    0  do_page_fault+0x0/0x881	  <-  page_fault+0x1a/0x30
> -[...]
> -[57848.106019]    0  do_page_fault+0x66b/0x881	  <-  is_prefetch+0x1ee/0x1f2
> -[57848.106019]    0  do_page_fault+0x6e0/0x881	  <-  do_page_fault+0x67a/0x881
> -[57848.106019]    0  oops_begin+0x0/0x96	  <-  do_page_fault+0x6e0/0x881
> -[57848.106019]    0  trace_hw_branch_oops+0x0/0x2d	  <-  oops_begin+0x9/0x96
> -[...]
> -[57848.106019]    0  ds_suspend_bts+0x2a/0xe3	  <-  ds_suspend_bts+0x1a/0xe3
> -[57848.106019] ---------------------------------
> -[57848.106019] CPU 0
> -[57848.106019] Modules linked in: oops
> -[57848.106019] Pid: 5542, comm: cat Tainted: G        W  2.6.28 #23
> -[57848.106019] RIP: 0010:[<ffffffffa0000006>]  [<ffffffffa0000006>] open+0x6/0x14 [oops]
> -[57848.106019] RSP: 0018:ffff880235457d48  EFLAGS: 00010246
> -[...]
> +------
> +#!/bin/bash
> +
> +debugfs=`sed -ne 's/^debugfs \(.*\) debugfs.*/\1/p' /proc/mounts`
> +echo nop > $debugfs/tracing/current_tracer
> +echo 0 > $debugfs/tracing/tracing_on
> +echo $$ > $debugfs/tracing/set_ftrace_pid
> +echo function > $debugfs/tracing/current_tracer
> +echo 1 > $debugfs/tracing/tracing_on
> +exec "$@"
> +------
>  
> 
>  function graph tracer
> @@ -1473,16 +2028,18 @@ starts of pointing to a simple return. (Enabling FTRACE will
>  include the -pg switch in the compiling of the kernel.)
>  
>  At compile time every C file object is run through the
> -recordmcount.pl script (located in the scripts directory). This
> -script will process the C object using objdump to find all the
> -locations in the .text section that call mcount. (Note, only the
> -.text section is processed, since processing other sections like
> -.init.text may cause races due to those sections being freed).
> +recordmcount program (located in the scripts directory). This
> +program will parse the ELF headers in the C object to find all
> +the locations in the .text section that call mcount. (Note, only
> +white listed .text sections are processed, since processing other
> +sections like .init.text may cause races due to those sections
> +being freed unexpectedly).
>  
>  A new section called "__mcount_loc" is created that holds
>  references to all the mcount call sites in the .text section.
> -This section is compiled back into the original object. The
> -final linker will add all these references into a single table.
> +The recordmcount program re-links this section back into the
> +original object. The final linking stage of the kernel will add all these
> +references into a single table.
>  
>  On boot up, before SMP is initialized, the dynamic ftrace code
>  scans this table and updates all the locations into nops. It
> @@ -1493,13 +2050,25 @@ unloaded, it also removes its functions from the ftrace function
>  list. This is automatic in the module unload code, and the
>  module author does not need to worry about it.
>  
> -When tracing is enabled, kstop_machine is called to prevent
> -races with the CPUS executing code being modified (which can
> -cause the CPU to do undesirable things), and the nops are
> +When tracing is enabled, the process of modifying the function
> +tracepoints is dependent on architecture. The old method is to use
> +kstop_machine to prevent races with the CPUs executing code being
> +modified (which can cause the CPU to do undesirable things, especially
> +if the modified code crosses cache (or page) boundaries), and the nops are
>  patched back to calls. But this time, they do not call mcount
>  (which is just a function stub). They now call into the ftrace
>  infrastructure.
>  
> +The new method of modifying the function tracepoints is to place
> +a breakpoint at the location to be modified, sync all CPUs, modify
> +the rest of the instruction not covered by the breakpoint. Sync
> +all CPUs again, and then remove the breakpoint with the finished
> +version to the ftrace call site.
> +
> +Some archs do not even need to monkey around with the synchronization,
> +and can just slap the new code on top of the old without any
> +problems with other CPUs executing it at the same time.
> +
>  One special side-effect to the recording of the functions being
>  traced is that we can now selectively choose which functions we
>  wish to trace and which ones we want the mcount calls to remain
> @@ -1530,20 +2099,28 @@ mutex_lock
>  
>  If I am only interested in sys_nanosleep and hrtimer_interrupt:
>  
> - # echo sys_nanosleep hrtimer_interrupt \
> -		> set_ftrace_filter
> + # echo sys_nanosleep hrtimer_interrupt > set_ftrace_filter
>   # echo function > current_tracer
>   # echo 1 > tracing_on
>   # usleep 1
>   # echo 0 > tracing_on
>   # cat trace
> -# tracer: ftrace
> +# tracer: function
> +#
> +# entries-in-buffer/entries-written: 5/5   #P:4
>  #
> -#           TASK-PID   CPU#    TIMESTAMP  FUNCTION
> -#              | |      |          |         |
> -          usleep-4134  [00]  1317.070017: hrtimer_interrupt <-smp_apic_timer_interrupt
> -          usleep-4134  [00]  1317.070111: sys_nanosleep <-syscall_call
> -          <idle>-0     [00]  1317.070115: hrtimer_interrupt <-smp_apic_timer_interrupt
> +#                              _-----=> irqs-off
> +#                             / _----=> need-resched
> +#                            | / _---=> hardirq/softirq
> +#                            || / _--=> preempt-depth
> +#                            ||| /     delay
> +#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> +#              | |       |   ||||       |         |
> +          usleep-2665  [001] ....  4186.475355: sys_nanosleep <-system_call_fastpath
> +          <idle>-0     [001] d.h1  4186.475409: hrtimer_interrupt <-smp_apic_timer_interrupt
> +          usleep-2665  [001] d.h1  4186.475426: hrtimer_interrupt <-smp_apic_timer_interrupt
> +          <idle>-0     [003] d.h1  4186.475426: hrtimer_interrupt <-smp_apic_timer_interrupt
> +          <idle>-0     [002] d.h1  4186.475427: hrtimer_interrupt <-smp_apic_timer_interrupt
>  
>  To see which functions are being traced, you can cat the file:
>  
> @@ -1571,20 +2148,25 @@ Note: It is better to use quotes to enclose the wild cards,
>  
>  Produces:
>  
> -# tracer: ftrace
> +# tracer: function
>  #
> -#           TASK-PID   CPU#    TIMESTAMP  FUNCTION
> -#              | |      |          |         |
> -            bash-4003  [00]  1480.611794: hrtimer_init <-copy_process
> -            bash-4003  [00]  1480.611941: hrtimer_start <-hrtick_set
> -            bash-4003  [00]  1480.611956: hrtimer_cancel <-hrtick_clear
> -            bash-4003  [00]  1480.611956: hrtimer_try_to_cancel <-hrtimer_cancel
> -          <idle>-0     [00]  1480.612019: hrtimer_get_next_event <-get_next_timer_interrupt
> -          <idle>-0     [00]  1480.612025: hrtimer_get_next_event <-get_next_timer_interrupt
> -          <idle>-0     [00]  1480.612032: hrtimer_get_next_event <-get_next_timer_interrupt
> -          <idle>-0     [00]  1480.612037: hrtimer_get_next_event <-get_next_timer_interrupt
> -          <idle>-0     [00]  1480.612382: hrtimer_get_next_event <-get_next_timer_interrupt
> -
> +# entries-in-buffer/entries-written: 897/897   #P:4
> +#
> +#                              _-----=> irqs-off
> +#                             / _----=> need-resched
> +#                            | / _---=> hardirq/softirq
> +#                            || / _--=> preempt-depth
> +#                            ||| /     delay
> +#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> +#              | |       |   ||||       |         |
> +          <idle>-0     [003] dN.1  4228.547803: hrtimer_cancel <-tick_nohz_idle_exit
> +          <idle>-0     [003] dN.1  4228.547804: hrtimer_try_to_cancel <-hrtimer_cancel
> +          <idle>-0     [003] dN.2  4228.547805: hrtimer_force_reprogram <-__remove_hrtimer
> +          <idle>-0     [003] dN.1  4228.547805: hrtimer_forward <-tick_nohz_idle_exit
> +          <idle>-0     [003] dN.1  4228.547805: hrtimer_start_range_ns <-hrtimer_start_expires.constprop.11
> +          <idle>-0     [003] d..1  4228.547858: hrtimer_get_next_event <-get_next_timer_interrupt
> +          <idle>-0     [003] d..1  4228.547859: hrtimer_start <-__tick_nohz_idle_enter
> +          <idle>-0     [003] d..2  4228.547860: hrtimer_force_reprogram <-__rem
>  
>  Notice that we lost the sys_nanosleep.
>  
> @@ -1651,19 +2233,29 @@ traced.
>  
>  Produces:
>  
> -# tracer: ftrace
> +# tracer: function
> +#
> +# entries-in-buffer/entries-written: 39608/39608   #P:4
>  #
> -#           TASK-PID   CPU#    TIMESTAMP  FUNCTION
> -#              | |      |          |         |
> -            bash-4043  [01]   115.281644: finish_task_switch <-schedule
> -            bash-4043  [01]   115.281645: hrtick_set <-schedule
> -            bash-4043  [01]   115.281645: hrtick_clear <-hrtick_set
> -            bash-4043  [01]   115.281646: wait_for_completion <-__stop_machine_run
> -            bash-4043  [01]   115.281647: wait_for_common <-wait_for_completion
> -            bash-4043  [01]   115.281647: kthread_stop <-stop_machine_run
> -            bash-4043  [01]   115.281648: init_waitqueue_head <-kthread_stop
> -            bash-4043  [01]   115.281648: wake_up_process <-kthread_stop
> -            bash-4043  [01]   115.281649: try_to_wake_up <-wake_up_process
> +#                              _-----=> irqs-off
> +#                             / _----=> need-resched
> +#                            | / _---=> hardirq/softirq
> +#                            || / _--=> preempt-depth
> +#                            ||| /     delay
> +#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> +#              | |       |   ||||       |         |
> +            bash-1994  [000] ....  4342.324896: file_ra_state_init <-do_dentry_open
> +            bash-1994  [000] ....  4342.324897: open_check_o_direct <-do_last
> +            bash-1994  [000] ....  4342.324897: ima_file_check <-do_last
> +            bash-1994  [000] ....  4342.324898: process_measurement <-ima_file_check
> +            bash-1994  [000] ....  4342.324898: ima_get_action <-process_measurement
> +            bash-1994  [000] ....  4342.324898: ima_match_policy <-ima_get_action
> +            bash-1994  [000] ....  4342.324899: do_truncate <-do_last
> +            bash-1994  [000] ....  4342.324899: should_remove_suid <-do_truncate
> +            bash-1994  [000] ....  4342.324899: notify_change <-do_truncate
> +            bash-1994  [000] ....  4342.324900: current_fs_time <-notify_change
> +            bash-1994  [000] ....  4342.324900: current_kernel_time <-current_fs_time
> +            bash-1994  [000] ....  4342.324900: timespec_trunc <-current_fs_time
>  
>  We can see that there's no more lock or preempt tracing.
>  
> @@ -1729,6 +2321,28 @@ this special filter via:
>   echo > set_graph_function
>  
> 
> +ftrace_enabled
> +--------------
> +
> +Note, the proc sysctl ftrace_enable is a big on/off switch for the
> +function tracer. By default it is enabled (when function tracing is
> +enabled in the kernel). If it is disabled, all function tracing is
> +disabled. This includes not only the function tracers for ftrace, but
> +also for any other uses (perf, kprobes, stack tracing, profiling, etc).
> +
> +Please disable this with care.
> +
> +This can be disable (and enabled) with:
> +
> +  sysctl kernel.ftrace_enabled=0
> +  sysctl kernel.ftrace_enabled=1
> +
> + or
> +
> +  echo 0 > /proc/sys/kernel/ftrace_enabled
> +  echo 1 > /proc/sys/kernel/ftrace_enabled
> +
> +
>  Filter commands
>  ---------------
>  
> @@ -1763,12 +2377,58 @@ The following commands are supported:
>  
>     echo '__schedule_bug:traceoff:5' > set_ftrace_filter
>  
> +  To always disable tracing when __schedule_bug is hit:
> +
> +   echo '__schedule_bug:traceoff' > set_ftrace_filter
> +
>    These commands are cumulative whether or not they are appended
>    to set_ftrace_filter. To remove a command, prepend it by '!'
>    and drop the parameter:
>  
> +   echo '!__schedule_bug:traceoff:0' > set_ftrace_filter
> +
> +    The above removes the traceoff command for __schedule_bug
> +    that have a counter. To remove commands without counters:
> +
>     echo '!__schedule_bug:traceoff' > set_ftrace_filter
>  
> +- snapshot
> +  Will cause a snapshot to be triggered when the function is hit.
> +
> +   echo 'native_flush_tlb_others:snapshot' > set_ftrace_filter
> +
> +  To only snapshot once:
> +
> +   echo 'native_flush_tlb_others:snapshot:1' > set_ftrace_filter
> +
> +  To remove the above commands:
> +
> +   echo '!native_flush_tlb_others:snapshot' > set_ftrace_filter
> +   echo '!native_flush_tlb_others:snapshot:0' > set_ftrace_filter
> +
> +- enable_event/disable_event
> +  These commands can enable or disable a trace event. Note, because
> +  function tracing callbacks are very sensitive, when these commands
> +  are registered, the trace point is activated, but disabled in
> +  a "soft" mode. That is, the tracepoint will be called, but
> +  just will not be traced. The event tracepoint stays in this mode
> +  as long as there's a command that triggers it.
> +
> +   echo 'try_to_wake_up:enable_event:sched:sched_switch:2' > \
> +   	 set_ftrace_filter
> +
> +  The format is:
> +
> +    <function>:enable_event:<system>:<event>[:count]
> +    <function>:disable_event:<system>:<event>[:count]
> +
> +  To remove the events commands:
> +
> +
> +   echo '!try_to_wake_up:enable_event:sched:sched_switch:0' > \
> +   	 set_ftrace_filter
> +   echo '!schedule:disable_event:sched:sched_switch' > \
> +   	 set_ftrace_filter
>  
>  trace_pipe
>  ----------
> @@ -1787,28 +2447,31 @@ different. The trace is live.
>   # cat trace
>  # tracer: function
>  #
> -#           TASK-PID   CPU#    TIMESTAMP  FUNCTION
> -#              | |      |          |         |
> +# entries-in-buffer/entries-written: 0/0   #P:4
> +#
> +#                              _-----=> irqs-off
> +#                             / _----=> need-resched
> +#                            | / _---=> hardirq/softirq
> +#                            || / _--=> preempt-depth
> +#                            ||| /     delay
> +#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> +#              | |       |   ||||       |         |
>  
>   #
>   # cat /tmp/trace.out
> -            bash-4043  [00] 41.267106: finish_task_switch <-schedule
> -            bash-4043  [00] 41.267106: hrtick_set <-schedule
> -            bash-4043  [00] 41.267107: hrtick_clear <-hrtick_set
> -            bash-4043  [00] 41.267108: wait_for_completion <-__stop_machine_run
> -            bash-4043  [00] 41.267108: wait_for_common <-wait_for_completion
> -            bash-4043  [00] 41.267109: kthread_stop <-stop_machine_run
> -            bash-4043  [00] 41.267109: init_waitqueue_head <-kthread_stop
> -            bash-4043  [00] 41.267110: wake_up_process <-kthread_stop
> -            bash-4043  [00] 41.267110: try_to_wake_up <-wake_up_process
> -            bash-4043  [00] 41.267111: select_task_rq_rt <-try_to_wake_up
> +            bash-1994  [000] ....  5281.568961: mutex_unlock <-rb_simple_write
> +            bash-1994  [000] ....  5281.568963: __mutex_unlock_slowpath <-mutex_unlock
> +            bash-1994  [000] ....  5281.568963: __fsnotify_parent <-fsnotify_modify
> +            bash-1994  [000] ....  5281.568964: fsnotify <-fsnotify_modify
> +            bash-1994  [000] ....  5281.568964: __srcu_read_lock <-fsnotify
> +            bash-1994  [000] ....  5281.568964: add_preempt_count <-__srcu_read_lock
> +            bash-1994  [000] ...1  5281.568965: sub_preempt_count <-__srcu_read_lock
> +            bash-1994  [000] ....  5281.568965: __srcu_read_unlock <-fsnotify
> +            bash-1994  [000] ....  5281.568967: sys_dup2 <-system_call_fastpath
>  
> 
>  Note, reading the trace_pipe file will block until more input is
> -added. By changing the tracer, trace_pipe will issue an EOF. We
> -needed to set the function tracer _before_ we "cat" the
> -trace_pipe file.
> -
> +added.
>  
>  trace entries
>  -------------
> @@ -1817,31 +2480,50 @@ Having too much or not enough data can be troublesome in
>  diagnosing an issue in the kernel. The file buffer_size_kb is
>  used to modify the size of the internal trace buffers. The
>  number listed is the number of entries that can be recorded per
> -CPU. To know the full size, multiply the number of possible CPUS
> +CPU. To know the full size, multiply the number of possible CPUs
>  with the number of entries.
>  
>   # cat buffer_size_kb
>  1408 (units kilobytes)
>  
> -Note, to modify this, you must have tracing completely disabled.
> -To do that, echo "nop" into the current_tracer. If the
> -current_tracer is not set to "nop", an EINVAL error will be
> -returned.
> +Or simply read buffer_total_size_kb
> +
> + # cat buffer_total_size_kb 
> +5632
> +
> +To modify the buffer, simple echo in a number (in 1024 byte segments).
>  
> - # echo nop > current_tracer
>   # echo 10000 > buffer_size_kb
>   # cat buffer_size_kb
>  10000 (units kilobytes)
>  
> -The number of pages which will be allocated is limited to a
> -percentage of available memory. Allocating too much will produce
> -an error.
> +It will try to allocate as much as possible. If you allocate too
> +much, it can cause Out-Of-Memory to trigger.
>  
>   # echo 1000000000000 > buffer_size_kb
>  -bash: echo: write error: Cannot allocate memory
>   # cat buffer_size_kb
>  85
>  
> +The per_cpu buffers can be changed individually as well:
> +
> + # echo 10000 > per_cpu/cpu0/buffer_size_kb
> + # echo 100 > per_cpu/cpu1/buffer_size_kb
> +
> +When the per_cpu buffers are not the same, the buffer_size_kb
> +at the top level will just show an X
> +
> + # cat buffer_size_kb
> +X
> +
> +This is where the buffer_total_size_kb is useful:
> +
> + # cat buffer_total_size_kb 
> +12916
> +
> +Writing to the top level buffer_size_kb will reset all the buffers
> +to be the same again.
> +
>  Snapshot
>  --------
>  CONFIG_TRACER_SNAPSHOT makes a generic snapshot feature
> @@ -1925,7 +2607,188 @@ bash: echo: write error: Device or resource busy
>   # cat snapshot
>  cat: snapshot: Device or resource busy
>  
> +
> +Instances
> +---------
> +In the debugfs tracing directory is a directory called "instances".
> +This directory can have new directories created inside of it using
> +mkdir, and removing directories with rmdir. The directory created
> +with mkdir in this directory will already contain files and other
> +directories after it is created.
> +
> + # mkdir instances/foo
> + # ls instances/foo
> +buffer_size_kb  buffer_total_size_kb  events  free_buffer  per_cpu
> +set_event  snapshot  trace  trace_clock  trace_marker  trace_options
> +trace_pipe  tracing_on
> +
> +As you can see, the new directory looks similar to the tracing directory
> +itself. In fact, it is very similar, except that the buffer and
> +events are agnostic from the main director, or from any other
> +instances that are created.
> +
> +The files in the new directory work just like the files with the
> +same name in the tracing directory except the buffer that is used
> +is a separate and new buffer. The files affect that buffer but do not
> +affect the main buffer with the exception of trace_options. Currently,
> +the trace_options affect all instances and the top level buffer
> +the same, but this may change in future releases. That is, options
> +may become specific to the instance they reside in.
> +
> +Notice that none of the function tracer files are there, nor is
> +current_tracer and available_tracers. This is because the buffers
> +can currently only have events enabled for them.
> +
> + # mkdir instances/foo
> + # mkdir instances/bar
> + # mkdir instances/zoot
> + # echo 100000 > buffer_size_kb
> + # echo 1000 > instances/foo/buffer_size_kb
> + # echo 5000 > instances/bar/per_cpu/cpu1/buffer_size_kb
> + # echo function > current_trace
> + # echo 1 > instances/foo/events/sched/sched_wakeup/enable
> + # echo 1 > instances/foo/events/sched/sched_wakeup_new/enable
> + # echo 1 > instances/foo/events/sched/sched_switch/enable
> + # echo 1 > instances/bar/events/irq/enable
> + # echo 1 > instances/zoot/events/syscalls/enable
> + # cat trace_pipe
> +CPU:2 [LOST 11745 EVENTS]
> +            bash-2044  [002] .... 10594.481032: _raw_spin_lock_irqsave <-get_page_from_freelist
> +            bash-2044  [002] d... 10594.481032: add_preempt_count <-_raw_spin_lock_irqsave
> +            bash-2044  [002] d..1 10594.481032: __rmqueue <-get_page_from_freelist
> +            bash-2044  [002] d..1 10594.481033: _raw_spin_unlock <-get_page_from_freelist
> +            bash-2044  [002] d..1 10594.481033: sub_preempt_count <-_raw_spin_unlock
> +            bash-2044  [002] d... 10594.481033: get_pageblock_flags_group <-get_pageblock_migratetype
> +            bash-2044  [002] d... 10594.481034: __mod_zone_page_state <-get_page_from_freelist
> +            bash-2044  [002] d... 10594.481034: zone_statistics <-get_page_from_freelist
> +            bash-2044  [002] d... 10594.481034: __inc_zone_state <-zone_statistics
> +            bash-2044  [002] d... 10594.481034: __inc_zone_state <-zone_statistics
> +            bash-2044  [002] .... 10594.481035: arch_dup_task_struct <-copy_process
> +[...]
> +
> + # cat instances/foo/trace_pipe
> +            bash-1998  [000] d..4   136.676759: sched_wakeup: comm=kworker/0:1 pid=59 prio=120 success=1 target_cpu=000
> +            bash-1998  [000] dN.4   136.676760: sched_wakeup: comm=bash pid=1998 prio=120 success=1 target_cpu=000
> +          <idle>-0     [003] d.h3   136.676906: sched_wakeup: comm=rcu_preempt pid=9 prio=120 success=1 target_cpu=003
> +          <idle>-0     [003] d..3   136.676909: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=rcu_preempt next_pid=9 next_prio=120
> +     rcu_preempt-9     [003] d..3   136.676916: sched_switch: prev_comm=rcu_preempt prev_pid=9 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120
> +            bash-1998  [000] d..4   136.677014: sched_wakeup: comm=kworker/0:1 pid=59 prio=120 success=1 target_cpu=000
> +            bash-1998  [000] dN.4   136.677016: sched_wakeup: comm=bash pid=1998 prio=120 success=1 target_cpu=000
> +            bash-1998  [000] d..3   136.677018: sched_switch: prev_comm=bash prev_pid=1998 prev_prio=120 prev_state=R+ ==> next_comm=kworker/0:1 next_pid=59 next_prio=120
> +     kworker/0:1-59    [000] d..4   136.677022: sched_wakeup: comm=sshd pid=1995 prio=120 success=1 target_cpu=001
> +     kworker/0:1-59    [000] d..3   136.677025: sched_switch: prev_comm=kworker/0:1 prev_pid=59 prev_prio=120 prev_state=S ==> next_comm=bash next_pid=1998 next_prio=120
> +[...]
> +
> + # cat instances/bar/trace_pipe
> +     migration/1-14    [001] d.h3   138.732674: softirq_raise: vec=3 [action=NET_RX]
> +          <idle>-0     [001] dNh3   138.732725: softirq_raise: vec=3 [action=NET_RX]
> +            bash-1998  [000] d.h1   138.733101: softirq_raise: vec=1 [action=TIMER]
> +            bash-1998  [000] d.h1   138.733102: softirq_raise: vec=9 [action=RCU]
> +            bash-1998  [000] ..s2   138.733105: softirq_entry: vec=1 [action=TIMER]
> +            bash-1998  [000] ..s2   138.733106: softirq_exit: vec=1 [action=TIMER]
> +            bash-1998  [000] ..s2   138.733106: softirq_entry: vec=9 [action=RCU]
> +            bash-1998  [000] ..s2   138.733109: softirq_exit: vec=9 [action=RCU]
> +            sshd-1995  [001] d.h1   138.733278: irq_handler_entry: irq=21 name=uhci_hcd:usb4
> +            sshd-1995  [001] d.h1   138.733280: irq_handler_exit: irq=21 ret=unhandled
> +            sshd-1995  [001] d.h1   138.733281: irq_handler_entry: irq=21 name=eth0
> +            sshd-1995  [001] d.h1   138.733283: irq_handler_exit: irq=21 ret=handled
> +[...]
> +
> + # cat instances/zoot/trace
> +# tracer: nop
> +#
> +# entries-in-buffer/entries-written: 18996/18996   #P:4
> +#
> +#                              _-----=> irqs-off
> +#                             / _----=> need-resched
> +#                            | / _---=> hardirq/softirq
> +#                            || / _--=> preempt-depth
> +#                            ||| /     delay
> +#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
> +#              | |       |   ||||       |         |
> +            bash-1998  [000] d...   140.733501: sys_write -> 0x2
> +            bash-1998  [000] d...   140.733504: sys_dup2(oldfd: a, newfd: 1)
> +            bash-1998  [000] d...   140.733506: sys_dup2 -> 0x1
> +            bash-1998  [000] d...   140.733508: sys_fcntl(fd: a, cmd: 1, arg: 0)
> +            bash-1998  [000] d...   140.733509: sys_fcntl -> 0x1
> +            bash-1998  [000] d...   140.733510: sys_close(fd: a)
> +            bash-1998  [000] d...   140.733510: sys_close -> 0x0
> +            bash-1998  [000] d...   140.733514: sys_rt_sigprocmask(how: 0, nset: 0, oset: 6e2768, sigsetsize: 8)
> +            bash-1998  [000] d...   140.733515: sys_rt_sigprocmask -> 0x0
> +            bash-1998  [000] d...   140.733516: sys_rt_sigaction(sig: 2, act: 7fff718846f0, oact: 7fff71884650, sigsetsize: 8)
> +            bash-1998  [000] d...   140.733516: sys_rt_sigaction -> 0x0
> +
> +You can see that the trace of the top most trace buffer shows only
> +the function tracing. The foo instance displays wakeups and task
> +switches.
> +
> +To remove the instances, simply delete their directories:
> +
> + # rmdir instances/foo
> + # rmdir instances/bar
> + # rmdir instances/zoot
> +
> +Note, if a process has a trace file open in one of the instance
> +directories, the rmdir will fail with EBUSY.
> +
> +
> +Stack trace
>  -----------
> +Since the kernel has a fixed sized stack, it is important not to
> +waste it in functions. A kernel developer must be conscience of
> +what they allocate on the stack. If they add too much, the system
> +can be in danger of a stack overflow, and corruption will occur,
> +usually leading to a system panic.
> +
> +There are some tools that check this, usually with interrupts
> +periodically checking usage. But if you can perform a check
> +at every function call that will become very useful. As ftrace provides
> +a function tracer, it makes it convenient to check the stack size
> +at every function call. This is enabled via the stack tracer.
> +
> +CONFIG_STACK_TRACER enables the ftrace stack tracing functionality.
> +To enable it, write a '1' into /proc/sys/kernel/stack_tracer_enabled.
> +
> + # echo 1 > /proc/sys/kernel/stack_tracer_enabled
> +
> +You can also enable it from the kernel command line to trace
> +the stack size of the kernel during boot up, by adding "stacktrace"
> +to the kernel command line parameter.
> +
> +After running it for a few minutes, the output looks like:
> +
> + # cat stack_max_size
> +2928
> +
> + # cat stack_trace
> +        Depth    Size   Location    (18 entries)
> +        -----    ----   --------
> +  0)     2928     224   update_sd_lb_stats+0xbc/0x4ac
> +  1)     2704     160   find_busiest_group+0x31/0x1f1
> +  2)     2544     256   load_balance+0xd9/0x662
> +  3)     2288      80   idle_balance+0xbb/0x130
> +  4)     2208     128   __schedule+0x26e/0x5b9
> +  5)     2080      16   schedule+0x64/0x66
> +  6)     2064     128   schedule_timeout+0x34/0xe0
> +  7)     1936     112   wait_for_common+0x97/0xf1
> +  8)     1824      16   wait_for_completion+0x1d/0x1f
> +  9)     1808     128   flush_work+0xfe/0x119
> + 10)     1680      16   tty_flush_to_ldisc+0x1e/0x20
> + 11)     1664      48   input_available_p+0x1d/0x5c
> + 12)     1616      48   n_tty_poll+0x6d/0x134
> + 13)     1568      64   tty_poll+0x64/0x7f
> + 14)     1504     880   do_select+0x31e/0x511
> + 15)      624     400   core_sys_select+0x177/0x216
> + 16)      224      96   sys_select+0x91/0xb9
> + 17)      128     128   system_call_fastpath+0x16/0x1b
> +
> +Note, if -mfentry is being used by gcc, functions get traced before
> +they set up the stack frame. This means that leaf level functions
> +are not tested by the stack tracer when -mfentry is used.
> +
> +Currently, -mfentry is used by gcc 4.6.0 and above on x86 only.
> +
> +---------
>  
>  More details can be found in the source code, in the
>  kernel/trace/*.c files.
> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index e5ca8ef..832422d 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -259,8 +259,10 @@ struct ftrace_probe_ops {
>  	void			(*func)(unsigned long ip,
>  					unsigned long parent_ip,
>  					void **data);
> -	int			(*callback)(unsigned long ip, void **data);
> -	void			(*free)(void **data);
> +	int			(*init)(struct ftrace_probe_ops *ops,
> +					unsigned long ip, void **data);
> +	void			(*free)(struct ftrace_probe_ops *ops,
> +					unsigned long ip, void **data);
>  	int			(*print)(struct seq_file *m,
>  					 unsigned long ip,
>  					 struct ftrace_probe_ops *ops,
> diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
> index 13a54d0..4e28b01 100644
> --- a/include/linux/ftrace_event.h
> +++ b/include/linux/ftrace_event.h
> @@ -8,6 +8,7 @@
>  #include <linux/perf_event.h>
>  
>  struct trace_array;
> +struct trace_buffer;
>  struct tracer;
>  struct dentry;
>  
> @@ -38,6 +39,12 @@ const char *ftrace_print_symbols_seq_u64(struct trace_seq *p,
>  const char *ftrace_print_hex_seq(struct trace_seq *p,
>  				 const unsigned char *buf, int len);
>  
> +struct trace_iterator;
> +struct trace_event;
> +
> +int ftrace_raw_output_prep(struct trace_iterator *iter,
> +			   struct trace_event *event);
> +
>  /*
>   * The trace entry - the most basic unit of tracing. This is what
>   * is printed in the end as a single line in the trace output, such as:
> @@ -61,6 +68,7 @@ struct trace_entry {
>  struct trace_iterator {
>  	struct trace_array	*tr;
>  	struct tracer		*trace;
> +	struct trace_buffer	*trace_buffer;
>  	void			*private;
>  	int			cpu_file;
>  	struct mutex		mutex;
> @@ -95,8 +103,6 @@ enum trace_iter_flags {
>  };
>  
> 
> -struct trace_event;
> -
>  typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter,
>  				      int flags, struct trace_event *event);
>  
> @@ -128,6 +134,13 @@ enum print_line_t {
>  void tracing_generic_entry_update(struct trace_entry *entry,
>  				  unsigned long flags,
>  				  int pc);
> +struct ftrace_event_file;
> +
> +struct ring_buffer_event *
> +trace_event_buffer_lock_reserve(struct ring_buffer **current_buffer,
> +				struct ftrace_event_file *ftrace_file,
> +				int type, unsigned long len,
> +				unsigned long flags, int pc);
>  struct ring_buffer_event *
>  trace_current_buffer_lock_reserve(struct ring_buffer **current_buffer,
>  				  int type, unsigned long len,
> @@ -182,53 +195,49 @@ extern int ftrace_event_reg(struct ftrace_event_call *event,
>  			    enum trace_reg type, void *data);
>  
>  enum {
> -	TRACE_EVENT_FL_ENABLED_BIT,
>  	TRACE_EVENT_FL_FILTERED_BIT,
> -	TRACE_EVENT_FL_RECORDED_CMD_BIT,
>  	TRACE_EVENT_FL_CAP_ANY_BIT,
>  	TRACE_EVENT_FL_NO_SET_FILTER_BIT,
>  	TRACE_EVENT_FL_IGNORE_ENABLE_BIT,
> +	TRACE_EVENT_FL_WAS_ENABLED_BIT,
>  };
>  
> +/*
> + * Event flags:
> + *  FILTERED	  - The event has a filter attached
> + *  CAP_ANY	  - Any user can enable for perf
> + *  NO_SET_FILTER - Set when filter has error and is to be ignored
> + *  IGNORE_ENABLE - For ftrace internal events, do not enable with debugfs file
> + *  WAS_ENABLED   - Set and stays set when an event was ever enabled
> + *                    (used for module unloading, if a module event is enabled,
> + *                     it is best to clear the buffers that used it).
> + */
>  enum {
> -	TRACE_EVENT_FL_ENABLED		= (1 << TRACE_EVENT_FL_ENABLED_BIT),
>  	TRACE_EVENT_FL_FILTERED		= (1 << TRACE_EVENT_FL_FILTERED_BIT),
> -	TRACE_EVENT_FL_RECORDED_CMD	= (1 << TRACE_EVENT_FL_RECORDED_CMD_BIT),
>  	TRACE_EVENT_FL_CAP_ANY		= (1 << TRACE_EVENT_FL_CAP_ANY_BIT),
>  	TRACE_EVENT_FL_NO_SET_FILTER	= (1 << TRACE_EVENT_FL_NO_SET_FILTER_BIT),
>  	TRACE_EVENT_FL_IGNORE_ENABLE	= (1 << TRACE_EVENT_FL_IGNORE_ENABLE_BIT),
> +	TRACE_EVENT_FL_WAS_ENABLED	= (1 << TRACE_EVENT_FL_WAS_ENABLED_BIT),
>  };
>  
>  struct ftrace_event_call {
>  	struct list_head	list;
>  	struct ftrace_event_class *class;
>  	char			*name;
> -	struct dentry		*dir;
>  	struct trace_event	event;
>  	const char		*print_fmt;
>  	struct event_filter	*filter;
> +	struct list_head	*files;
>  	void			*mod;
>  	void			*data;
> -
>  	/*
> -	 * 32 bit flags:
> -	 *   bit 1:		enabled
> -	 *   bit 2:		filter_active
> -	 *   bit 3:		enabled cmd record
> -	 *   bit 4:		allow trace by non root (cap any)
> -	 *   bit 5:		failed to apply filter
> -	 *   bit 6:		ftrace internal event (do not enable)
> -	 *
> -	 * Changes to flags must hold the event_mutex.
> -	 *
> -	 * Note: Reads of flags do not hold the event_mutex since
> -	 * they occur in critical sections. But the way flags
> -	 * is currently used, these changes do no affect the code
> -	 * except that when a change is made, it may have a slight
> -	 * delay in propagating the changes to other CPUs due to
> -	 * caching and such.
> +	 *   bit 0:		filter_active
> +	 *   bit 1:		allow trace by non root (cap any)
> +	 *   bit 2:		failed to apply filter
> +	 *   bit 3:		ftrace internal event (do not enable)
> +	 *   bit 4:		Event was enabled by module
>  	 */
> -	unsigned int		flags;
> +	int			flags; /* static flags of different events */
>  
>  #ifdef CONFIG_PERF_EVENTS
>  	int				perf_refcount;
> @@ -236,6 +245,56 @@ struct ftrace_event_call {
>  #endif
>  };
>  
> +struct trace_array;
> +struct ftrace_subsystem_dir;
> +
> +enum {
> +	FTRACE_EVENT_FL_ENABLED_BIT,
> +	FTRACE_EVENT_FL_RECORDED_CMD_BIT,
> +	FTRACE_EVENT_FL_SOFT_MODE_BIT,
> +	FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
> +};
> +
> +/*
> + * Ftrace event file flags:
> + *  ENABLED	  - The event is enabled
> + *  RECORDED_CMD  - The comms should be recorded at sched_switch
> + *  SOFT_MODE     - The event is enabled/disabled by SOFT_DISABLED
> + *  SOFT_DISABLED - When set, do not trace the event (even though its
> + *                   tracepoint may be enabled)
> + */
> +enum {
> +	FTRACE_EVENT_FL_ENABLED		= (1 << FTRACE_EVENT_FL_ENABLED_BIT),
> +	FTRACE_EVENT_FL_RECORDED_CMD	= (1 << FTRACE_EVENT_FL_RECORDED_CMD_BIT),
> +	FTRACE_EVENT_FL_SOFT_MODE	= (1 << FTRACE_EVENT_FL_SOFT_MODE_BIT),
> +	FTRACE_EVENT_FL_SOFT_DISABLED	= (1 << FTRACE_EVENT_FL_SOFT_DISABLED_BIT),
> +};
> +
> +struct ftrace_event_file {
> +	struct list_head		list;
> +	struct ftrace_event_call	*event_call;
> +	struct dentry			*dir;
> +	struct trace_array		*tr;
> +	struct ftrace_subsystem_dir	*system;
> +
> +	/*
> +	 * 32 bit flags:
> +	 *   bit 0:		enabled
> +	 *   bit 1:		enabled cmd record
> +	 *   bit 2:		enable/disable with the soft disable bit
> +	 *   bit 3:		soft disabled
> +	 *
> +	 * Note: The bits must be set atomically to prevent races
> +	 * from other writers. Reads of flags do not need to be in
> +	 * sync as they occur in critical sections. But the way flags
> +	 * is currently used, these changes do not affect the code
> +	 * except that when a change is made, it may have a slight
> +	 * delay in propagating the changes to other CPUs due to
> +	 * caching and such. Which is mostly OK ;-)
> +	 */
> +	unsigned long		flags;
> +};
> +
>  #define __TRACE_EVENT_FLAGS(name, value)				\
>  	static int __init trace_init_flags_##name(void)			\
>  	{								\
> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
> index c566927..239dbb9 100644
> --- a/include/linux/kernel.h
> +++ b/include/linux/kernel.h
> @@ -483,6 +483,8 @@ enum ftrace_dump_mode {
>  void tracing_on(void);
>  void tracing_off(void);
>  int tracing_is_on(void);
> +void tracing_snapshot(void);
> +void tracing_snapshot_alloc(void);
>  
>  extern void tracing_start(void);
>  extern void tracing_stop(void);
> @@ -512,10 +514,32 @@ do {									\
>   *
>   * This is intended as a debugging tool for the developer only.
>   * Please refrain from leaving trace_printks scattered around in
> - * your code.
> + * your code. (Extra memory is used for special buffers that are
> + * allocated when trace_printk() is used)
> + *
> + * A little optization trick is done here. If there's only one
> + * argument, there's no need to scan the string for printf formats.
> + * The trace_puts() will suffice. But how can we take advantage of
> + * using trace_puts() when trace_printk() has only one argument?
> + * By stringifying the args and checking the size we can tell
> + * whether or not there are args. __stringify((__VA_ARGS__)) will
> + * turn into "()\0" with a size of 3 when there are no args, anything
> + * else will be bigger. All we need to do is define a string to this,
> + * and then take its size and compare to 3. If it's bigger, use
> + * do_trace_printk() otherwise, optimize it to trace_puts(). Then just
> + * let gcc optimize the rest.
>   */
>  
> -#define trace_printk(fmt, args...)					\
> +#define trace_printk(fmt, ...)				\
> +do {							\
> +	char _______STR[] = __stringify((__VA_ARGS__));	\
> +	if (sizeof(_______STR) > 3)			\
> +		do_trace_printk(fmt, ##__VA_ARGS__);	\
> +	else						\
> +		trace_puts(fmt);			\
> +} while (0)
> +
> +#define do_trace_printk(fmt, args...)					\
>  do {									\
>  	static const char *trace_printk_fmt				\
>  		__attribute__((section("__trace_printk_fmt"))) =	\
> @@ -535,7 +559,45 @@ int __trace_bprintk(unsigned long ip, const char *fmt, ...);
>  extern __printf(2, 3)
>  int __trace_printk(unsigned long ip, const char *fmt, ...);
>  
> -extern void trace_dump_stack(void);
> +/**
> + * trace_puts - write a string into the ftrace buffer
> + * @str: the string to record
> + *
> + * Note: __trace_bputs is an internal function for trace_puts and
> + *       the @ip is passed in via the trace_puts macro.
> + *
> + * This is similar to trace_printk() but is made for those really fast
> + * paths that a developer wants the least amount of "Heisenbug" affects,
> + * where the processing of the print format is still too much.
> + *
> + * This function allows a kernel developer to debug fast path sections
> + * that printk is not appropriate for. By scattering in various
> + * printk like tracing in the code, a developer can quickly see
> + * where problems are occurring.
> + *
> + * This is intended as a debugging tool for the developer only.
> + * Please refrain from leaving trace_puts scattered around in
> + * your code. (Extra memory is used for special buffers that are
> + * allocated when trace_puts() is used)
> + *
> + * Returns: 0 if nothing was written, positive # if string was.
> + *  (1 when __trace_bputs is used, strlen(str) when __trace_puts is used)
> + */
> +
> +extern int __trace_bputs(unsigned long ip, const char *str);
> +extern int __trace_puts(unsigned long ip, const char *str, int size);
> +#define trace_puts(str) ({						\
> +	static const char *trace_printk_fmt				\
> +		__attribute__((section("__trace_printk_fmt"))) =	\
> +		__builtin_constant_p(str) ? str : NULL;			\
> +									\
> +	if (__builtin_constant_p(str))					\
> +		__trace_bputs(_THIS_IP_, trace_printk_fmt);		\
> +	else								\
> +		__trace_puts(_THIS_IP_, str, strlen(str));		\
> +})
> +
> +extern void trace_dump_stack(int skip);
>  
>  /*
>   * The double __builtin_constant_p is because gcc will give us an error
> @@ -570,6 +632,8 @@ static inline void trace_dump_stack(void) { }
>  static inline void tracing_on(void) { }
>  static inline void tracing_off(void) { }
>  static inline int tracing_is_on(void) { return 0; }
> +static inline void tracing_snapshot(void) { }
> +static inline void tracing_snapshot_alloc(void) { }
>  
>  static inline __printf(1, 2)
>  int trace_printk(const char *fmt, ...)
> diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
> index 1342e69..d69cf63 100644
> --- a/include/linux/ring_buffer.h
> +++ b/include/linux/ring_buffer.h
> @@ -4,6 +4,7 @@
>  #include <linux/kmemcheck.h>
>  #include <linux/mm.h>
>  #include <linux/seq_file.h>
> +#include <linux/poll.h>
>  
>  struct ring_buffer;
>  struct ring_buffer_iter;
> @@ -96,6 +97,11 @@ __ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *k
>  	__ring_buffer_alloc((size), (flags), &__key);	\
>  })
>  
> +void ring_buffer_wait(struct ring_buffer *buffer, int cpu);
> +int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu,
> +			  struct file *filp, poll_table *poll_table);
> +
> +
>  #define RING_BUFFER_ALL_CPUS -1
>  
>  void ring_buffer_free(struct ring_buffer *buffer);
> diff --git a/include/linux/trace_clock.h b/include/linux/trace_clock.h
> index d563f37..1d7ca27 100644
> --- a/include/linux/trace_clock.h
> +++ b/include/linux/trace_clock.h
> @@ -16,6 +16,7 @@
>  
>  extern u64 notrace trace_clock_local(void);
>  extern u64 notrace trace_clock(void);
> +extern u64 notrace trace_clock_jiffies(void);
>  extern u64 notrace trace_clock_global(void);
>  extern u64 notrace trace_clock_counter(void);
>  
> diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
> index 40dc5e8..4bda044 100644
> --- a/include/trace/ftrace.h
> +++ b/include/trace/ftrace.h
> @@ -227,29 +227,18 @@ static notrace enum print_line_t					\
>  ftrace_raw_output_##call(struct trace_iterator *iter, int flags,	\
>  			 struct trace_event *trace_event)		\
>  {									\
> -	struct ftrace_event_call *event;				\
>  	struct trace_seq *s = &iter->seq;				\
> +	struct trace_seq __maybe_unused *p = &iter->tmp_seq;		\
>  	struct ftrace_raw_##call *field;				\
> -	struct trace_entry *entry;					\
> -	struct trace_seq *p = &iter->tmp_seq;				\
>  	int ret;							\
>  									\
> -	event = container_of(trace_event, struct ftrace_event_call,	\
> -			     event);					\
> -									\
> -	entry = iter->ent;						\
> -									\
> -	if (entry->type != event->event.type) {				\
> -		WARN_ON_ONCE(1);					\
> -		return TRACE_TYPE_UNHANDLED;				\
> -	}								\
> -									\
> -	field = (typeof(field))entry;					\
> +	field = (typeof(field))iter->ent;				\
>  									\
> -	trace_seq_init(p);						\
> -	ret = trace_seq_printf(s, "%s: ", event->name);			\
> +	ret = ftrace_raw_output_prep(iter, trace_event);		\
>  	if (ret)							\
> -		ret = trace_seq_printf(s, print);			\
> +		return ret;						\
> +									\
> +	ret = trace_seq_printf(s, print);				\
>  	if (!ret)							\
>  		return TRACE_TYPE_PARTIAL_LINE;				\
>  									\
> @@ -335,7 +324,7 @@ static struct trace_event_functions ftrace_event_type_funcs_##call = {	\
>  
>  #undef DECLARE_EVENT_CLASS
>  #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print)	\
> -static int notrace							\
> +static int notrace __init						\
>  ftrace_define_fields_##call(struct ftrace_event_call *event_call)	\
>  {									\
>  	struct ftrace_raw_##call field;					\
> @@ -414,7 +403,8 @@ static inline notrace int ftrace_get_offsets_##call(			\
>   *
>   * static void ftrace_raw_event_<call>(void *__data, proto)
>   * {
> - *	struct ftrace_event_call *event_call = __data;
> + *	struct ftrace_event_file *ftrace_file = __data;
> + *	struct ftrace_event_call *event_call = ftrace_file->event_call;
>   *	struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
>   *	struct ring_buffer_event *event;
>   *	struct ftrace_raw_<call> *entry; <-- defined in stage 1
> @@ -423,12 +413,16 @@ static inline notrace int ftrace_get_offsets_##call(			\
>   *	int __data_size;
>   *	int pc;
>   *
> + *	if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
> + *		     &ftrace_file->flags))
> + *		return;
> + *
>   *	local_save_flags(irq_flags);
>   *	pc = preempt_count();
>   *
>   *	__data_size = ftrace_get_offsets_<call>(&__data_offsets, args);
>   *
> - *	event = trace_current_buffer_lock_reserve(&buffer,
> + *	event = trace_event_buffer_lock_reserve(&buffer, ftrace_file,
>   *				  event_<call>->event.type,
>   *				  sizeof(*entry) + __data_size,
>   *				  irq_flags, pc);
> @@ -440,7 +434,7 @@ static inline notrace int ftrace_get_offsets_##call(			\
>   *			   __array macros.
>   *
>   *	if (!filter_current_check_discard(buffer, event_call, entry, event))
> - *		trace_current_buffer_unlock_commit(buffer,
> + *		trace_nowake_buffer_unlock_commit(buffer,
>   *						   event, irq_flags, pc);
>   * }
>   *
> @@ -518,7 +512,8 @@ static inline notrace int ftrace_get_offsets_##call(			\
>  static notrace void							\
>  ftrace_raw_event_##call(void *__data, proto)				\
>  {									\
> -	struct ftrace_event_call *event_call = __data;			\
> +	struct ftrace_event_file *ftrace_file = __data;			\
> +	struct ftrace_event_call *event_call = ftrace_file->event_call;	\
>  	struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
>  	struct ring_buffer_event *event;				\
>  	struct ftrace_raw_##call *entry;				\
> @@ -527,12 +522,16 @@ ftrace_raw_event_##call(void *__data, proto)				\
>  	int __data_size;						\
>  	int pc;								\
>  									\
> +	if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT,			\
> +		     &ftrace_file->flags))				\
> +		return;							\
> +									\
>  	local_save_flags(irq_flags);					\
>  	pc = preempt_count();						\
>  									\
>  	__data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
>  									\
> -	event = trace_current_buffer_lock_reserve(&buffer,		\
> +	event = trace_event_buffer_lock_reserve(&buffer, ftrace_file,	\
>  				 event_call->event.type,		\
>  				 sizeof(*entry) + __data_size,		\
>  				 irq_flags, pc);			\
> @@ -581,7 +580,7 @@ static inline void ftrace_test_probe_##call(void)			\
>  #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)	\
>  _TRACE_PERF_PROTO(call, PARAMS(proto));					\
>  static const char print_fmt_##call[] = print;				\
> -static struct ftrace_event_class __used event_class_##call = {		\
> +static struct ftrace_event_class __used __refdata event_class_##call = { \
>  	.system			= __stringify(TRACE_SYSTEM),		\
>  	.define_fields		= ftrace_define_fields_##call,		\
>  	.fields			= LIST_HEAD_INIT(event_class_##call.fields),\
> diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> index b516a8e..0b5ecf5 100644
> --- a/kernel/trace/Kconfig
> +++ b/kernel/trace/Kconfig
> @@ -191,6 +191,8 @@ config IRQSOFF_TRACER
>  	select GENERIC_TRACER
>  	select TRACER_MAX_TRACE
>  	select RING_BUFFER_ALLOW_SWAP
> +	select TRACER_SNAPSHOT
> +	select TRACER_SNAPSHOT_PER_CPU_SWAP
>  	help
>  	  This option measures the time spent in irqs-off critical
>  	  sections, with microsecond accuracy.
> @@ -213,6 +215,8 @@ config PREEMPT_TRACER
>  	select GENERIC_TRACER
>  	select TRACER_MAX_TRACE
>  	select RING_BUFFER_ALLOW_SWAP
> +	select TRACER_SNAPSHOT
> +	select TRACER_SNAPSHOT_PER_CPU_SWAP
>  	help
>  	  This option measures the time spent in preemption-off critical
>  	  sections, with microsecond accuracy.
> @@ -232,6 +236,7 @@ config SCHED_TRACER
>  	select GENERIC_TRACER
>  	select CONTEXT_SWITCH_TRACER
>  	select TRACER_MAX_TRACE
> +	select TRACER_SNAPSHOT
>  	help
>  	  This tracer tracks the latency of the highest priority task
>  	  to be scheduled in, starting from the point it has woken up.
> @@ -263,6 +268,27 @@ config TRACER_SNAPSHOT
>  	      echo 1 > /sys/kernel/debug/tracing/snapshot
>  	      cat snapshot
>  
> +config TRACER_SNAPSHOT_PER_CPU_SWAP
> +        bool "Allow snapshot to swap per CPU"
> +	depends on TRACER_SNAPSHOT
> +	select RING_BUFFER_ALLOW_SWAP
> +	help
> +	  Allow doing a snapshot of a single CPU buffer instead of a
> +	  full swap (all buffers). If this is set, then the following is
> +	  allowed:
> +
> +	      echo 1 > /sys/kernel/debug/tracing/per_cpu/cpu2/snapshot
> +
> +	  After which, only the tracing buffer for CPU 2 was swapped with
> +	  the main tracing buffer, and the other CPU buffers remain the same.
> +
> +	  When this is enabled, this adds a little more overhead to the
> +	  trace recording, as it needs to add some checks to synchronize
> +	  recording with swaps. But this does not affect the performance
> +	  of the overall system. This is enabled by default when the preempt
> +	  or irq latency tracers are enabled, as those need to swap as well
> +	  and already adds the overhead (plus a lot more).
> +
>  config TRACE_BRANCH_PROFILING
>  	bool
>  	select GENERIC_TRACER
> @@ -539,6 +565,29 @@ config RING_BUFFER_BENCHMARK
>  
>  	  If unsure, say N.
>  
> +config RING_BUFFER_STARTUP_TEST
> +       bool "Ring buffer startup self test"
> +       depends on RING_BUFFER
> +       help
> +         Run a simple self test on the ring buffer on boot up. Late in the
> +	 kernel boot sequence, the test will start that kicks off
> +	 a thread per cpu. Each thread will write various size events
> +	 into the ring buffer. Another thread is created to send IPIs
> +	 to each of the threads, where the IPI handler will also write
> +	 to the ring buffer, to test/stress the nesting ability.
> +	 If any anomalies are discovered, a warning will be displayed
> +	 and all ring buffers will be disabled.
> +
> +	 The test runs for 10 seconds. This will slow your boot time
> +	 by at least 10 more seconds.
> +
> +	 At the end of the test, statics and more checks are done.
> +	 It will output the stats of each per cpu buffer. What
> +	 was written, the sizes, what was read, what was lost, and
> +	 other similar details.
> +
> +	 If unsure, say N
> +
>  endif # FTRACE
>  
>  endif # TRACING_SUPPORT
> diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
> index 71259e2..90a5505 100644
> --- a/kernel/trace/blktrace.c
> +++ b/kernel/trace/blktrace.c
> @@ -72,7 +72,7 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action,
>  	bool blk_tracer = blk_tracer_enabled;
>  
>  	if (blk_tracer) {
> -		buffer = blk_tr->buffer;
> +		buffer = blk_tr->trace_buffer.buffer;
>  		pc = preempt_count();
>  		event = trace_buffer_lock_reserve(buffer, TRACE_BLK,
>  						  sizeof(*t) + len,
> @@ -218,7 +218,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
>  	if (blk_tracer) {
>  		tracing_record_cmdline(current);
>  
> -		buffer = blk_tr->buffer;
> +		buffer = blk_tr->trace_buffer.buffer;
>  		pc = preempt_count();
>  		event = trace_buffer_lock_reserve(buffer, TRACE_BLK,
>  						  sizeof(*t) + pdu_len,
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index e6effd0..2577082 100644
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -1068,7 +1068,7 @@ struct ftrace_func_probe {
>  	unsigned long		flags;
>  	unsigned long		ip;
>  	void			*data;
> -	struct rcu_head		rcu;
> +	struct list_head	free_list;
>  };
>  
>  struct ftrace_func_entry {
> @@ -2978,28 +2978,27 @@ static void __disable_ftrace_function_probe(void)
>  }
>  
> 
> -static void ftrace_free_entry_rcu(struct rcu_head *rhp)
> +static void ftrace_free_entry(struct ftrace_func_probe *entry)
>  {
> -	struct ftrace_func_probe *entry =
> -		container_of(rhp, struct ftrace_func_probe, rcu);
> -
>  	if (entry->ops->free)
> -		entry->ops->free(&entry->data);
> +		entry->ops->free(entry->ops, entry->ip, &entry->data);
>  	kfree(entry);
>  }
>  
> -
>  int
>  register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
>  			      void *data)
>  {
>  	struct ftrace_func_probe *entry;
> +	struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash;
> +	struct ftrace_hash *hash;
>  	struct ftrace_page *pg;
>  	struct dyn_ftrace *rec;
>  	int type, len, not;
>  	unsigned long key;
>  	int count = 0;
>  	char *search;
> +	int ret;
>  
>  	type = filter_parse_regex(glob, strlen(glob), &search, &not);
>  	len = strlen(search);
> @@ -3010,8 +3009,16 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
>  
>  	mutex_lock(&ftrace_lock);
>  
> -	if (unlikely(ftrace_disabled))
> +	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
> +	if (!hash) {
> +		count = -ENOMEM;
> +		goto out_unlock;
> +	}
> +
> +	if (unlikely(ftrace_disabled)) {
> +		count = -ENODEV;
>  		goto out_unlock;
> +	}
>  
>  	do_for_each_ftrace_rec(pg, rec) {
>  
> @@ -3035,14 +3042,21 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
>  		 * for each function we find. We call the callback
>  		 * to give the caller an opportunity to do so.
>  		 */
> -		if (ops->callback) {
> -			if (ops->callback(rec->ip, &entry->data) < 0) {
> +		if (ops->init) {
> +			if (ops->init(ops, rec->ip, &entry->data) < 0) {
>  				/* caller does not like this func */
>  				kfree(entry);
>  				continue;
>  			}
>  		}
>  
> +		ret = enter_record(hash, rec, 0);
> +		if (ret < 0) {
> +			kfree(entry);
> +			count = ret;
> +			goto out_unlock;
> +		}
> +
>  		entry->ops = ops;
>  		entry->ip = rec->ip;
>  
> @@ -3050,10 +3064,16 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
>  		hlist_add_head_rcu(&entry->node, &ftrace_func_hash[key]);
>  
>  	} while_for_each_ftrace_rec();
> +
> +	ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
> +	if (ret < 0)
> +		count = ret;
> +
>  	__enable_ftrace_function_probe();
>  
>   out_unlock:
>  	mutex_unlock(&ftrace_lock);
> +	free_ftrace_hash(hash);
>  
>  	return count;
>  }
> @@ -3067,7 +3087,12 @@ static void
>  __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
>  				  void *data, int flags)
>  {
> +	struct ftrace_func_entry *rec_entry;
>  	struct ftrace_func_probe *entry;
> +	struct ftrace_func_probe *p;
> +	struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash;
> +	struct list_head free_list;
> +	struct ftrace_hash *hash;
>  	struct hlist_node *n, *tmp;
>  	char str[KSYM_SYMBOL_LEN];
>  	int type = MATCH_FULL;
> @@ -3088,6 +3113,14 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
>  	}
>  
>  	mutex_lock(&ftrace_lock);
> +
> +	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
> +	if (!hash)
> +		/* Hmm, should report this somehow */
> +		goto out_unlock;
> +
> +	INIT_LIST_HEAD(&free_list);
> +
>  	for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
>  		struct hlist_head *hhd = &ftrace_func_hash[i];
>  
> @@ -3108,12 +3141,30 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
>  					continue;
>  			}
>  
> +			rec_entry = ftrace_lookup_ip(hash, entry->ip);
> +			/* It is possible more than one entry had this ip */
> +			if (rec_entry)
> +				free_hash_entry(hash, rec_entry);
> +
>  			hlist_del_rcu(&entry->node);
> -			call_rcu_sched(&entry->rcu, ftrace_free_entry_rcu);
> +			list_add(&entry->free_list, &free_list);
>  		}
>  	}
>  	__disable_ftrace_function_probe();
> +	/*
> +	 * Remove after the disable is called. Otherwise, if the last
> +	 * probe is removed, a null hash means *all enabled*.
> +	 */
> +	ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
> +	synchronize_sched();
> +	list_for_each_entry_safe(entry, p, &free_list, free_list) {
> +		list_del(&entry->free_list);
> +		ftrace_free_entry(entry);
> +	}
> +		
> + out_unlock:
>  	mutex_unlock(&ftrace_lock);
> +	free_ftrace_hash(hash);
>  }
>  
>  void
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index 7244acd..e5472f7 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
> @@ -8,13 +8,16 @@
>  #include <linux/trace_clock.h>
>  #include <linux/trace_seq.h>
>  #include <linux/spinlock.h>
> +#include <linux/irq_work.h>
>  #include <linux/debugfs.h>
>  #include <linux/uaccess.h>
>  #include <linux/hardirq.h>
> +#include <linux/kthread.h>	/* for self test */
>  #include <linux/kmemcheck.h>
>  #include <linux/module.h>
>  #include <linux/percpu.h>
>  #include <linux/mutex.h>
> +#include <linux/delay.h>
>  #include <linux/slab.h>
>  #include <linux/init.h>
>  #include <linux/hash.h>
> @@ -442,6 +445,12 @@ int ring_buffer_print_page_header(struct trace_seq *s)
>  	return ret;
>  }
>  
> +struct rb_irq_work {
> +	struct irq_work			work;
> +	wait_queue_head_t		waiters;
> +	bool				waiters_pending;
> +};
> +
>  /*
>   * head_page == tail_page && head == tail then buffer is empty.
>   */
> @@ -476,6 +485,8 @@ struct ring_buffer_per_cpu {
>  	struct list_head		new_pages; /* new pages to add */
>  	struct work_struct		update_pages_work;
>  	struct completion		update_done;
> +
> +	struct rb_irq_work		irq_work;
>  };
>  
>  struct ring_buffer {
> @@ -495,6 +506,8 @@ struct ring_buffer {
>  	struct notifier_block		cpu_notify;
>  #endif
>  	u64				(*clock)(void);
> +
> +	struct rb_irq_work		irq_work;
>  };
>  
>  struct ring_buffer_iter {
> @@ -506,6 +519,118 @@ struct ring_buffer_iter {
>  	u64				read_stamp;
>  };
>  
> +/*
> + * rb_wake_up_waiters - wake up tasks waiting for ring buffer input
> + *
> + * Schedules a delayed work to wake up any task that is blocked on the
> + * ring buffer waiters queue.
> + */
> +static void rb_wake_up_waiters(struct irq_work *work)
> +{
> +	struct rb_irq_work *rbwork = container_of(work, struct rb_irq_work, work);
> +
> +	wake_up_all(&rbwork->waiters);
> +}
> +
> +/**
> + * ring_buffer_wait - wait for input to the ring buffer
> + * @buffer: buffer to wait on
> + * @cpu: the cpu buffer to wait on
> + *
> + * If @cpu == RING_BUFFER_ALL_CPUS then the task will wake up as soon
> + * as data is added to any of the @buffer's cpu buffers. Otherwise
> + * it will wait for data to be added to a specific cpu buffer.
> + */
> +void ring_buffer_wait(struct ring_buffer *buffer, int cpu)
> +{
> +	struct ring_buffer_per_cpu *cpu_buffer;
> +	DEFINE_WAIT(wait);
> +	struct rb_irq_work *work;
> +
> +	/*
> +	 * Depending on what the caller is waiting for, either any
> +	 * data in any cpu buffer, or a specific buffer, put the
> +	 * caller on the appropriate wait queue.
> +	 */
> +	if (cpu == RING_BUFFER_ALL_CPUS)
> +		work = &buffer->irq_work;
> +	else {
> +		cpu_buffer = buffer->buffers[cpu];
> +		work = &cpu_buffer->irq_work;
> +	}
> +
> +
> +	prepare_to_wait(&work->waiters, &wait, TASK_INTERRUPTIBLE);
> +
> +	/*
> +	 * The events can happen in critical sections where
> +	 * checking a work queue can cause deadlocks.
> +	 * After adding a task to the queue, this flag is set
> +	 * only to notify events to try to wake up the queue
> +	 * using irq_work.
> +	 *
> +	 * We don't clear it even if the buffer is no longer
> +	 * empty. The flag only causes the next event to run
> +	 * irq_work to do the work queue wake up. The worse
> +	 * that can happen if we race with !trace_empty() is that
> +	 * an event will cause an irq_work to try to wake up
> +	 * an empty queue.
> +	 *
> +	 * There's no reason to protect this flag either, as
> +	 * the work queue and irq_work logic will do the necessary
> +	 * synchronization for the wake ups. The only thing
> +	 * that is necessary is that the wake up happens after
> +	 * a task has been queued. It's OK for spurious wake ups.
> +	 */
> +	work->waiters_pending = true;
> +
> +	if ((cpu == RING_BUFFER_ALL_CPUS && ring_buffer_empty(buffer)) ||
> +	    (cpu != RING_BUFFER_ALL_CPUS && ring_buffer_empty_cpu(buffer, cpu)))
> +		schedule();
> +
> +	finish_wait(&work->waiters, &wait);
> +}
> +
> +/**
> + * ring_buffer_poll_wait - poll on buffer input
> + * @buffer: buffer to wait on
> + * @cpu: the cpu buffer to wait on
> + * @filp: the file descriptor
> + * @poll_table: The poll descriptor
> + *
> + * If @cpu == RING_BUFFER_ALL_CPUS then the task will wake up as soon
> + * as data is added to any of the @buffer's cpu buffers. Otherwise
> + * it will wait for data to be added to a specific cpu buffer.
> + *
> + * Returns POLLIN | POLLRDNORM if data exists in the buffers,
> + * zero otherwise.
> + */
> +int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu,
> +			  struct file *filp, poll_table *poll_table)
> +{
> +	struct ring_buffer_per_cpu *cpu_buffer;
> +	struct rb_irq_work *work;
> +
> +	if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) ||
> +	    (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu)))
> +		return POLLIN | POLLRDNORM;
> +
> +	if (cpu == RING_BUFFER_ALL_CPUS)
> +		work = &buffer->irq_work;
> +	else {
> +		cpu_buffer = buffer->buffers[cpu];
> +		work = &cpu_buffer->irq_work;
> +	}
> +
> +	work->waiters_pending = true;
> +	poll_wait(filp, &work->waiters, poll_table);
> +
> +	if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) ||
> +	    (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu)))
> +		return POLLIN | POLLRDNORM;
> +	return 0;
> +}
> +
>  /* buffer may be either ring_buffer or ring_buffer_per_cpu */
>  #define RB_WARN_ON(b, cond)						\
>  	({								\
> @@ -1061,6 +1186,8 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int nr_pages, int cpu)
>  	cpu_buffer->lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
>  	INIT_WORK(&cpu_buffer->update_pages_work, update_pages_handler);
>  	init_completion(&cpu_buffer->update_done);
> +	init_irq_work(&cpu_buffer->irq_work.work, rb_wake_up_waiters);
> +	init_waitqueue_head(&cpu_buffer->irq_work.waiters);
>  
>  	bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
>  			    GFP_KERNEL, cpu_to_node(cpu));
> @@ -1156,6 +1283,9 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
>  	buffer->clock = trace_clock_local;
>  	buffer->reader_lock_key = key;
>  
> +	init_irq_work(&buffer->irq_work.work, rb_wake_up_waiters);
> +	init_waitqueue_head(&buffer->irq_work.waiters);
> +
>  	/* need at least two pages */
>  	if (nr_pages < 2)
>  		nr_pages = 2;
> @@ -1551,11 +1681,22 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
>  			if (!cpu_buffer->nr_pages_to_update)
>  				continue;
>  
> -			if (cpu_online(cpu))
> +			/* The update must run on the CPU that is being updated. */
> +			preempt_disable();
> +			if (cpu == smp_processor_id() || !cpu_online(cpu)) {
> +				rb_update_pages(cpu_buffer);
> +				cpu_buffer->nr_pages_to_update = 0;
> +			} else {
> +				/*
> +				 * Can not disable preemption for schedule_work_on()
> +				 * on PREEMPT_RT.
> +				 */
> +				preempt_enable();
>  				schedule_work_on(cpu,
>  						&cpu_buffer->update_pages_work);
> -			else
> -				rb_update_pages(cpu_buffer);
> +				preempt_disable();
> +			}
> +			preempt_enable();
>  		}
>  
>  		/* wait for all the updates to complete */
> @@ -1593,12 +1734,22 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
>  
>  		get_online_cpus();
>  
> -		if (cpu_online(cpu_id)) {
> +		preempt_disable();
> +		/* The update must run on the CPU that is being updated. */
> +		if (cpu_id == smp_processor_id() || !cpu_online(cpu_id))
> +			rb_update_pages(cpu_buffer);
> +		else {
> +			/*
> +			 * Can not disable preemption for schedule_work_on()
> +			 * on PREEMPT_RT.
> +			 */
> +			preempt_enable();
>  			schedule_work_on(cpu_id,
>  					 &cpu_buffer->update_pages_work);
>  			wait_for_completion(&cpu_buffer->update_done);
> -		} else
> -			rb_update_pages(cpu_buffer);
> +			preempt_disable();
> +		}
> +		preempt_enable();
>  
>  		cpu_buffer->nr_pages_to_update = 0;
>  		put_online_cpus();
> @@ -2610,6 +2761,22 @@ static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer,
>  	rb_end_commit(cpu_buffer);
>  }
>  
> +static __always_inline void
> +rb_wakeups(struct ring_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
> +{
> +	if (buffer->irq_work.waiters_pending) {
> +		buffer->irq_work.waiters_pending = false;
> +		/* irq_work_queue() supplies it's own memory barriers */
> +		irq_work_queue(&buffer->irq_work.work);
> +	}
> +
> +	if (cpu_buffer->irq_work.waiters_pending) {
> +		cpu_buffer->irq_work.waiters_pending = false;
> +		/* irq_work_queue() supplies it's own memory barriers */
> +		irq_work_queue(&cpu_buffer->irq_work.work);
> +	}
> +}
> +
>  /**
>   * ring_buffer_unlock_commit - commit a reserved
>   * @buffer: The buffer to commit to
> @@ -2629,6 +2796,8 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer,
>  
>  	rb_commit(cpu_buffer, event);
>  
> +	rb_wakeups(buffer, cpu_buffer);
> +
>  	trace_recursive_unlock();
>  
>  	preempt_enable_notrace();
> @@ -2801,6 +2970,8 @@ int ring_buffer_write(struct ring_buffer *buffer,
>  
>  	rb_commit(cpu_buffer, event);
>  
> +	rb_wakeups(buffer, cpu_buffer);
> +
>  	ret = 0;
>   out:
>  	preempt_enable_notrace();
> @@ -4465,3 +4636,320 @@ static int rb_cpu_notify(struct notifier_block *self,
>  	return NOTIFY_OK;
>  }
>  #endif
> +
> +#ifdef CONFIG_RING_BUFFER_STARTUP_TEST
> +/*
> + * This is a basic integrity check of the ring buffer.
> + * Late in the boot cycle this test will run when configured in.
> + * It will kick off a thread per CPU that will go into a loop
> + * writing to the per cpu ring buffer various sizes of data.
> + * Some of the data will be large items, some small.
> + *
> + * Another thread is created that goes into a spin, sending out
> + * IPIs to the other CPUs to also write into the ring buffer.
> + * this is to test the nesting ability of the buffer.
> + *
> + * Basic stats are recorded and reported. If something in the
> + * ring buffer should happen that's not expected, a big warning
> + * is displayed and all ring buffers are disabled.
> + */
> +static struct task_struct *rb_threads[NR_CPUS] __initdata;
> +
> +struct rb_test_data {
> +	struct ring_buffer	*buffer;
> +	unsigned long		events;
> +	unsigned long		bytes_written;
> +	unsigned long		bytes_alloc;
> +	unsigned long		bytes_dropped;
> +	unsigned long		events_nested;
> +	unsigned long		bytes_written_nested;
> +	unsigned long		bytes_alloc_nested;
> +	unsigned long		bytes_dropped_nested;
> +	int			min_size_nested;
> +	int			max_size_nested;
> +	int			max_size;
> +	int			min_size;
> +	int			cpu;
> +	int			cnt;
> +};
> +
> +static struct rb_test_data rb_data[NR_CPUS] __initdata;
> +
> +/* 1 meg per cpu */
> +#define RB_TEST_BUFFER_SIZE	1048576
> +
> +static char rb_string[] __initdata =
> +	"abcdefghijklmnopqrstuvwxyz1234567890!@...^&*()?+\\"
> +	"?+|:';\",.<>/?abcdefghijklmnopqrstuvwxyz1234567890"
> +	"!@...^&*()?+\\?+|:';\",.<>/?abcdefghijklmnopqrstuv";
> +
> +static bool rb_test_started __initdata;
> +
> +struct rb_item {
> +	int size;
> +	char str[];
> +};
> +
> +static __init int rb_write_something(struct rb_test_data *data, bool nested)
> +{
> +	struct ring_buffer_event *event;
> +	struct rb_item *item;
> +	bool started;
> +	int event_len;
> +	int size;
> +	int len;
> +	int cnt;
> +
> +	/* Have nested writes different that what is written */
> +	cnt = data->cnt + (nested ? 27 : 0);
> +
> +	/* Multiply cnt by ~e, to make some unique increment */
> +	size = (data->cnt * 68 / 25) % (sizeof(rb_string) - 1);
> +
> +	len = size + sizeof(struct rb_item);
> +
> +	started = rb_test_started;
> +	/* read rb_test_started before checking buffer enabled */
> +	smp_rmb();
> +
> +	event = ring_buffer_lock_reserve(data->buffer, len);
> +	if (!event) {
> +		/* Ignore dropped events before test starts. */
> +		if (started) {
> +			if (nested)
> +				data->bytes_dropped += len;
> +			else
> +				data->bytes_dropped_nested += len;
> +		}
> +		return len;
> +	}
> +
> +	event_len = ring_buffer_event_length(event);
> +
> +	if (RB_WARN_ON(data->buffer, event_len < len))
> +		goto out;
> +
> +	item = ring_buffer_event_data(event);
> +	item->size = size;
> +	memcpy(item->str, rb_string, size);
> +
> +	if (nested) {
> +		data->bytes_alloc_nested += event_len;
> +		data->bytes_written_nested += len;
> +		data->events_nested++;
> +		if (!data->min_size_nested || len < data->min_size_nested)
> +			data->min_size_nested = len;
> +		if (len > data->max_size_nested)
> +			data->max_size_nested = len;
> +	} else {
> +		data->bytes_alloc += event_len;
> +		data->bytes_written += len;
> +		data->events++;
> +		if (!data->min_size || len < data->min_size)
> +			data->max_size = len;
> +		if (len > data->max_size)
> +			data->max_size = len;
> +	}
> +
> + out:
> +	ring_buffer_unlock_commit(data->buffer, event);
> +
> +	return 0;
> +}
> +
> +static __init int rb_test(void *arg)
> +{
> +	struct rb_test_data *data = arg;
> +
> +	while (!kthread_should_stop()) {
> +		rb_write_something(data, false);
> +		data->cnt++;
> +
> +		set_current_state(TASK_INTERRUPTIBLE);
> +		/* Now sleep between a min of 100-300us and a max of 1ms */
> +		usleep_range(((data->cnt % 3) + 1) * 100, 1000);
> +	}
> +
> +	return 0;
> +}
> +
> +static __init void rb_ipi(void *ignore)
> +{
> +	struct rb_test_data *data;
> +	int cpu = smp_processor_id();
> +
> +	data = &rb_data[cpu];
> +	rb_write_something(data, true);
> +}
> +
> +static __init int rb_hammer_test(void *arg)
> +{
> +	while (!kthread_should_stop()) {
> +
> +		/* Send an IPI to all cpus to write data! */
> +		smp_call_function(rb_ipi, NULL, 1);
> +		/* No sleep, but for non preempt, let others run */
> +		schedule();
> +	}
> +
> +	return 0;
> +}
> +
> +static __init int test_ringbuffer(void)
> +{
> +	struct task_struct *rb_hammer;
> +	struct ring_buffer *buffer;
> +	int cpu;
> +	int ret = 0;
> +
> +	pr_info("Running ring buffer tests...\n");
> +
> +	buffer = ring_buffer_alloc(RB_TEST_BUFFER_SIZE, RB_FL_OVERWRITE);
> +	if (WARN_ON(!buffer))
> +		return 0;
> +
> +	/* Disable buffer so that threads can't write to it yet */
> +	ring_buffer_record_off(buffer);
> +
> +	for_each_online_cpu(cpu) {
> +		rb_data[cpu].buffer = buffer;
> +		rb_data[cpu].cpu = cpu;
> +		rb_data[cpu].cnt = cpu;
> +		rb_threads[cpu] = kthread_create(rb_test, &rb_data[cpu],
> +						 "rbtester/%d", cpu);
> +		if (WARN_ON(!rb_threads[cpu])) {
> +			pr_cont("FAILED\n");
> +			ret = -1;
> +			goto out_free;
> +		}
> +
> +		kthread_bind(rb_threads[cpu], cpu);
> + 		wake_up_process(rb_threads[cpu]);
> +	}
> +
> +	/* Now create the rb hammer! */
> +	rb_hammer = kthread_run(rb_hammer_test, NULL, "rbhammer");
> +	if (WARN_ON(!rb_hammer)) {
> +		pr_cont("FAILED\n");
> +		ret = -1;
> +		goto out_free;
> +	}
> +
> +	ring_buffer_record_on(buffer);
> +	/*
> +	 * Show buffer is enabled before setting rb_test_started.
> +	 * Yes there's a small race window where events could be
> +	 * dropped and the thread wont catch it. But when a ring
> +	 * buffer gets enabled, there will always be some kind of
> +	 * delay before other CPUs see it. Thus, we don't care about
> +	 * those dropped events. We care about events dropped after
> +	 * the threads see that the buffer is active.
> +	 */
> +	smp_wmb();
> +	rb_test_started = true;
> +
> +	set_current_state(TASK_INTERRUPTIBLE);
> +	/* Just run for 10 seconds */;
> +	schedule_timeout(10 * HZ);
> +
> +	kthread_stop(rb_hammer);
> +
> + out_free:
> +	for_each_online_cpu(cpu) {
> +		if (!rb_threads[cpu])
> +			break;
> +		kthread_stop(rb_threads[cpu]);
> +	}
> +	if (ret) {
> +		ring_buffer_free(buffer);
> +		return ret;
> +	}
> +
> +	/* Report! */
> +	pr_info("finished\n");
> +	for_each_online_cpu(cpu) {
> +		struct ring_buffer_event *event;
> +		struct rb_test_data *data = &rb_data[cpu];
> +		struct rb_item *item;
> +		unsigned long total_events;
> +		unsigned long total_dropped;
> +		unsigned long total_written;
> +		unsigned long total_alloc;
> +		unsigned long total_read = 0;
> +		unsigned long total_size = 0;
> +		unsigned long total_len = 0;
> +		unsigned long total_lost = 0;
> +		unsigned long lost;
> +		int big_event_size;
> +		int small_event_size;
> +
> +		ret = -1;
> +
> +		total_events = data->events + data->events_nested;
> +		total_written = data->bytes_written + data->bytes_written_nested;
> +		total_alloc = data->bytes_alloc + data->bytes_alloc_nested;
> +		total_dropped = data->bytes_dropped + data->bytes_dropped_nested;
> +
> +		big_event_size = data->max_size + data->max_size_nested;
> +		small_event_size = data->min_size + data->min_size_nested;
> +
> +		pr_info("CPU %d:\n", cpu);
> +		pr_info("              events:    %ld\n", total_events);
> +		pr_info("       dropped bytes:    %ld\n", total_dropped);
> +		pr_info("       alloced bytes:    %ld\n", total_alloc);
> +		pr_info("       written bytes:    %ld\n", total_written);
> +		pr_info("       biggest event:    %d\n", big_event_size);
> +		pr_info("      smallest event:    %d\n", small_event_size);
> +
> +		if (RB_WARN_ON(buffer, total_dropped))
> +			break;
> +
> +		ret = 0;
> +
> +		while ((event = ring_buffer_consume(buffer, cpu, NULL, &lost))) {
> +			total_lost += lost;
> +			item = ring_buffer_event_data(event);
> +			total_len += ring_buffer_event_length(event);
> +			total_size += item->size + sizeof(struct rb_item);
> +			if (memcmp(&item->str[0], rb_string, item->size) != 0) {
> +				pr_info("FAILED!\n");
> +				pr_info("buffer had: %.*s\n", item->size, item->str);
> +				pr_info("expected:   %.*s\n", item->size, rb_string);
> +				RB_WARN_ON(buffer, 1);
> +				ret = -1;
> +				break;
> +			}
> +			total_read++;
> +		}
> +		if (ret)
> +			break;
> +
> +		ret = -1;
> +
> +		pr_info("         read events:   %ld\n", total_read);
> +		pr_info("         lost events:   %ld\n", total_lost);
> +		pr_info("        total events:   %ld\n", total_lost + total_read);
> +		pr_info("  recorded len bytes:   %ld\n", total_len);
> +		pr_info(" recorded size bytes:   %ld\n", total_size);
> +		if (total_lost)
> +			pr_info(" With dropped events, record len and size may not match\n"
> +				" alloced and written from above\n");
> +		if (!total_lost) {
> +			if (RB_WARN_ON(buffer, total_len != total_alloc ||
> +				       total_size != total_written))
> +				break;
> +		}
> +		if (RB_WARN_ON(buffer, total_lost + total_read != total_events))
> +			break;
> +
> +		ret = 0;
> +	}
> +	if (!ret)
> +		pr_info("Ring buffer PASSED!\n");
> +
> +	ring_buffer_free(buffer);
> +	return 0;
> +}
> +
> +late_initcall(test_ringbuffer);
> +#endif /* CONFIG_RING_BUFFER_STARTUP_TEST */
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index 4f1dade..829b2be 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -1,7 +1,7 @@
>  /*
>   * ring buffer based function tracer
>   *
> - * Copyright (C) 2007-2008 Steven Rostedt <srostedt@...hat.com>
> + * Copyright (C) 2007-2012 Steven Rostedt <srostedt@...hat.com>
>   * Copyright (C) 2008 Ingo Molnar <mingo@...hat.com>
>   *
>   * Originally taken from the RT patch by:
> @@ -19,7 +19,6 @@
>  #include <linux/seq_file.h>
>  #include <linux/notifier.h>
>  #include <linux/irqflags.h>
> -#include <linux/irq_work.h>
>  #include <linux/debugfs.h>
>  #include <linux/pagemap.h>
>  #include <linux/hardirq.h>
> @@ -48,7 +47,7 @@
>   * On boot up, the ring buffer is set to the minimum size, so that
>   * we do not waste memory on systems that are not using tracing.
>   */
> -int ring_buffer_expanded;
> +bool ring_buffer_expanded;
>  
>  /*
>   * We need to change this state when a selftest is running.
> @@ -87,14 +86,6 @@ static int dummy_set_flag(u32 old_flags, u32 bit, int set)
>  static DEFINE_PER_CPU(bool, trace_cmdline_save);
>  
>  /*
> - * When a reader is waiting for data, then this variable is
> - * set to true.
> - */
> -static bool trace_wakeup_needed;
> -
> -static struct irq_work trace_work_wakeup;
> -
> -/*
>   * Kill all tracing for good (never come back).
>   * It is initialized to 1 but will turn to zero if the initialization
>   * of the tracer is successful. But that is the only place that sets
> @@ -130,12 +121,14 @@ static int tracing_set_tracer(const char *buf);
>  static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata;
>  static char *default_bootup_tracer;
>  
> +static bool allocate_snapshot;
> +
>  static int __init set_cmdline_ftrace(char *str)
>  {
>  	strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
>  	default_bootup_tracer = bootup_tracer_buf;
>  	/* We are using ftrace early, expand it */
> -	ring_buffer_expanded = 1;
> +	ring_buffer_expanded = true;
>  	return 1;
>  }
>  __setup("ftrace=", set_cmdline_ftrace);
> @@ -156,6 +149,15 @@ static int __init set_ftrace_dump_on_oops(char *str)
>  }
>  __setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
>  
> +static int __init boot_alloc_snapshot(char *str)
> +{
> +	allocate_snapshot = true;
> +	/* We also need the main ring buffer expanded */
> +	ring_buffer_expanded = true;
> +	return 1;
> +}
> +__setup("alloc_snapshot", boot_alloc_snapshot);
> +
>  
>  static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata;
>  static char *trace_boot_options __initdata;
> @@ -189,7 +191,7 @@ unsigned long long ns2usecs(cycle_t nsec)
>   */
>  static struct trace_array	global_trace;
>  
> -static DEFINE_PER_CPU(struct trace_array_cpu, global_trace_cpu);
> +LIST_HEAD(ftrace_trace_arrays);
>  
>  int filter_current_check_discard(struct ring_buffer *buffer,
>  				 struct ftrace_event_call *call, void *rec,
> @@ -204,29 +206,15 @@ cycle_t ftrace_now(int cpu)
>  	u64 ts;
>  
>  	/* Early boot up does not have a buffer yet */
> -	if (!global_trace.buffer)
> +	if (!global_trace.trace_buffer.buffer)
>  		return trace_clock_local();
>  
> -	ts = ring_buffer_time_stamp(global_trace.buffer, cpu);
> -	ring_buffer_normalize_time_stamp(global_trace.buffer, cpu, &ts);
> +	ts = ring_buffer_time_stamp(global_trace.trace_buffer.buffer, cpu);
> +	ring_buffer_normalize_time_stamp(global_trace.trace_buffer.buffer, cpu, &ts);
>  
>  	return ts;
>  }
>  
> -/*
> - * The max_tr is used to snapshot the global_trace when a maximum
> - * latency is reached. Some tracers will use this to store a maximum
> - * trace while it continues examining live traces.
> - *
> - * The buffers for the max_tr are set up the same as the global_trace.
> - * When a snapshot is taken, the link list of the max_tr is swapped
> - * with the link list of the global_trace and the buffers are reset for
> - * the global_trace so the tracing can continue.
> - */
> -static struct trace_array	max_tr;
> -
> -static DEFINE_PER_CPU(struct trace_array_cpu, max_tr_data);
> -
>  int tracing_is_enabled(void)
>  {
>  	return tracing_is_on();
> @@ -249,9 +237,6 @@ static unsigned long		trace_buf_size = TRACE_BUF_SIZE_DEFAULT;
>  /* trace_types holds a link list of available tracers. */
>  static struct tracer		*trace_types __read_mostly;
>  
> -/* current_trace points to the tracer that is currently active */
> -static struct tracer		*current_trace __read_mostly = &nop_trace;
> -
>  /*
>   * trace_types_lock is used to protect the trace_types list.
>   */
> @@ -285,13 +270,13 @@ static DEFINE_PER_CPU(struct mutex, cpu_access_lock);
>  
>  static inline void trace_access_lock(int cpu)
>  {
> -	if (cpu == TRACE_PIPE_ALL_CPU) {
> +	if (cpu == RING_BUFFER_ALL_CPUS) {
>  		/* gain it for accessing the whole ring buffer. */
>  		down_write(&all_cpu_access_lock);
>  	} else {
>  		/* gain it for accessing a cpu ring buffer. */
>  
> -		/* Firstly block other trace_access_lock(TRACE_PIPE_ALL_CPU). */
> +		/* Firstly block other trace_access_lock(RING_BUFFER_ALL_CPUS). */
>  		down_read(&all_cpu_access_lock);
>  
>  		/* Secondly block other access to this @cpu ring buffer. */
> @@ -301,7 +286,7 @@ static inline void trace_access_lock(int cpu)
>  
>  static inline void trace_access_unlock(int cpu)
>  {
> -	if (cpu == TRACE_PIPE_ALL_CPU) {
> +	if (cpu == RING_BUFFER_ALL_CPUS) {
>  		up_write(&all_cpu_access_lock);
>  	} else {
>  		mutex_unlock(&per_cpu(cpu_access_lock, cpu));
> @@ -339,30 +324,11 @@ static inline void trace_access_lock_init(void)
>  
>  #endif
>  
> -/* trace_wait is a waitqueue for tasks blocked on trace_poll */
> -static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
> -
>  /* trace_flags holds trace_options default values */
>  unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
>  	TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
>  	TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
> -	TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS;
> -
> -static int trace_stop_count;
> -static DEFINE_RAW_SPINLOCK(tracing_start_lock);
> -
> -/**
> - * trace_wake_up - wake up tasks waiting for trace input
> - *
> - * Schedules a delayed work to wake up any task that is blocked on the
> - * trace_wait queue. These is used with trace_poll for tasks polling the
> - * trace.
> - */
> -static void trace_wake_up(struct irq_work *work)
> -{
> -	wake_up_all(&trace_wait);
> -
> -}
> +	TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION;
>  
>  /**
>   * tracing_on - enable tracing buffers
> @@ -372,8 +338,8 @@ static void trace_wake_up(struct irq_work *work)
>   */
>  void tracing_on(void)
>  {
> -	if (global_trace.buffer)
> -		ring_buffer_record_on(global_trace.buffer);
> +	if (global_trace.trace_buffer.buffer)
> +		ring_buffer_record_on(global_trace.trace_buffer.buffer);
>  	/*
>  	 * This flag is only looked at when buffers haven't been
>  	 * allocated yet. We don't really care about the race
> @@ -385,6 +351,196 @@ void tracing_on(void)
>  EXPORT_SYMBOL_GPL(tracing_on);
>  
>  /**
> + * __trace_puts - write a constant string into the trace buffer.
> + * @ip:	   The address of the caller
> + * @str:   The constant string to write
> + * @size:  The size of the string.
> + */
> +int __trace_puts(unsigned long ip, const char *str, int size)
> +{
> +	struct ring_buffer_event *event;
> +	struct ring_buffer *buffer;
> +	struct print_entry *entry;
> +	unsigned long irq_flags;
> +	int alloc;
> +
> +	alloc = sizeof(*entry) + size + 2; /* possible \n added */
> +
> +	local_save_flags(irq_flags);
> +	buffer = global_trace.trace_buffer.buffer;
> +	event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc, 
> +					  irq_flags, preempt_count());
> +	if (!event)
> +		return 0;
> +
> +	entry = ring_buffer_event_data(event);
> +	entry->ip = ip;
> +
> +	memcpy(&entry->buf, str, size);
> +
> +	/* Add a newline if necessary */
> +	if (entry->buf[size - 1] != '\n') {
> +		entry->buf[size] = '\n';
> +		entry->buf[size + 1] = '\0';
> +	} else
> +		entry->buf[size] = '\0';
> +
> +	__buffer_unlock_commit(buffer, event);
> +
> +	return size;
> +}
> +EXPORT_SYMBOL_GPL(__trace_puts);
> +
> +/**
> + * __trace_bputs - write the pointer to a constant string into trace buffer
> + * @ip:	   The address of the caller
> + * @str:   The constant string to write to the buffer to
> + */
> +int __trace_bputs(unsigned long ip, const char *str)
> +{
> +	struct ring_buffer_event *event;
> +	struct ring_buffer *buffer;
> +	struct bputs_entry *entry;
> +	unsigned long irq_flags;
> +	int size = sizeof(struct bputs_entry);
> +
> +	local_save_flags(irq_flags);
> +	buffer = global_trace.trace_buffer.buffer;
> +	event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size,
> +					  irq_flags, preempt_count());
> +	if (!event)
> +		return 0;
> +
> +	entry = ring_buffer_event_data(event);
> +	entry->ip			= ip;
> +	entry->str			= str;
> +
> +	__buffer_unlock_commit(buffer, event);
> +
> +	return 1;
> +}
> +EXPORT_SYMBOL_GPL(__trace_bputs);
> +
> +#ifdef CONFIG_TRACER_SNAPSHOT
> +/**
> + * trace_snapshot - take a snapshot of the current buffer.
> + *
> + * This causes a swap between the snapshot buffer and the current live
> + * tracing buffer. You can use this to take snapshots of the live
> + * trace when some condition is triggered, but continue to trace.
> + *
> + * Note, make sure to allocate the snapshot with either
> + * a tracing_snapshot_alloc(), or by doing it manually
> + * with: echo 1 > /sys/kernel/debug/tracing/snapshot
> + *
> + * If the snapshot buffer is not allocated, it will stop tracing.
> + * Basically making a permanent snapshot.
> + */
> +void tracing_snapshot(void)
> +{
> +	struct trace_array *tr = &global_trace;
> +	struct tracer *tracer = tr->current_trace;
> +	unsigned long flags;
> +
> +	if (in_nmi()) {
> +		internal_trace_puts("*** SNAPSHOT CALLED FROM NMI CONTEXT ***\n");
> +		internal_trace_puts("*** snapshot is being ignored        ***\n");
> +		return;
> +	}
> +
> +	if (!tr->allocated_snapshot) {
> +		internal_trace_puts("*** SNAPSHOT NOT ALLOCATED ***\n");
> +		internal_trace_puts("*** stopping trace here!   ***\n");
> +		tracing_off();
> +		return;
> +	}
> +
> +	/* Note, snapshot can not be used when the tracer uses it */
> +	if (tracer->use_max_tr) {
> +		internal_trace_puts("*** LATENCY TRACER ACTIVE ***\n");
> +		internal_trace_puts("*** Can not use snapshot (sorry) ***\n");
> +		return;
> +	}
> +
> +	local_irq_save(flags);
> +	update_max_tr(tr, current, smp_processor_id());
> +	local_irq_restore(flags);
> +}
> +EXPORT_SYMBOL_GPL(tracing_snapshot);
> +
> +static int resize_buffer_duplicate_size(struct trace_buffer *trace_buf,
> +					struct trace_buffer *size_buf, int cpu_id);
> +static void set_buffer_entries(struct trace_buffer *buf, unsigned long val);
> +
> +static int alloc_snapshot(struct trace_array *tr)
> +{
> +	int ret;
> +
> +	if (!tr->allocated_snapshot) {
> +
> +		/* allocate spare buffer */
> +		ret = resize_buffer_duplicate_size(&tr->max_buffer,
> +				   &tr->trace_buffer, RING_BUFFER_ALL_CPUS);
> +		if (ret < 0)
> +			return ret;
> +
> +		tr->allocated_snapshot = true;
> +	}
> +
> +	return 0;
> +}
> +
> +void free_snapshot(struct trace_array *tr)
> +{
> +	/*
> +	 * We don't free the ring buffer. instead, resize it because
> +	 * The max_tr ring buffer has some state (e.g. ring->clock) and
> +	 * we want preserve it.
> +	 */
> +	ring_buffer_resize(tr->max_buffer.buffer, 1, RING_BUFFER_ALL_CPUS);
> +	set_buffer_entries(&tr->max_buffer, 1);
> +	tracing_reset_online_cpus(&tr->max_buffer);
> +	tr->allocated_snapshot = false;
> +}
> +
> +/**
> + * trace_snapshot_alloc - allocate and take a snapshot of the current buffer.
> + *
> + * This is similar to trace_snapshot(), but it will allocate the
> + * snapshot buffer if it isn't already allocated. Use this only
> + * where it is safe to sleep, as the allocation may sleep.
> + *
> + * This causes a swap between the snapshot buffer and the current live
> + * tracing buffer. You can use this to take snapshots of the live
> + * trace when some condition is triggered, but continue to trace.
> + */
> +void tracing_snapshot_alloc(void)
> +{
> +	struct trace_array *tr = &global_trace;
> +	int ret;
> +
> +	ret = alloc_snapshot(tr);
> +	if (WARN_ON(ret < 0))
> +		return;
> +
> +	tracing_snapshot();
> +}
> +EXPORT_SYMBOL_GPL(tracing_snapshot_alloc);
> +#else
> +void tracing_snapshot(void)
> +{
> +	WARN_ONCE(1, "Snapshot feature not enabled, but internal snapshot used");
> +}
> +EXPORT_SYMBOL_GPL(tracing_snapshot);
> +void tracing_snapshot_alloc(void)
> +{
> +	/* Give warning */
> +	tracing_snapshot();
> +}
> +EXPORT_SYMBOL_GPL(tracing_snapshot_alloc);
> +#endif /* CONFIG_TRACER_SNAPSHOT */
> +
> +/**
>   * tracing_off - turn off tracing buffers
>   *
>   * This function stops the tracing buffers from recording data.
> @@ -394,8 +550,8 @@ EXPORT_SYMBOL_GPL(tracing_on);
>   */
>  void tracing_off(void)
>  {
> -	if (global_trace.buffer)
> -		ring_buffer_record_off(global_trace.buffer);
> +	if (global_trace.trace_buffer.buffer)
> +		ring_buffer_record_off(global_trace.trace_buffer.buffer);
>  	/*
>  	 * This flag is only looked at when buffers haven't been
>  	 * allocated yet. We don't really care about the race
> @@ -411,8 +567,8 @@ EXPORT_SYMBOL_GPL(tracing_off);
>   */
>  int tracing_is_on(void)
>  {
> -	if (global_trace.buffer)
> -		return ring_buffer_record_is_on(global_trace.buffer);
> +	if (global_trace.trace_buffer.buffer)
> +		return ring_buffer_record_is_on(global_trace.trace_buffer.buffer);
>  	return !global_trace.buffer_disabled;
>  }
>  EXPORT_SYMBOL_GPL(tracing_is_on);
> @@ -479,6 +635,7 @@ static const char *trace_options[] = {
>  	"disable_on_free",
>  	"irq-info",
>  	"markers",
> +	"function-trace",
>  	NULL
>  };
>  
> @@ -490,6 +647,8 @@ static struct {
>  	{ trace_clock_local,	"local",	1 },
>  	{ trace_clock_global,	"global",	1 },
>  	{ trace_clock_counter,	"counter",	0 },
> +	{ trace_clock_jiffies,	"uptime",	1 },
> +	{ trace_clock,		"perf",		1 },
>  	ARCH_TRACE_CLOCKS
>  };
>  
> @@ -670,13 +829,14 @@ unsigned long __read_mostly	tracing_max_latency;
>  static void
>  __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
>  {
> -	struct trace_array_cpu *data = tr->data[cpu];
> -	struct trace_array_cpu *max_data;
> +	struct trace_buffer *trace_buf = &tr->trace_buffer;
> +	struct trace_buffer *max_buf = &tr->max_buffer;
> +	struct trace_array_cpu *data = per_cpu_ptr(trace_buf->data, cpu);
> +	struct trace_array_cpu *max_data = per_cpu_ptr(max_buf->data, cpu);
>  
> -	max_tr.cpu = cpu;
> -	max_tr.time_start = data->preempt_timestamp;
> +	max_buf->cpu = cpu;
> +	max_buf->time_start = data->preempt_timestamp;
>  
> -	max_data = max_tr.data[cpu];
>  	max_data->saved_latency = tracing_max_latency;
>  	max_data->critical_start = data->critical_start;
>  	max_data->critical_end = data->critical_end;
> @@ -706,22 +866,22 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
>  {
>  	struct ring_buffer *buf;
>  
> -	if (trace_stop_count)
> +	if (tr->stop_count)
>  		return;
>  
>  	WARN_ON_ONCE(!irqs_disabled());
>  
> -	if (!current_trace->allocated_snapshot) {
> +	if (!tr->allocated_snapshot) {
>  		/* Only the nop tracer should hit this when disabling */
> -		WARN_ON_ONCE(current_trace != &nop_trace);
> +		WARN_ON_ONCE(tr->current_trace != &nop_trace);
>  		return;
>  	}
>  
>  	arch_spin_lock(&ftrace_max_lock);
>  
> -	buf = tr->buffer;
> -	tr->buffer = max_tr.buffer;
> -	max_tr.buffer = buf;
> +	buf = tr->trace_buffer.buffer;
> +	tr->trace_buffer.buffer = tr->max_buffer.buffer;
> +	tr->max_buffer.buffer = buf;
>  
>  	__update_max_tr(tr, tsk, cpu);
>  	arch_spin_unlock(&ftrace_max_lock);
> @@ -740,16 +900,16 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
>  {
>  	int ret;
>  
> -	if (trace_stop_count)
> +	if (tr->stop_count)
>  		return;
>  
>  	WARN_ON_ONCE(!irqs_disabled());
> -	if (WARN_ON_ONCE(!current_trace->allocated_snapshot))
> +	if (WARN_ON_ONCE(!tr->allocated_snapshot))
>  		return;
>  
>  	arch_spin_lock(&ftrace_max_lock);
>  
> -	ret = ring_buffer_swap_cpu(max_tr.buffer, tr->buffer, cpu);
> +	ret = ring_buffer_swap_cpu(tr->max_buffer.buffer, tr->trace_buffer.buffer, cpu);
>  
>  	if (ret == -EBUSY) {
>  		/*
> @@ -758,7 +918,7 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
>  		 * the max trace buffer (no one writes directly to it)
>  		 * and flag that it failed.
>  		 */
> -		trace_array_printk(&max_tr, _THIS_IP_,
> +		trace_array_printk_buf(tr->max_buffer.buffer, _THIS_IP_,
>  			"Failed to swap buffers due to commit in progress\n");
>  	}
>  
> @@ -771,37 +931,78 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
>  
>  static void default_wait_pipe(struct trace_iterator *iter)
>  {
> -	DEFINE_WAIT(wait);
> +	/* Iterators are static, they should be filled or empty */
> +	if (trace_buffer_iter(iter, iter->cpu_file))
> +		return;
> +
> +	ring_buffer_wait(iter->trace_buffer->buffer, iter->cpu_file);
> +}
> +
> +#ifdef CONFIG_FTRACE_STARTUP_TEST
> +static int run_tracer_selftest(struct tracer *type)
> +{
> +	struct trace_array *tr = &global_trace;
> +	struct tracer *saved_tracer = tr->current_trace;
> +	int ret;
>  
> -	prepare_to_wait(&trace_wait, &wait, TASK_INTERRUPTIBLE);
> +	if (!type->selftest || tracing_selftest_disabled)
> +		return 0;
>  
>  	/*
> -	 * The events can happen in critical sections where
> -	 * checking a work queue can cause deadlocks.
> -	 * After adding a task to the queue, this flag is set
> -	 * only to notify events to try to wake up the queue
> -	 * using irq_work.
> -	 *
> -	 * We don't clear it even if the buffer is no longer
> -	 * empty. The flag only causes the next event to run
> -	 * irq_work to do the work queue wake up. The worse
> -	 * that can happen if we race with !trace_empty() is that
> -	 * an event will cause an irq_work to try to wake up
> -	 * an empty queue.
> -	 *
> -	 * There's no reason to protect this flag either, as
> -	 * the work queue and irq_work logic will do the necessary
> -	 * synchronization for the wake ups. The only thing
> -	 * that is necessary is that the wake up happens after
> -	 * a task has been queued. It's OK for spurious wake ups.
> +	 * Run a selftest on this tracer.
> +	 * Here we reset the trace buffer, and set the current
> +	 * tracer to be this tracer. The tracer can then run some
> +	 * internal tracing to verify that everything is in order.
> +	 * If we fail, we do not register this tracer.
>  	 */
> -	trace_wakeup_needed = true;
> +	tracing_reset_online_cpus(&tr->trace_buffer);
>  
> -	if (trace_empty(iter))
> -		schedule();
> +	tr->current_trace = type;
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	if (type->use_max_tr) {
> +		/* If we expanded the buffers, make sure the max is expanded too */
> +		if (ring_buffer_expanded)
> +			ring_buffer_resize(tr->max_buffer.buffer, trace_buf_size,
> +					   RING_BUFFER_ALL_CPUS);
> +		tr->allocated_snapshot = true;
> +	}
> +#endif
> +
> +	/* the test is responsible for initializing and enabling */
> +	pr_info("Testing tracer %s: ", type->name);
> +	ret = type->selftest(type, tr);
> +	/* the test is responsible for resetting too */
> +	tr->current_trace = saved_tracer;
> +	if (ret) {
> +		printk(KERN_CONT "FAILED!\n");
> +		/* Add the warning after printing 'FAILED' */
> +		WARN_ON(1);
> +		return -1;
> +	}
> +	/* Only reset on passing, to avoid touching corrupted buffers */
> +	tracing_reset_online_cpus(&tr->trace_buffer);
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	if (type->use_max_tr) {
> +		tr->allocated_snapshot = false;
>  
> -	finish_wait(&trace_wait, &wait);
> +		/* Shrink the max buffer again */
> +		if (ring_buffer_expanded)
> +			ring_buffer_resize(tr->max_buffer.buffer, 1,
> +					   RING_BUFFER_ALL_CPUS);
> +	}
> +#endif
> +
> +	printk(KERN_CONT "PASSED\n");
> +	return 0;
> +}
> +#else
> +static inline int run_tracer_selftest(struct tracer *type)
> +{
> +	return 0;
>  }
> +#endif /* CONFIG_FTRACE_STARTUP_TEST */
>  
>  /**
>   * register_tracer - register a tracer with the ftrace system.
> @@ -848,57 +1049,9 @@ int register_tracer(struct tracer *type)
>  	if (!type->wait_pipe)
>  		type->wait_pipe = default_wait_pipe;
>  
> -
> -#ifdef CONFIG_FTRACE_STARTUP_TEST
> -	if (type->selftest && !tracing_selftest_disabled) {
> -		struct tracer *saved_tracer = current_trace;
> -		struct trace_array *tr = &global_trace;
> -
> -		/*
> -		 * Run a selftest on this tracer.
> -		 * Here we reset the trace buffer, and set the current
> -		 * tracer to be this tracer. The tracer can then run some
> -		 * internal tracing to verify that everything is in order.
> -		 * If we fail, we do not register this tracer.
> -		 */
> -		tracing_reset_online_cpus(tr);
> -
> -		current_trace = type;
> -
> -		if (type->use_max_tr) {
> -			/* If we expanded the buffers, make sure the max is expanded too */
> -			if (ring_buffer_expanded)
> -				ring_buffer_resize(max_tr.buffer, trace_buf_size,
> -						   RING_BUFFER_ALL_CPUS);
> -			type->allocated_snapshot = true;
> -		}
> -
> -		/* the test is responsible for initializing and enabling */
> -		pr_info("Testing tracer %s: ", type->name);
> -		ret = type->selftest(type, tr);
> -		/* the test is responsible for resetting too */
> -		current_trace = saved_tracer;
> -		if (ret) {
> -			printk(KERN_CONT "FAILED!\n");
> -			/* Add the warning after printing 'FAILED' */
> -			WARN_ON(1);
> -			goto out;
> -		}
> -		/* Only reset on passing, to avoid touching corrupted buffers */
> -		tracing_reset_online_cpus(tr);
> -
> -		if (type->use_max_tr) {
> -			type->allocated_snapshot = false;
> -
> -			/* Shrink the max buffer again */
> -			if (ring_buffer_expanded)
> -				ring_buffer_resize(max_tr.buffer, 1,
> -						   RING_BUFFER_ALL_CPUS);
> -		}
> -
> -		printk(KERN_CONT "PASSED\n");
> -	}
> -#endif
> +	ret = run_tracer_selftest(type);
> +	if (ret < 0)
> +		goto out;
>  
>  	type->next = trace_types;
>  	trace_types = type;
> @@ -918,7 +1071,7 @@ int register_tracer(struct tracer *type)
>  	tracing_set_tracer(type->name);
>  	default_bootup_tracer = NULL;
>  	/* disable other selftests, since this will break it. */
> -	tracing_selftest_disabled = 1;
> +	tracing_selftest_disabled = true;
>  #ifdef CONFIG_FTRACE_STARTUP_TEST
>  	printk(KERN_INFO "Disabling FTRACE selftests due to running tracer '%s'\n",
>  	       type->name);
> @@ -928,9 +1081,9 @@ int register_tracer(struct tracer *type)
>  	return ret;
>  }
>  
> -void tracing_reset(struct trace_array *tr, int cpu)
> +void tracing_reset(struct trace_buffer *buf, int cpu)
>  {
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = buf->buffer;
>  
>  	if (!buffer)
>  		return;
> @@ -944,9 +1097,9 @@ void tracing_reset(struct trace_array *tr, int cpu)
>  	ring_buffer_record_enable(buffer);
>  }
>  
> -void tracing_reset_online_cpus(struct trace_array *tr)
> +void tracing_reset_online_cpus(struct trace_buffer *buf)
>  {
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = buf->buffer;
>  	int cpu;
>  
>  	if (!buffer)
> @@ -957,7 +1110,7 @@ void tracing_reset_online_cpus(struct trace_array *tr)
>  	/* Make sure all commits have finished */
>  	synchronize_sched();
>  
> -	tr->time_start = ftrace_now(tr->cpu);
> +	buf->time_start = ftrace_now(buf->cpu);
>  
>  	for_each_online_cpu(cpu)
>  		ring_buffer_reset_cpu(buffer, cpu);
> @@ -967,12 +1120,21 @@ void tracing_reset_online_cpus(struct trace_array *tr)
>  
>  void tracing_reset_current(int cpu)
>  {
> -	tracing_reset(&global_trace, cpu);
> +	tracing_reset(&global_trace.trace_buffer, cpu);
>  }
>  
> -void tracing_reset_current_online_cpus(void)
> +void tracing_reset_all_online_cpus(void)
>  {
> -	tracing_reset_online_cpus(&global_trace);
> +	struct trace_array *tr;
> +
> +	mutex_lock(&trace_types_lock);
> +	list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> +		tracing_reset_online_cpus(&tr->trace_buffer);
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +		tracing_reset_online_cpus(&tr->max_buffer);
> +#endif
> +	}
> +	mutex_unlock(&trace_types_lock);
>  }
>  
>  #define SAVED_CMDLINES 128
> @@ -995,7 +1157,7 @@ static void trace_init_cmdlines(void)
>  
>  int is_tracing_stopped(void)
>  {
> -	return trace_stop_count;
> +	return global_trace.stop_count;
>  }
>  
>  /**
> @@ -1027,12 +1189,12 @@ void tracing_start(void)
>  	if (tracing_disabled)
>  		return;
>  
> -	raw_spin_lock_irqsave(&tracing_start_lock, flags);
> -	if (--trace_stop_count) {
> -		if (trace_stop_count < 0) {
> +	raw_spin_lock_irqsave(&global_trace.start_lock, flags);
> +	if (--global_trace.stop_count) {
> +		if (global_trace.stop_count < 0) {
>  			/* Someone screwed up their debugging */
>  			WARN_ON_ONCE(1);
> -			trace_stop_count = 0;
> +			global_trace.stop_count = 0;
>  		}
>  		goto out;
>  	}
> @@ -1040,19 +1202,52 @@ void tracing_start(void)
>  	/* Prevent the buffers from switching */
>  	arch_spin_lock(&ftrace_max_lock);
>  
> -	buffer = global_trace.buffer;
> +	buffer = global_trace.trace_buffer.buffer;
>  	if (buffer)
>  		ring_buffer_record_enable(buffer);
>  
> -	buffer = max_tr.buffer;
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	buffer = global_trace.max_buffer.buffer;
>  	if (buffer)
>  		ring_buffer_record_enable(buffer);
> +#endif
>  
>  	arch_spin_unlock(&ftrace_max_lock);
>  
>  	ftrace_start();
>   out:
> -	raw_spin_unlock_irqrestore(&tracing_start_lock, flags);
> +	raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);
> +}
> +
> +static void tracing_start_tr(struct trace_array *tr)
> +{
> +	struct ring_buffer *buffer;
> +	unsigned long flags;
> +
> +	if (tracing_disabled)
> +		return;
> +
> +	/* If global, we need to also start the max tracer */
> +	if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
> +		return tracing_start();
> +
> +	raw_spin_lock_irqsave(&tr->start_lock, flags);
> +
> +	if (--tr->stop_count) {
> +		if (tr->stop_count < 0) {
> +			/* Someone screwed up their debugging */
> +			WARN_ON_ONCE(1);
> +			tr->stop_count = 0;
> +		}
> +		goto out;
> +	}
> +
> +	buffer = tr->trace_buffer.buffer;
> +	if (buffer)
> +		ring_buffer_record_enable(buffer);
> +
> + out:
> +	raw_spin_unlock_irqrestore(&tr->start_lock, flags);
>  }
>  
>  /**
> @@ -1067,25 +1262,48 @@ void tracing_stop(void)
>  	unsigned long flags;
>  
>  	ftrace_stop();
> -	raw_spin_lock_irqsave(&tracing_start_lock, flags);
> -	if (trace_stop_count++)
> +	raw_spin_lock_irqsave(&global_trace.start_lock, flags);
> +	if (global_trace.stop_count++)
>  		goto out;
>  
>  	/* Prevent the buffers from switching */
>  	arch_spin_lock(&ftrace_max_lock);
>  
> -	buffer = global_trace.buffer;
> +	buffer = global_trace.trace_buffer.buffer;
>  	if (buffer)
>  		ring_buffer_record_disable(buffer);
>  
> -	buffer = max_tr.buffer;
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	buffer = global_trace.max_buffer.buffer;
>  	if (buffer)
>  		ring_buffer_record_disable(buffer);
> +#endif
>  
>  	arch_spin_unlock(&ftrace_max_lock);
>  
>   out:
> -	raw_spin_unlock_irqrestore(&tracing_start_lock, flags);
> +	raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);
> +}
> +
> +static void tracing_stop_tr(struct trace_array *tr)
> +{
> +	struct ring_buffer *buffer;
> +	unsigned long flags;
> +
> +	/* If global, we need to also stop the max tracer */
> +	if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
> +		return tracing_stop();
> +
> +	raw_spin_lock_irqsave(&tr->start_lock, flags);
> +	if (tr->stop_count++)
> +		goto out;
> +
> +	buffer = tr->trace_buffer.buffer;
> +	if (buffer)
> +		ring_buffer_record_disable(buffer);
> +
> + out:
> +	raw_spin_unlock_irqrestore(&tr->start_lock, flags);
>  }
>  
>  void trace_stop_cmdline_recording(void);
> @@ -1218,11 +1436,6 @@ void
>  __buffer_unlock_commit(struct ring_buffer *buffer, struct ring_buffer_event *event)
>  {
>  	__this_cpu_write(trace_cmdline_save, true);
> -	if (trace_wakeup_needed) {
> -		trace_wakeup_needed = false;
> -		/* irq_work_queue() supplies it's own memory barriers */
> -		irq_work_queue(&trace_work_wakeup);
> -	}
>  	ring_buffer_unlock_commit(buffer, event);
>  }
>  
> @@ -1246,11 +1459,23 @@ void trace_buffer_unlock_commit(struct ring_buffer *buffer,
>  EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
>  
>  struct ring_buffer_event *
> +trace_event_buffer_lock_reserve(struct ring_buffer **current_rb,
> +			  struct ftrace_event_file *ftrace_file,
> +			  int type, unsigned long len,
> +			  unsigned long flags, int pc)
> +{
> +	*current_rb = ftrace_file->tr->trace_buffer.buffer;
> +	return trace_buffer_lock_reserve(*current_rb,
> +					 type, len, flags, pc);
> +}
> +EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve);
> +
> +struct ring_buffer_event *
>  trace_current_buffer_lock_reserve(struct ring_buffer **current_rb,
>  				  int type, unsigned long len,
>  				  unsigned long flags, int pc)
>  {
> -	*current_rb = global_trace.buffer;
> +	*current_rb = global_trace.trace_buffer.buffer;
>  	return trace_buffer_lock_reserve(*current_rb,
>  					 type, len, flags, pc);
>  }
> @@ -1289,7 +1514,7 @@ trace_function(struct trace_array *tr,
>  	       int pc)
>  {
>  	struct ftrace_event_call *call = &event_function;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  	struct ring_buffer_event *event;
>  	struct ftrace_entry *entry;
>  
> @@ -1430,13 +1655,14 @@ void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags,
>  void __trace_stack(struct trace_array *tr, unsigned long flags, int skip,
>  		   int pc)
>  {
> -	__ftrace_trace_stack(tr->buffer, flags, skip, pc, NULL);
> +	__ftrace_trace_stack(tr->trace_buffer.buffer, flags, skip, pc, NULL);
>  }
>  
>  /**
>   * trace_dump_stack - record a stack back trace in the trace buffer
> + * @skip: Number of functions to skip (helper handlers)
>   */
> -void trace_dump_stack(void)
> +void trace_dump_stack(int skip)
>  {
>  	unsigned long flags;
>  
> @@ -1445,8 +1671,13 @@ void trace_dump_stack(void)
>  
>  	local_save_flags(flags);
>  
> -	/* skipping 3 traces, seems to get us at the caller of this function */
> -	__ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count(), NULL);
> +	/*
> +	 * Skip 3 more, seems to get us at the caller of
> +	 * this function.
> +	 */
> +	skip += 3;
> +	__ftrace_trace_stack(global_trace.trace_buffer.buffer,
> +			     flags, skip, preempt_count(), NULL);
>  }
>  
>  static DEFINE_PER_CPU(int, user_stack_count);
> @@ -1616,7 +1847,7 @@ void trace_printk_init_buffers(void)
>  	 * directly here. If the global_trace.buffer is already
>  	 * allocated here, then this was called by module code.
>  	 */
> -	if (global_trace.buffer)
> +	if (global_trace.trace_buffer.buffer)
>  		tracing_start_cmdline_record();
>  }
>  
> @@ -1676,7 +1907,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
>  
>  	local_save_flags(flags);
>  	size = sizeof(*entry) + sizeof(u32) * len;
> -	buffer = tr->buffer;
> +	buffer = tr->trace_buffer.buffer;
>  	event = trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size,
>  					  flags, pc);
>  	if (!event)
> @@ -1699,27 +1930,12 @@ out:
>  }
>  EXPORT_SYMBOL_GPL(trace_vbprintk);
>  
> -int trace_array_printk(struct trace_array *tr,
> -		       unsigned long ip, const char *fmt, ...)
> -{
> -	int ret;
> -	va_list ap;
> -
> -	if (!(trace_flags & TRACE_ITER_PRINTK))
> -		return 0;
> -
> -	va_start(ap, fmt);
> -	ret = trace_array_vprintk(tr, ip, fmt, ap);
> -	va_end(ap);
> -	return ret;
> -}
> -
> -int trace_array_vprintk(struct trace_array *tr,
> -			unsigned long ip, const char *fmt, va_list args)
> +static int
> +__trace_array_vprintk(struct ring_buffer *buffer,
> +		      unsigned long ip, const char *fmt, va_list args)
>  {
>  	struct ftrace_event_call *call = &event_print;
>  	struct ring_buffer_event *event;
> -	struct ring_buffer *buffer;
>  	int len = 0, size, pc;
>  	struct print_entry *entry;
>  	unsigned long flags;
> @@ -1747,7 +1963,6 @@ int trace_array_vprintk(struct trace_array *tr,
>  
>  	local_save_flags(flags);
>  	size = sizeof(*entry) + len + 1;
> -	buffer = tr->buffer;
>  	event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
>  					  flags, pc);
>  	if (!event)
> @@ -1768,8 +1983,44 @@ int trace_array_vprintk(struct trace_array *tr,
>  	return len;
>  }
>  
> -int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
> -{
> +int trace_array_vprintk(struct trace_array *tr,
> +			unsigned long ip, const char *fmt, va_list args)
> +{
> +	return __trace_array_vprintk(tr->trace_buffer.buffer, ip, fmt, args);
> +}
> +
> +int trace_array_printk(struct trace_array *tr,
> +		       unsigned long ip, const char *fmt, ...)
> +{
> +	int ret;
> +	va_list ap;
> +
> +	if (!(trace_flags & TRACE_ITER_PRINTK))
> +		return 0;
> +
> +	va_start(ap, fmt);
> +	ret = trace_array_vprintk(tr, ip, fmt, ap);
> +	va_end(ap);
> +	return ret;
> +}
> +
> +int trace_array_printk_buf(struct ring_buffer *buffer,
> +			   unsigned long ip, const char *fmt, ...)
> +{
> +	int ret;
> +	va_list ap;
> +
> +	if (!(trace_flags & TRACE_ITER_PRINTK))
> +		return 0;
> +
> +	va_start(ap, fmt);
> +	ret = __trace_array_vprintk(buffer, ip, fmt, ap);
> +	va_end(ap);
> +	return ret;
> +}
> +
> +int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
> +{
>  	return trace_array_vprintk(&global_trace, ip, fmt, args);
>  }
>  EXPORT_SYMBOL_GPL(trace_vprintk);
> @@ -1793,7 +2044,7 @@ peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts,
>  	if (buf_iter)
>  		event = ring_buffer_iter_peek(buf_iter, ts);
>  	else
> -		event = ring_buffer_peek(iter->tr->buffer, cpu, ts,
> +		event = ring_buffer_peek(iter->trace_buffer->buffer, cpu, ts,
>  					 lost_events);
>  
>  	if (event) {
> @@ -1808,7 +2059,7 @@ static struct trace_entry *
>  __find_next_entry(struct trace_iterator *iter, int *ent_cpu,
>  		  unsigned long *missing_events, u64 *ent_ts)
>  {
> -	struct ring_buffer *buffer = iter->tr->buffer;
> +	struct ring_buffer *buffer = iter->trace_buffer->buffer;
>  	struct trace_entry *ent, *next = NULL;
>  	unsigned long lost_events = 0, next_lost = 0;
>  	int cpu_file = iter->cpu_file;
> @@ -1821,7 +2072,7 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu,
>  	 * If we are in a per_cpu trace file, don't bother by iterating over
>  	 * all cpu and peek directly.
>  	 */
> -	if (cpu_file > TRACE_PIPE_ALL_CPU) {
> +	if (cpu_file > RING_BUFFER_ALL_CPUS) {
>  		if (ring_buffer_empty_cpu(buffer, cpu_file))
>  			return NULL;
>  		ent = peek_next_entry(iter, cpu_file, ent_ts, missing_events);
> @@ -1885,7 +2136,7 @@ void *trace_find_next_entry_inc(struct trace_iterator *iter)
>  
>  static void trace_consume(struct trace_iterator *iter)
>  {
> -	ring_buffer_consume(iter->tr->buffer, iter->cpu, &iter->ts,
> +	ring_buffer_consume(iter->trace_buffer->buffer, iter->cpu, &iter->ts,
>  			    &iter->lost_events);
>  }
>  
> @@ -1918,13 +2169,12 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos)
>  
>  void tracing_iter_reset(struct trace_iterator *iter, int cpu)
>  {
> -	struct trace_array *tr = iter->tr;
>  	struct ring_buffer_event *event;
>  	struct ring_buffer_iter *buf_iter;
>  	unsigned long entries = 0;
>  	u64 ts;
>  
> -	tr->data[cpu]->skipped_entries = 0;
> +	per_cpu_ptr(iter->trace_buffer->data, cpu)->skipped_entries = 0;
>  
>  	buf_iter = trace_buffer_iter(iter, cpu);
>  	if (!buf_iter)
> @@ -1938,13 +2188,13 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
>  	 * by the timestamp being before the start of the buffer.
>  	 */
>  	while ((event = ring_buffer_iter_peek(buf_iter, &ts))) {
> -		if (ts >= iter->tr->time_start)
> +		if (ts >= iter->trace_buffer->time_start)
>  			break;
>  		entries++;
>  		ring_buffer_read(buf_iter, NULL);
>  	}
>  
> -	tr->data[cpu]->skipped_entries = entries;
> +	per_cpu_ptr(iter->trace_buffer->data, cpu)->skipped_entries = entries;
>  }
>  
>  /*
> @@ -1954,6 +2204,7 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
>  static void *s_start(struct seq_file *m, loff_t *pos)
>  {
>  	struct trace_iterator *iter = m->private;
> +	struct trace_array *tr = iter->tr;
>  	int cpu_file = iter->cpu_file;
>  	void *p = NULL;
>  	loff_t l = 0;
> @@ -1966,12 +2217,14 @@ static void *s_start(struct seq_file *m, loff_t *pos)
>  	 * will point to the same string as current_trace->name.
>  	 */
>  	mutex_lock(&trace_types_lock);
> -	if (unlikely(current_trace && iter->trace->name != current_trace->name))
> -		*iter->trace = *current_trace;
> +	if (unlikely(tr->current_trace && iter->trace->name != tr->current_trace->name))
> +		*iter->trace = *tr->current_trace;
>  	mutex_unlock(&trace_types_lock);
>  
> +#ifdef CONFIG_TRACER_MAX_TRACE
>  	if (iter->snapshot && iter->trace->use_max_tr)
>  		return ERR_PTR(-EBUSY);
> +#endif
>  
>  	if (!iter->snapshot)
>  		atomic_inc(&trace_record_cmdline_disabled);
> @@ -1981,7 +2234,7 @@ static void *s_start(struct seq_file *m, loff_t *pos)
>  		iter->cpu = 0;
>  		iter->idx = -1;
>  
> -		if (cpu_file == TRACE_PIPE_ALL_CPU) {
> +		if (cpu_file == RING_BUFFER_ALL_CPUS) {
>  			for_each_tracing_cpu(cpu)
>  				tracing_iter_reset(iter, cpu);
>  		} else
> @@ -2013,17 +2266,21 @@ static void s_stop(struct seq_file *m, void *p)
>  {
>  	struct trace_iterator *iter = m->private;
>  
> +#ifdef CONFIG_TRACER_MAX_TRACE
>  	if (iter->snapshot && iter->trace->use_max_tr)
>  		return;
> +#endif
>  
>  	if (!iter->snapshot)
>  		atomic_dec(&trace_record_cmdline_disabled);
> +
>  	trace_access_unlock(iter->cpu_file);
>  	trace_event_read_unlock();
>  }
>  
>  static void
> -get_total_entries(struct trace_array *tr, unsigned long *total, unsigned long *entries)
> +get_total_entries(struct trace_buffer *buf,
> +		  unsigned long *total, unsigned long *entries)
>  {
>  	unsigned long count;
>  	int cpu;
> @@ -2032,19 +2289,19 @@ get_total_entries(struct trace_array *tr, unsigned long *total, unsigned long *e
>  	*entries = 0;
>  
>  	for_each_tracing_cpu(cpu) {
> -		count = ring_buffer_entries_cpu(tr->buffer, cpu);
> +		count = ring_buffer_entries_cpu(buf->buffer, cpu);
>  		/*
>  		 * If this buffer has skipped entries, then we hold all
>  		 * entries for the trace and we need to ignore the
>  		 * ones before the time stamp.
>  		 */
> -		if (tr->data[cpu]->skipped_entries) {
> -			count -= tr->data[cpu]->skipped_entries;
> +		if (per_cpu_ptr(buf->data, cpu)->skipped_entries) {
> +			count -= per_cpu_ptr(buf->data, cpu)->skipped_entries;
>  			/* total is the same as the entries */
>  			*total += count;
>  		} else
>  			*total += count +
> -				ring_buffer_overrun_cpu(tr->buffer, cpu);
> +				ring_buffer_overrun_cpu(buf->buffer, cpu);
>  		*entries += count;
>  	}
>  }
> @@ -2061,27 +2318,27 @@ static void print_lat_help_header(struct seq_file *m)
>  	seq_puts(m, "#     \\   /      |||||  \\    |   /           \n");
>  }
>  
> -static void print_event_info(struct trace_array *tr, struct seq_file *m)
> +static void print_event_info(struct trace_buffer *buf, struct seq_file *m)
>  {
>  	unsigned long total;
>  	unsigned long entries;
>  
> -	get_total_entries(tr, &total, &entries);
> +	get_total_entries(buf, &total, &entries);
>  	seq_printf(m, "# entries-in-buffer/entries-written: %lu/%lu   #P:%d\n",
>  		   entries, total, num_online_cpus());
>  	seq_puts(m, "#\n");
>  }
>  
> -static void print_func_help_header(struct trace_array *tr, struct seq_file *m)
> +static void print_func_help_header(struct trace_buffer *buf, struct seq_file *m)
>  {
> -	print_event_info(tr, m);
> +	print_event_info(buf, m);
>  	seq_puts(m, "#           TASK-PID   CPU#      TIMESTAMP  FUNCTION\n");
>  	seq_puts(m, "#              | |       |          |         |\n");
>  }
>  
> -static void print_func_help_header_irq(struct trace_array *tr, struct seq_file *m)
> +static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file *m)
>  {
> -	print_event_info(tr, m);
> +	print_event_info(buf, m);
>  	seq_puts(m, "#                              _-----=> irqs-off\n");
>  	seq_puts(m, "#                             / _----=> need-resched\n");
>  	seq_puts(m, "#                            | / _---=> hardirq/softirq\n");
> @@ -2095,16 +2352,16 @@ void
>  print_trace_header(struct seq_file *m, struct trace_iterator *iter)
>  {
>  	unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
> -	struct trace_array *tr = iter->tr;
> -	struct trace_array_cpu *data = tr->data[tr->cpu];
> -	struct tracer *type = current_trace;
> +	struct trace_buffer *buf = iter->trace_buffer;
> +	struct trace_array_cpu *data = per_cpu_ptr(buf->data, buf->cpu);
> +	struct tracer *type = iter->trace;
>  	unsigned long entries;
>  	unsigned long total;
>  	const char *name = "preemption";
>  
>  	name = type->name;
>  
> -	get_total_entries(tr, &total, &entries);
> +	get_total_entries(buf, &total, &entries);
>  
>  	seq_printf(m, "# %s latency trace v1.1.5 on %s\n",
>  		   name, UTS_RELEASE);
> @@ -2115,7 +2372,7 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
>  		   nsecs_to_usecs(data->saved_latency),
>  		   entries,
>  		   total,
> -		   tr->cpu,
> +		   buf->cpu,
>  #if defined(CONFIG_PREEMPT_NONE)
>  		   "server",
>  #elif defined(CONFIG_PREEMPT_VOLUNTARY)
> @@ -2166,7 +2423,7 @@ static void test_cpu_buff_start(struct trace_iterator *iter)
>  	if (cpumask_test_cpu(iter->cpu, iter->started))
>  		return;
>  
> -	if (iter->tr->data[iter->cpu]->skipped_entries)
> +	if (per_cpu_ptr(iter->trace_buffer->data, iter->cpu)->skipped_entries)
>  		return;
>  
>  	cpumask_set_cpu(iter->cpu, iter->started);
> @@ -2289,14 +2546,14 @@ int trace_empty(struct trace_iterator *iter)
>  	int cpu;
>  
>  	/* If we are looking at one CPU buffer, only check that one */
> -	if (iter->cpu_file != TRACE_PIPE_ALL_CPU) {
> +	if (iter->cpu_file != RING_BUFFER_ALL_CPUS) {
>  		cpu = iter->cpu_file;
>  		buf_iter = trace_buffer_iter(iter, cpu);
>  		if (buf_iter) {
>  			if (!ring_buffer_iter_empty(buf_iter))
>  				return 0;
>  		} else {
> -			if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu))
> +			if (!ring_buffer_empty_cpu(iter->trace_buffer->buffer, cpu))
>  				return 0;
>  		}
>  		return 1;
> @@ -2308,7 +2565,7 @@ int trace_empty(struct trace_iterator *iter)
>  			if (!ring_buffer_iter_empty(buf_iter))
>  				return 0;
>  		} else {
> -			if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu))
> +			if (!ring_buffer_empty_cpu(iter->trace_buffer->buffer, cpu))
>  				return 0;
>  		}
>  	}
> @@ -2332,6 +2589,11 @@ enum print_line_t print_trace_line(struct trace_iterator *iter)
>  			return ret;
>  	}
>  
> +	if (iter->ent->type == TRACE_BPUTS &&
> +			trace_flags & TRACE_ITER_PRINTK &&
> +			trace_flags & TRACE_ITER_PRINTK_MSGONLY)
> +		return trace_print_bputs_msg_only(iter);
> +
>  	if (iter->ent->type == TRACE_BPRINT &&
>  			trace_flags & TRACE_ITER_PRINTK &&
>  			trace_flags & TRACE_ITER_PRINTK_MSGONLY)
> @@ -2386,9 +2648,9 @@ void trace_default_header(struct seq_file *m)
>  	} else {
>  		if (!(trace_flags & TRACE_ITER_VERBOSE)) {
>  			if (trace_flags & TRACE_ITER_IRQ_INFO)
> -				print_func_help_header_irq(iter->tr, m);
> +				print_func_help_header_irq(iter->trace_buffer, m);
>  			else
> -				print_func_help_header(iter->tr, m);
> +				print_func_help_header(iter->trace_buffer, m);
>  		}
>  	}
>  }
> @@ -2402,14 +2664,8 @@ static void test_ftrace_alive(struct seq_file *m)
>  }
>  
>  #ifdef CONFIG_TRACER_MAX_TRACE
> -static void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter)
> +static void show_snapshot_main_help(struct seq_file *m)
>  {
> -	if (iter->trace->allocated_snapshot)
> -		seq_printf(m, "#\n# * Snapshot is allocated *\n#\n");
> -	else
> -		seq_printf(m, "#\n# * Snapshot is freed *\n#\n");
> -
> -	seq_printf(m, "# Snapshot commands:\n");
>  	seq_printf(m, "# echo 0 > snapshot : Clears and frees snapshot buffer\n");
>  	seq_printf(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n");
>  	seq_printf(m, "#                      Takes a snapshot of the main buffer.\n");
> @@ -2417,6 +2673,35 @@ static void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter)
>  	seq_printf(m, "#                      (Doesn't have to be '2' works with any number that\n");
>  	seq_printf(m, "#                       is not a '0' or '1')\n");
>  }
> +
> +static void show_snapshot_percpu_help(struct seq_file *m)
> +{
> +	seq_printf(m, "# echo 0 > snapshot : Invalid for per_cpu snapshot file.\n");
> +#ifdef CONFIG_RING_BUFFER_ALLOW_SWAP
> +	seq_printf(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n");
> +	seq_printf(m, "#                      Takes a snapshot of the main buffer for this cpu.\n");
> +#else
> +	seq_printf(m, "# echo 1 > snapshot : Not supported with this kernel.\n");
> +	seq_printf(m, "#                     Must use main snapshot file to allocate.\n");
> +#endif
> +	seq_printf(m, "# echo 2 > snapshot : Clears this cpu's snapshot buffer (but does not allocate)\n");
> +	seq_printf(m, "#                      (Doesn't have to be '2' works with any number that\n");
> +	seq_printf(m, "#                       is not a '0' or '1')\n");
> +}
> +
> +static void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter)
> +{
> +	if (iter->tr->allocated_snapshot)
> +		seq_printf(m, "#\n# * Snapshot is allocated *\n#\n");
> +	else
> +		seq_printf(m, "#\n# * Snapshot is freed *\n#\n");
> +
> +	seq_printf(m, "# Snapshot commands:\n");
> +	if (iter->cpu_file == RING_BUFFER_ALL_CPUS)
> +		show_snapshot_main_help(m);
> +	else
> +		show_snapshot_percpu_help(m);
> +}
>  #else
>  /* Should never be called */
>  static inline void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter) { }
> @@ -2476,7 +2761,8 @@ static const struct seq_operations tracer_seq_ops = {
>  static struct trace_iterator *
>  __tracing_open(struct inode *inode, struct file *file, bool snapshot)
>  {
> -	long cpu_file = (long) inode->i_private;
> +	struct trace_cpu *tc = inode->i_private;
> +	struct trace_array *tr = tc->tr;
>  	struct trace_iterator *iter;
>  	int cpu;
>  
> @@ -2501,26 +2787,31 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
>  	if (!iter->trace)
>  		goto fail;
>  
> -	*iter->trace = *current_trace;
> +	*iter->trace = *tr->current_trace;
>  
>  	if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL))
>  		goto fail;
>  
> -	if (current_trace->print_max || snapshot)
> -		iter->tr = &max_tr;
> +	iter->tr = tr;
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	/* Currently only the top directory has a snapshot */
> +	if (tr->current_trace->print_max || snapshot)
> +		iter->trace_buffer = &tr->max_buffer;
>  	else
> -		iter->tr = &global_trace;
> +#endif
> +		iter->trace_buffer = &tr->trace_buffer;
>  	iter->snapshot = snapshot;
>  	iter->pos = -1;
>  	mutex_init(&iter->mutex);
> -	iter->cpu_file = cpu_file;
> +	iter->cpu_file = tc->cpu;
>  
>  	/* Notify the tracer early; before we stop tracing. */
>  	if (iter->trace && iter->trace->open)
>  		iter->trace->open(iter);
>  
>  	/* Annotate start of buffers if we had overruns */
> -	if (ring_buffer_overruns(iter->tr->buffer))
> +	if (ring_buffer_overruns(iter->trace_buffer->buffer))
>  		iter->iter_flags |= TRACE_FILE_ANNOTATE;
>  
>  	/* Output in nanoseconds only if we are using a clock in nanoseconds. */
> @@ -2529,12 +2820,12 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
>  
>  	/* stop the trace while dumping if we are not opening "snapshot" */
>  	if (!iter->snapshot)
> -		tracing_stop();
> +		tracing_stop_tr(tr);
>  
> -	if (iter->cpu_file == TRACE_PIPE_ALL_CPU) {
> +	if (iter->cpu_file == RING_BUFFER_ALL_CPUS) {
>  		for_each_tracing_cpu(cpu) {
>  			iter->buffer_iter[cpu] =
> -				ring_buffer_read_prepare(iter->tr->buffer, cpu);
> +				ring_buffer_read_prepare(iter->trace_buffer->buffer, cpu);
>  		}
>  		ring_buffer_read_prepare_sync();
>  		for_each_tracing_cpu(cpu) {
> @@ -2544,12 +2835,14 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
>  	} else {
>  		cpu = iter->cpu_file;
>  		iter->buffer_iter[cpu] =
> -			ring_buffer_read_prepare(iter->tr->buffer, cpu);
> +			ring_buffer_read_prepare(iter->trace_buffer->buffer, cpu);
>  		ring_buffer_read_prepare_sync();
>  		ring_buffer_read_start(iter->buffer_iter[cpu]);
>  		tracing_iter_reset(iter, cpu);
>  	}
>  
> +	tr->ref++;
> +
>  	mutex_unlock(&trace_types_lock);
>  
>  	return iter;
> @@ -2576,14 +2869,20 @@ static int tracing_release(struct inode *inode, struct file *file)
>  {
>  	struct seq_file *m = file->private_data;
>  	struct trace_iterator *iter;
> +	struct trace_array *tr;
>  	int cpu;
>  
>  	if (!(file->f_mode & FMODE_READ))
>  		return 0;
>  
>  	iter = m->private;
> +	tr = iter->tr;
>  
>  	mutex_lock(&trace_types_lock);
> +
> +	WARN_ON(!tr->ref);
> +	tr->ref--;
> +
>  	for_each_tracing_cpu(cpu) {
>  		if (iter->buffer_iter[cpu])
>  			ring_buffer_read_finish(iter->buffer_iter[cpu]);
> @@ -2594,7 +2893,7 @@ static int tracing_release(struct inode *inode, struct file *file)
>  
>  	if (!iter->snapshot)
>  		/* reenable tracing if it was previously enabled */
> -		tracing_start();
> +		tracing_start_tr(tr);
>  	mutex_unlock(&trace_types_lock);
>  
>  	mutex_destroy(&iter->mutex);
> @@ -2613,12 +2912,13 @@ static int tracing_open(struct inode *inode, struct file *file)
>  	/* If this file was open for write, then erase contents */
>  	if ((file->f_mode & FMODE_WRITE) &&
>  	    (file->f_flags & O_TRUNC)) {
> -		long cpu = (long) inode->i_private;
> +		struct trace_cpu *tc = inode->i_private;
> +		struct trace_array *tr = tc->tr;
>  
> -		if (cpu == TRACE_PIPE_ALL_CPU)
> -			tracing_reset_online_cpus(&global_trace);
> +		if (tc->cpu == RING_BUFFER_ALL_CPUS)
> +			tracing_reset_online_cpus(&tr->trace_buffer);
>  		else
> -			tracing_reset(&global_trace, cpu);
> +			tracing_reset(&tr->trace_buffer, tc->cpu);
>  	}
>  
>  	if (file->f_mode & FMODE_READ) {
> @@ -2765,8 +3065,9 @@ static ssize_t
>  tracing_cpumask_write(struct file *filp, const char __user *ubuf,
>  		      size_t count, loff_t *ppos)
>  {
> -	int err, cpu;
> +	struct trace_array *tr = filp->private_data;
>  	cpumask_var_t tracing_cpumask_new;
> +	int err, cpu;
>  
>  	if (!alloc_cpumask_var(&tracing_cpumask_new, GFP_KERNEL))
>  		return -ENOMEM;
> @@ -2786,13 +3087,13 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
>  		 */
>  		if (cpumask_test_cpu(cpu, tracing_cpumask) &&
>  				!cpumask_test_cpu(cpu, tracing_cpumask_new)) {
> -			atomic_inc(&global_trace.data[cpu]->disabled);
> -			ring_buffer_record_disable_cpu(global_trace.buffer, cpu);
> +			atomic_inc(&per_cpu_ptr(tr->trace_buffer.data, cpu)->disabled);
> +			ring_buffer_record_disable_cpu(tr->trace_buffer.buffer, cpu);
>  		}
>  		if (!cpumask_test_cpu(cpu, tracing_cpumask) &&
>  				cpumask_test_cpu(cpu, tracing_cpumask_new)) {
> -			atomic_dec(&global_trace.data[cpu]->disabled);
> -			ring_buffer_record_enable_cpu(global_trace.buffer, cpu);
> +			atomic_dec(&per_cpu_ptr(tr->trace_buffer.data, cpu)->disabled);
> +			ring_buffer_record_enable_cpu(tr->trace_buffer.buffer, cpu);
>  		}
>  	}
>  	arch_spin_unlock(&ftrace_max_lock);
> @@ -2821,12 +3122,13 @@ static const struct file_operations tracing_cpumask_fops = {
>  static int tracing_trace_options_show(struct seq_file *m, void *v)
>  {
>  	struct tracer_opt *trace_opts;
> +	struct trace_array *tr = m->private;
>  	u32 tracer_flags;
>  	int i;
>  
>  	mutex_lock(&trace_types_lock);
> -	tracer_flags = current_trace->flags->val;
> -	trace_opts = current_trace->flags->opts;
> +	tracer_flags = tr->current_trace->flags->val;
> +	trace_opts = tr->current_trace->flags->opts;
>  
>  	for (i = 0; trace_options[i]; i++) {
>  		if (trace_flags & (1 << i))
> @@ -2890,15 +3192,15 @@ int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
>  	return 0;
>  }
>  
> -int set_tracer_flag(unsigned int mask, int enabled)
> +int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
>  {
>  	/* do nothing if flag is already set */
>  	if (!!(trace_flags & mask) == !!enabled)
>  		return 0;
>  
>  	/* Give the tracer a chance to approve the change */
> -	if (current_trace->flag_changed)
> -		if (current_trace->flag_changed(current_trace, mask, !!enabled))
> +	if (tr->current_trace->flag_changed)
> +		if (tr->current_trace->flag_changed(tr->current_trace, mask, !!enabled))
>  			return -EINVAL;
>  
>  	if (enabled)
> @@ -2910,9 +3212,9 @@ int set_tracer_flag(unsigned int mask, int enabled)
>  		trace_event_enable_cmd_record(enabled);
>  
>  	if (mask == TRACE_ITER_OVERWRITE) {
> -		ring_buffer_change_overwrite(global_trace.buffer, enabled);
> +		ring_buffer_change_overwrite(tr->trace_buffer.buffer, enabled);
>  #ifdef CONFIG_TRACER_MAX_TRACE
> -		ring_buffer_change_overwrite(max_tr.buffer, enabled);
> +		ring_buffer_change_overwrite(tr->max_buffer.buffer, enabled);
>  #endif
>  	}
>  
> @@ -2922,7 +3224,7 @@ int set_tracer_flag(unsigned int mask, int enabled)
>  	return 0;
>  }
>  
> -static int trace_set_options(char *option)
> +static int trace_set_options(struct trace_array *tr, char *option)
>  {
>  	char *cmp;
>  	int neg = 0;
> @@ -2940,14 +3242,14 @@ static int trace_set_options(char *option)
>  
>  	for (i = 0; trace_options[i]; i++) {
>  		if (strcmp(cmp, trace_options[i]) == 0) {
> -			ret = set_tracer_flag(1 << i, !neg);
> +			ret = set_tracer_flag(tr, 1 << i, !neg);
>  			break;
>  		}
>  	}
>  
>  	/* If no option could be set, test the specific tracer options */
>  	if (!trace_options[i])
> -		ret = set_tracer_option(current_trace, cmp, neg);
> +		ret = set_tracer_option(tr->current_trace, cmp, neg);
>  
>  	mutex_unlock(&trace_types_lock);
>  
> @@ -2958,6 +3260,8 @@ static ssize_t
>  tracing_trace_options_write(struct file *filp, const char __user *ubuf,
>  			size_t cnt, loff_t *ppos)
>  {
> +	struct seq_file *m = filp->private_data;
> +	struct trace_array *tr = m->private;
>  	char buf[64];
>  	int ret;
>  
> @@ -2969,7 +3273,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
>  
>  	buf[cnt] = 0;
>  
> -	ret = trace_set_options(buf);
> +	ret = trace_set_options(tr, buf);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -2982,7 +3286,8 @@ static int tracing_trace_options_open(struct inode *inode, struct file *file)
>  {
>  	if (tracing_disabled)
>  		return -ENODEV;
> -	return single_open(file, tracing_trace_options_show, NULL);
> +
> +	return single_open(file, tracing_trace_options_show, inode->i_private);
>  }
>  
>  static const struct file_operations tracing_iter_fops = {
> @@ -2995,20 +3300,84 @@ static const struct file_operations tracing_iter_fops = {
>  
>  static const char readme_msg[] =
>  	"tracing mini-HOWTO:\n\n"
> -	"# mount -t debugfs nodev /sys/kernel/debug\n\n"
> -	"# cat /sys/kernel/debug/tracing/available_tracers\n"
> -	"wakeup wakeup_rt preemptirqsoff preemptoff irqsoff function nop\n\n"
> -	"# cat /sys/kernel/debug/tracing/current_tracer\n"
> -	"nop\n"
> -	"# echo wakeup > /sys/kernel/debug/tracing/current_tracer\n"
> -	"# cat /sys/kernel/debug/tracing/current_tracer\n"
> -	"wakeup\n"
> -	"# cat /sys/kernel/debug/tracing/trace_options\n"
> -	"noprint-parent nosym-offset nosym-addr noverbose\n"
> -	"# echo print-parent > /sys/kernel/debug/tracing/trace_options\n"
> -	"# echo 1 > /sys/kernel/debug/tracing/tracing_on\n"
> -	"# cat /sys/kernel/debug/tracing/trace > /tmp/trace.txt\n"
> -	"# echo 0 > /sys/kernel/debug/tracing/tracing_on\n"
> +	"# echo 0 > tracing_on : quick way to disable tracing\n"
> +	"# echo 1 > tracing_on : quick way to re-enable tracing\n\n"
> +	" Important files:\n"
> +	"  trace\t\t\t- The static contents of the buffer\n"
> +	"\t\t\t  To clear the buffer write into this file: echo > trace\n"
> +	"  trace_pipe\t\t- A consuming read to see the contents of the buffer\n"
> +	"  current_tracer\t- function and latency tracers\n"
> +	"  available_tracers\t- list of configured tracers for current_tracer\n"
> +	"  buffer_size_kb\t- view and modify size of per cpu buffer\n"
> +	"  buffer_total_size_kb  - view total size of all cpu buffers\n\n"
> +	"  trace_clock\t\t-change the clock used to order events\n"
> +	"       local:   Per cpu clock but may not be synced across CPUs\n"
> +	"      global:   Synced across CPUs but slows tracing down.\n"
> +	"     counter:   Not a clock, but just an increment\n"
> +	"      uptime:   Jiffy counter from time of boot\n"
> +	"        perf:   Same clock that perf events use\n"
> +#ifdef CONFIG_X86_64
> +	"     x86-tsc:   TSC cycle counter\n"
> +#endif
> +	"\n  trace_marker\t\t- Writes into this file writes into the kernel buffer\n"
> +	"  tracing_cpumask\t- Limit which CPUs to trace\n"
> +	"  instances\t\t- Make sub-buffers with: mkdir instances/foo\n"
> +	"\t\t\t  Remove sub-buffer with rmdir\n"
> +	"  trace_options\t\t- Set format or modify how tracing happens\n"
> +	"\t\t\t  Disable an option by adding a suffix 'no' to the option name\n"
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +	"\n  available_filter_functions - list of functions that can be filtered on\n"
> +	"  set_ftrace_filter\t- echo function name in here to only trace these functions\n"
> +	"            accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
> +	"            modules: Can select a group via module\n"
> +	"             Format: :mod:<module-name>\n"
> +	"             example: echo :mod:ext3 > set_ftrace_filter\n"
> +	"            triggers: a command to perform when function is hit\n"
> +	"              Format: <function>:<trigger>[:count]\n"
> +	"             trigger: traceon, traceoff\n"
> +	"                      enable_event:<system>:<event>\n"
> +	"                      disable_event:<system>:<event>\n"
> +#ifdef CONFIG_STACKTRACE
> +	"                      stacktrace\n"
> +#endif
> +#ifdef CONFIG_TRACER_SNAPSHOT
> +	"                      snapshot\n"
> +#endif
> +	"             example: echo do_fault:traceoff > set_ftrace_filter\n"
> +	"                      echo do_trap:traceoff:3 > set_ftrace_filter\n"
> +	"             The first one will disable tracing every time do_fault is hit\n"
> +	"             The second will disable tracing at most 3 times when do_trap is hit\n"
> +	"               The first time do trap is hit and it disables tracing, the counter\n"
> +	"               will decrement to 2. If tracing is already disabled, the counter\n"
> +	"               will not decrement. It only decrements when the trigger did work\n"
> +	"             To remove trigger without count:\n"
> +	"               echo '!<function>:<trigger> > set_ftrace_filter\n"
> +	"             To remove trigger with a count:\n"
> +	"               echo '!<function>:<trigger>:0 > set_ftrace_filter\n"
> +	"  set_ftrace_notrace\t- echo function name in here to never trace.\n"
> +	"            accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
> +	"            modules: Can select a group via module command :mod:\n"
> +	"            Does not accept triggers\n"
> +#endif /* CONFIG_DYNAMIC_FTRACE */
> +#ifdef CONFIG_FUNCTION_TRACER
> +	"  set_ftrace_pid\t- Write pid(s) to only function trace those pids (function)\n"
> +#endif
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +	"  set_graph_function\t- Trace the nested calls of a function (function_graph)\n"
> +	"  max_graph_depth\t- Trace a limited depth of nested calls (0 is unlimited)\n"
> +#endif
> +#ifdef CONFIG_TRACER_SNAPSHOT
> +	"\n  snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n"
> +	"\t\t\t  Read the contents for more information\n"
> +#endif
> +#ifdef CONFIG_STACKTRACE
> +	"  stack_trace\t\t- Shows the max stack trace when active\n"
> +	"  stack_max_size\t- Shows current max stack size that was traced\n"
> +	"\t\t\t  Write into this file to reset the max size (trigger a new trace)\n"
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +	"  stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n"
> +#endif
> +#endif /* CONFIG_STACKTRACE */
>  ;
>  
>  static ssize_t
> @@ -3080,11 +3449,12 @@ static ssize_t
>  tracing_set_trace_read(struct file *filp, char __user *ubuf,
>  		       size_t cnt, loff_t *ppos)
>  {
> +	struct trace_array *tr = filp->private_data;
>  	char buf[MAX_TRACER_SIZE+2];
>  	int r;
>  
>  	mutex_lock(&trace_types_lock);
> -	r = sprintf(buf, "%s\n", current_trace->name);
> +	r = sprintf(buf, "%s\n", tr->current_trace->name);
>  	mutex_unlock(&trace_types_lock);
>  
>  	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
> @@ -3092,43 +3462,48 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,
>  
>  int tracer_init(struct tracer *t, struct trace_array *tr)
>  {
> -	tracing_reset_online_cpus(tr);
> +	tracing_reset_online_cpus(&tr->trace_buffer);
>  	return t->init(tr);
>  }
>  
> -static void set_buffer_entries(struct trace_array *tr, unsigned long val)
> +static void set_buffer_entries(struct trace_buffer *buf, unsigned long val)
>  {
>  	int cpu;
> +
>  	for_each_tracing_cpu(cpu)
> -		tr->data[cpu]->entries = val;
> +		per_cpu_ptr(buf->data, cpu)->entries = val;
>  }
>  
> +#ifdef CONFIG_TRACER_MAX_TRACE
>  /* resize @tr's buffer to the size of @size_tr's entries */
> -static int resize_buffer_duplicate_size(struct trace_array *tr,
> -					struct trace_array *size_tr, int cpu_id)
> +static int resize_buffer_duplicate_size(struct trace_buffer *trace_buf,
> +					struct trace_buffer *size_buf, int cpu_id)
>  {
>  	int cpu, ret = 0;
>  
>  	if (cpu_id == RING_BUFFER_ALL_CPUS) {
>  		for_each_tracing_cpu(cpu) {
> -			ret = ring_buffer_resize(tr->buffer,
> -					size_tr->data[cpu]->entries, cpu);
> +			ret = ring_buffer_resize(trace_buf->buffer,
> +				 per_cpu_ptr(size_buf->data, cpu)->entries, cpu);
>  			if (ret < 0)
>  				break;
> -			tr->data[cpu]->entries = size_tr->data[cpu]->entries;
> +			per_cpu_ptr(trace_buf->data, cpu)->entries =
> +				per_cpu_ptr(size_buf->data, cpu)->entries;
>  		}
>  	} else {
> -		ret = ring_buffer_resize(tr->buffer,
> -					size_tr->data[cpu_id]->entries, cpu_id);
> +		ret = ring_buffer_resize(trace_buf->buffer,
> +				 per_cpu_ptr(size_buf->data, cpu_id)->entries, cpu_id);
>  		if (ret == 0)
> -			tr->data[cpu_id]->entries =
> -				size_tr->data[cpu_id]->entries;
> +			per_cpu_ptr(trace_buf->data, cpu_id)->entries =
> +				per_cpu_ptr(size_buf->data, cpu_id)->entries;
>  	}
>  
>  	return ret;
>  }
> +#endif /* CONFIG_TRACER_MAX_TRACE */
>  
> -static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
> +static int __tracing_resize_ring_buffer(struct trace_array *tr,
> +					unsigned long size, int cpu)
>  {
>  	int ret;
>  
> @@ -3137,23 +3512,25 @@ static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
>  	 * we use the size that was given, and we can forget about
>  	 * expanding it later.
>  	 */
> -	ring_buffer_expanded = 1;
> +	ring_buffer_expanded = true;
>  
>  	/* May be called before buffers are initialized */
> -	if (!global_trace.buffer)
> +	if (!tr->trace_buffer.buffer)
>  		return 0;
>  
> -	ret = ring_buffer_resize(global_trace.buffer, size, cpu);
> +	ret = ring_buffer_resize(tr->trace_buffer.buffer, size, cpu);
>  	if (ret < 0)
>  		return ret;
>  
> -	if (!current_trace->use_max_tr)
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	if (!(tr->flags & TRACE_ARRAY_FL_GLOBAL) ||
> +	    !tr->current_trace->use_max_tr)
>  		goto out;
>  
> -	ret = ring_buffer_resize(max_tr.buffer, size, cpu);
> +	ret = ring_buffer_resize(tr->max_buffer.buffer, size, cpu);
>  	if (ret < 0) {
> -		int r = resize_buffer_duplicate_size(&global_trace,
> -						     &global_trace, cpu);
> +		int r = resize_buffer_duplicate_size(&tr->trace_buffer,
> +						     &tr->trace_buffer, cpu);
>  		if (r < 0) {
>  			/*
>  			 * AARGH! We are left with different
> @@ -3176,20 +3553,23 @@ static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
>  	}
>  
>  	if (cpu == RING_BUFFER_ALL_CPUS)
> -		set_buffer_entries(&max_tr, size);
> +		set_buffer_entries(&tr->max_buffer, size);
>  	else
> -		max_tr.data[cpu]->entries = size;
> +		per_cpu_ptr(tr->max_buffer.data, cpu)->entries = size;
>  
>   out:
> +#endif /* CONFIG_TRACER_MAX_TRACE */
> +
>  	if (cpu == RING_BUFFER_ALL_CPUS)
> -		set_buffer_entries(&global_trace, size);
> +		set_buffer_entries(&tr->trace_buffer, size);
>  	else
> -		global_trace.data[cpu]->entries = size;
> +		per_cpu_ptr(tr->trace_buffer.data, cpu)->entries = size;
>  
>  	return ret;
>  }
>  
> -static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
> +static ssize_t tracing_resize_ring_buffer(struct trace_array *tr,
> +					  unsigned long size, int cpu_id)
>  {
>  	int ret = size;
>  
> @@ -3203,7 +3583,7 @@ static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
>  		}
>  	}
>  
> -	ret = __tracing_resize_ring_buffer(size, cpu_id);
> +	ret = __tracing_resize_ring_buffer(tr, size, cpu_id);
>  	if (ret < 0)
>  		ret = -ENOMEM;
>  
> @@ -3230,7 +3610,7 @@ int tracing_update_buffers(void)
>  
>  	mutex_lock(&trace_types_lock);
>  	if (!ring_buffer_expanded)
> -		ret = __tracing_resize_ring_buffer(trace_buf_size,
> +		ret = __tracing_resize_ring_buffer(&global_trace, trace_buf_size,
>  						RING_BUFFER_ALL_CPUS);
>  	mutex_unlock(&trace_types_lock);
>  
> @@ -3240,7 +3620,7 @@ int tracing_update_buffers(void)
>  struct trace_option_dentry;
>  
>  static struct trace_option_dentry *
> -create_trace_option_files(struct tracer *tracer);
> +create_trace_option_files(struct trace_array *tr, struct tracer *tracer);
>  
>  static void
>  destroy_trace_option_files(struct trace_option_dentry *topts);
> @@ -3250,13 +3630,15 @@ static int tracing_set_tracer(const char *buf)
>  	static struct trace_option_dentry *topts;
>  	struct trace_array *tr = &global_trace;
>  	struct tracer *t;
> +#ifdef CONFIG_TRACER_MAX_TRACE
>  	bool had_max_tr;
> +#endif
>  	int ret = 0;
>  
>  	mutex_lock(&trace_types_lock);
>  
>  	if (!ring_buffer_expanded) {
> -		ret = __tracing_resize_ring_buffer(trace_buf_size,
> +		ret = __tracing_resize_ring_buffer(tr, trace_buf_size,
>  						RING_BUFFER_ALL_CPUS);
>  		if (ret < 0)
>  			goto out;
> @@ -3271,18 +3653,21 @@ static int tracing_set_tracer(const char *buf)
>  		ret = -EINVAL;
>  		goto out;
>  	}
> -	if (t == current_trace)
> +	if (t == tr->current_trace)
>  		goto out;
>  
>  	trace_branch_disable();
>  
> -	current_trace->enabled = false;
> +	tr->current_trace->enabled = false;
>  
> -	if (current_trace->reset)
> -		current_trace->reset(tr);
> +	if (tr->current_trace->reset)
> +		tr->current_trace->reset(tr);
>  
> -	had_max_tr = current_trace->allocated_snapshot;
> -	current_trace = &nop_trace;
> +	/* Current trace needs to be nop_trace before synchronize_sched */
> +	tr->current_trace = &nop_trace;
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	had_max_tr = tr->allocated_snapshot;
>  
>  	if (had_max_tr && !t->use_max_tr) {
>  		/*
> @@ -3293,27 +3678,20 @@ static int tracing_set_tracer(const char *buf)
>  		 * so a synchronized_sched() is sufficient.
>  		 */
>  		synchronize_sched();
> -		/*
> -		 * We don't free the ring buffer. instead, resize it because
> -		 * The max_tr ring buffer has some state (e.g. ring->clock) and
> -		 * we want preserve it.
> -		 */
> -		ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS);
> -		set_buffer_entries(&max_tr, 1);
> -		tracing_reset_online_cpus(&max_tr);
> -		current_trace->allocated_snapshot = false;
> +		free_snapshot(tr);
>  	}
> +#endif
>  	destroy_trace_option_files(topts);
>  
> -	topts = create_trace_option_files(t);
> +	topts = create_trace_option_files(tr, t);
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
>  	if (t->use_max_tr && !had_max_tr) {
> -		/* we need to make per cpu buffer sizes equivalent */
> -		ret = resize_buffer_duplicate_size(&max_tr, &global_trace,
> -						   RING_BUFFER_ALL_CPUS);
> +		ret = alloc_snapshot(tr);
>  		if (ret < 0)
>  			goto out;
> -		t->allocated_snapshot = true;
>  	}
> +#endif
>  
>  	if (t->init) {
>  		ret = tracer_init(t, tr);
> @@ -3321,8 +3699,8 @@ static int tracing_set_tracer(const char *buf)
>  			goto out;
>  	}
>  
> -	current_trace = t;
> -	current_trace->enabled = true;
> +	tr->current_trace = t;
> +	tr->current_trace->enabled = true;
>  	trace_branch_enable(tr);
>   out:
>  	mutex_unlock(&trace_types_lock);
> @@ -3396,7 +3774,8 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf,
>  
>  static int tracing_open_pipe(struct inode *inode, struct file *filp)
>  {
> -	long cpu_file = (long) inode->i_private;
> +	struct trace_cpu *tc = inode->i_private;
> +	struct trace_array *tr = tc->tr;
>  	struct trace_iterator *iter;
>  	int ret = 0;
>  
> @@ -3421,7 +3800,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
>  		ret = -ENOMEM;
>  		goto fail;
>  	}
> -	*iter->trace = *current_trace;
> +	*iter->trace = *tr->current_trace;
>  
>  	if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {
>  		ret = -ENOMEM;
> @@ -3438,8 +3817,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
>  	if (trace_clocks[trace_clock_id].in_ns)
>  		iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
>  
> -	iter->cpu_file = cpu_file;
> -	iter->tr = &global_trace;
> +	iter->cpu_file = tc->cpu;
> +	iter->tr = tc->tr;
> +	iter->trace_buffer = &tc->tr->trace_buffer;
>  	mutex_init(&iter->mutex);
>  	filp->private_data = iter;
>  
> @@ -3478,24 +3858,28 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
>  }
>  
>  static unsigned int
> -tracing_poll_pipe(struct file *filp, poll_table *poll_table)
> +trace_poll(struct trace_iterator *iter, struct file *filp, poll_table *poll_table)
>  {
> -	struct trace_iterator *iter = filp->private_data;
> +	/* Iterators are static, they should be filled or empty */
> +	if (trace_buffer_iter(iter, iter->cpu_file))
> +		return POLLIN | POLLRDNORM;
>  
> -	if (trace_flags & TRACE_ITER_BLOCK) {
> +	if (trace_flags & TRACE_ITER_BLOCK)
>  		/*
>  		 * Always select as readable when in blocking mode
>  		 */
>  		return POLLIN | POLLRDNORM;
> -	} else {
> -		if (!trace_empty(iter))
> -			return POLLIN | POLLRDNORM;
> -		poll_wait(filp, &trace_wait, poll_table);
> -		if (!trace_empty(iter))
> -			return POLLIN | POLLRDNORM;
> +	else
> +		return ring_buffer_poll_wait(iter->trace_buffer->buffer, iter->cpu_file,
> +					     filp, poll_table);
> +}
>  
> -		return 0;
> -	}
> +static unsigned int
> +tracing_poll_pipe(struct file *filp, poll_table *poll_table)
> +{
> +	struct trace_iterator *iter = filp->private_data;
> +
> +	return trace_poll(iter, filp, poll_table);
>  }
>  
>  /*
> @@ -3561,6 +3945,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
>  		  size_t cnt, loff_t *ppos)
>  {
>  	struct trace_iterator *iter = filp->private_data;
> +	struct trace_array *tr = iter->tr;
>  	ssize_t sret;
>  
>  	/* return any leftover data */
> @@ -3572,8 +3957,8 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
>  
>  	/* copy the tracer to avoid using a global lock all around */
>  	mutex_lock(&trace_types_lock);
> -	if (unlikely(iter->trace->name != current_trace->name))
> -		*iter->trace = *current_trace;
> +	if (unlikely(iter->trace->name != tr->current_trace->name))
> +		*iter->trace = *tr->current_trace;
>  	mutex_unlock(&trace_types_lock);
>  
>  	/*
> @@ -3729,6 +4114,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
>  		.ops		= &tracing_pipe_buf_ops,
>  		.spd_release	= tracing_spd_release_pipe,
>  	};
> +	struct trace_array *tr = iter->tr;
>  	ssize_t ret;
>  	size_t rem;
>  	unsigned int i;
> @@ -3738,8 +4124,8 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
>  
>  	/* copy the tracer to avoid using a global lock all around */
>  	mutex_lock(&trace_types_lock);
> -	if (unlikely(iter->trace->name != current_trace->name))
> -		*iter->trace = *current_trace;
> +	if (unlikely(iter->trace->name != tr->current_trace->name))
> +		*iter->trace = *tr->current_trace;
>  	mutex_unlock(&trace_types_lock);
>  
>  	mutex_lock(&iter->mutex);
> @@ -3801,43 +4187,19 @@ out_err:
>  	goto out;
>  }
>  
> -struct ftrace_entries_info {
> -	struct trace_array	*tr;
> -	int			cpu;
> -};
> -
> -static int tracing_entries_open(struct inode *inode, struct file *filp)
> -{
> -	struct ftrace_entries_info *info;
> -
> -	if (tracing_disabled)
> -		return -ENODEV;
> -
> -	info = kzalloc(sizeof(*info), GFP_KERNEL);
> -	if (!info)
> -		return -ENOMEM;
> -
> -	info->tr = &global_trace;
> -	info->cpu = (unsigned long)inode->i_private;
> -
> -	filp->private_data = info;
> -
> -	return 0;
> -}
> -
>  static ssize_t
>  tracing_entries_read(struct file *filp, char __user *ubuf,
>  		     size_t cnt, loff_t *ppos)
>  {
> -	struct ftrace_entries_info *info = filp->private_data;
> -	struct trace_array *tr = info->tr;
> +	struct trace_cpu *tc = filp->private_data;
> +	struct trace_array *tr = tc->tr;
>  	char buf[64];
>  	int r = 0;
>  	ssize_t ret;
>  
>  	mutex_lock(&trace_types_lock);
>  
> -	if (info->cpu == RING_BUFFER_ALL_CPUS) {
> +	if (tc->cpu == RING_BUFFER_ALL_CPUS) {
>  		int cpu, buf_size_same;
>  		unsigned long size;
>  
> @@ -3847,8 +4209,8 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
>  		for_each_tracing_cpu(cpu) {
>  			/* fill in the size from first enabled cpu */
>  			if (size == 0)
> -				size = tr->data[cpu]->entries;
> -			if (size != tr->data[cpu]->entries) {
> +				size = per_cpu_ptr(tr->trace_buffer.data, cpu)->entries;
> +			if (size != per_cpu_ptr(tr->trace_buffer.data, cpu)->entries) {
>  				buf_size_same = 0;
>  				break;
>  			}
> @@ -3864,7 +4226,7 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
>  		} else
>  			r = sprintf(buf, "X\n");
>  	} else
> -		r = sprintf(buf, "%lu\n", tr->data[info->cpu]->entries >> 10);
> +		r = sprintf(buf, "%lu\n", per_cpu_ptr(tr->trace_buffer.data, tc->cpu)->entries >> 10);
>  
>  	mutex_unlock(&trace_types_lock);
>  
> @@ -3876,7 +4238,7 @@ static ssize_t
>  tracing_entries_write(struct file *filp, const char __user *ubuf,
>  		      size_t cnt, loff_t *ppos)
>  {
> -	struct ftrace_entries_info *info = filp->private_data;
> +	struct trace_cpu *tc = filp->private_data;
>  	unsigned long val;
>  	int ret;
>  
> @@ -3891,7 +4253,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
>  	/* value is in KB */
>  	val <<= 10;
>  
> -	ret = tracing_resize_ring_buffer(val, info->cpu);
> +	ret = tracing_resize_ring_buffer(tc->tr, val, tc->cpu);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -3900,16 +4262,6 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
>  	return cnt;
>  }
>  
> -static int
> -tracing_entries_release(struct inode *inode, struct file *filp)
> -{
> -	struct ftrace_entries_info *info = filp->private_data;
> -
> -	kfree(info);
> -
> -	return 0;
> -}
> -
>  static ssize_t
>  tracing_total_entries_read(struct file *filp, char __user *ubuf,
>  				size_t cnt, loff_t *ppos)
> @@ -3921,7 +4273,7 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
>  
>  	mutex_lock(&trace_types_lock);
>  	for_each_tracing_cpu(cpu) {
> -		size += tr->data[cpu]->entries >> 10;
> +		size += per_cpu_ptr(tr->trace_buffer.data, cpu)->entries >> 10;
>  		if (!ring_buffer_expanded)
>  			expanded_size += trace_buf_size >> 10;
>  	}
> @@ -3951,11 +4303,13 @@ tracing_free_buffer_write(struct file *filp, const char __user *ubuf,
>  static int
>  tracing_free_buffer_release(struct inode *inode, struct file *filp)
>  {
> +	struct trace_array *tr = inode->i_private;
> +
>  	/* disable tracing ? */
>  	if (trace_flags & TRACE_ITER_STOP_ON_FREE)
>  		tracing_off();
>  	/* resize the ring buffer to 0 */
> -	tracing_resize_ring_buffer(0, RING_BUFFER_ALL_CPUS);
> +	tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
>  
>  	return 0;
>  }
> @@ -4024,7 +4378,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
>  
>  	local_save_flags(irq_flags);
>  	size = sizeof(*entry) + cnt + 2; /* possible \n added */
> -	buffer = global_trace.buffer;
> +	buffer = global_trace.trace_buffer.buffer;
>  	event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
>  					  irq_flags, preempt_count());
>  	if (!event) {
> @@ -4066,13 +4420,14 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
>  
>  static int tracing_clock_show(struct seq_file *m, void *v)
>  {
> +	struct trace_array *tr = m->private;
>  	int i;
>  
>  	for (i = 0; i < ARRAY_SIZE(trace_clocks); i++)
>  		seq_printf(m,
>  			"%s%s%s%s", i ? " " : "",
> -			i == trace_clock_id ? "[" : "", trace_clocks[i].name,
> -			i == trace_clock_id ? "]" : "");
> +			i == tr->clock_id ? "[" : "", trace_clocks[i].name,
> +			i == tr->clock_id ? "]" : "");
>  	seq_putc(m, '\n');
>  
>  	return 0;
> @@ -4081,6 +4436,8 @@ static int tracing_clock_show(struct seq_file *m, void *v)
>  static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
>  				   size_t cnt, loff_t *fpos)
>  {
> +	struct seq_file *m = filp->private_data;
> +	struct trace_array *tr = m->private;
>  	char buf[64];
>  	const char *clockstr;
>  	int i;
> @@ -4102,20 +4459,23 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
>  	if (i == ARRAY_SIZE(trace_clocks))
>  		return -EINVAL;
>  
> -	trace_clock_id = i;
> -
>  	mutex_lock(&trace_types_lock);
>  
> -	ring_buffer_set_clock(global_trace.buffer, trace_clocks[i].func);
> -	if (max_tr.buffer)
> -		ring_buffer_set_clock(max_tr.buffer, trace_clocks[i].func);
> +	tr->clock_id = i;
> +
> +	ring_buffer_set_clock(tr->trace_buffer.buffer, trace_clocks[i].func);
>  
>  	/*
>  	 * New clock may not be consistent with the previous clock.
>  	 * Reset the buffer so that it doesn't have incomparable timestamps.
>  	 */
> -	tracing_reset_online_cpus(&global_trace);
> -	tracing_reset_online_cpus(&max_tr);
> +	tracing_reset_online_cpus(&global_trace.trace_buffer);
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
> +		ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
> +	tracing_reset_online_cpus(&global_trace.max_buffer);
> +#endif
>  
>  	mutex_unlock(&trace_types_lock);
>  
> @@ -4128,20 +4488,45 @@ static int tracing_clock_open(struct inode *inode, struct file *file)
>  {
>  	if (tracing_disabled)
>  		return -ENODEV;
> -	return single_open(file, tracing_clock_show, NULL);
> +
> +	return single_open(file, tracing_clock_show, inode->i_private);
>  }
>  
> +struct ftrace_buffer_info {
> +	struct trace_iterator	iter;
> +	void			*spare;
> +	unsigned int		read;
> +};
> +
>  #ifdef CONFIG_TRACER_SNAPSHOT
>  static int tracing_snapshot_open(struct inode *inode, struct file *file)
>  {
> +	struct trace_cpu *tc = inode->i_private;
>  	struct trace_iterator *iter;
> +	struct seq_file *m;
>  	int ret = 0;
>  
>  	if (file->f_mode & FMODE_READ) {
>  		iter = __tracing_open(inode, file, true);
>  		if (IS_ERR(iter))
>  			ret = PTR_ERR(iter);
> +	} else {
> +		/* Writes still need the seq_file to hold the private data */
> +		m = kzalloc(sizeof(*m), GFP_KERNEL);
> +		if (!m)
> +			return -ENOMEM;
> +		iter = kzalloc(sizeof(*iter), GFP_KERNEL);
> +		if (!iter) {
> +			kfree(m);
> +			return -ENOMEM;
> +		}
> +		iter->tr = tc->tr;
> +		iter->trace_buffer = &tc->tr->max_buffer;
> +		iter->cpu_file = tc->cpu;
> +		m->private = iter;
> +		file->private_data = m;
>  	}
> +
>  	return ret;
>  }
>  
> @@ -4149,6 +4534,9 @@ static ssize_t
>  tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  		       loff_t *ppos)
>  {
> +	struct seq_file *m = filp->private_data;
> +	struct trace_iterator *iter = m->private;
> +	struct trace_array *tr = iter->tr;
>  	unsigned long val;
>  	int ret;
>  
> @@ -4162,40 +4550,48 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  
>  	mutex_lock(&trace_types_lock);
>  
> -	if (current_trace->use_max_tr) {
> +	if (tr->current_trace->use_max_tr) {
>  		ret = -EBUSY;
>  		goto out;
>  	}
>  
>  	switch (val) {
>  	case 0:
> -		if (current_trace->allocated_snapshot) {
> -			/* free spare buffer */
> -			ring_buffer_resize(max_tr.buffer, 1,
> -					   RING_BUFFER_ALL_CPUS);
> -			set_buffer_entries(&max_tr, 1);
> -			tracing_reset_online_cpus(&max_tr);
> -			current_trace->allocated_snapshot = false;
> +		if (iter->cpu_file != RING_BUFFER_ALL_CPUS) {
> +			ret = -EINVAL;
> +			break;
>  		}
> +		if (tr->allocated_snapshot)
> +			free_snapshot(tr);
>  		break;
>  	case 1:
> -		if (!current_trace->allocated_snapshot) {
> -			/* allocate spare buffer */
> -			ret = resize_buffer_duplicate_size(&max_tr,
> -					&global_trace, RING_BUFFER_ALL_CPUS);
> +/* Only allow per-cpu swap if the ring buffer supports it */
> +#ifndef CONFIG_RING_BUFFER_ALLOW_SWAP
> +		if (iter->cpu_file != RING_BUFFER_ALL_CPUS) {
> +			ret = -EINVAL;
> +			break;
> +		}
> +#endif
> +		if (!tr->allocated_snapshot) {
> +			ret = alloc_snapshot(tr);
>  			if (ret < 0)
>  				break;
> -			current_trace->allocated_snapshot = true;
>  		}
> -
>  		local_irq_disable();
>  		/* Now, we're going to swap */
> -		update_max_tr(&global_trace, current, smp_processor_id());
> +		if (iter->cpu_file == RING_BUFFER_ALL_CPUS)
> +			update_max_tr(tr, current, smp_processor_id());
> +		else
> +			update_max_tr_single(tr, current, iter->cpu_file);
>  		local_irq_enable();
>  		break;
>  	default:
> -		if (current_trace->allocated_snapshot)
> -			tracing_reset_online_cpus(&max_tr);
> +		if (tr->allocated_snapshot) {
> +			if (iter->cpu_file == RING_BUFFER_ALL_CPUS)
> +				tracing_reset_online_cpus(&tr->max_buffer);
> +			else
> +				tracing_reset(&tr->max_buffer, iter->cpu_file);
> +		}
>  		break;
>  	}
>  
> @@ -4207,6 +4603,51 @@ out:
>  	mutex_unlock(&trace_types_lock);
>  	return ret;
>  }
> +
> +static int tracing_snapshot_release(struct inode *inode, struct file *file)
> +{
> +	struct seq_file *m = file->private_data;
> +
> +	if (file->f_mode & FMODE_READ)
> +		return tracing_release(inode, file);
> +
> +	/* If write only, the seq_file is just a stub */
> +	if (m)
> +		kfree(m->private);
> +	kfree(m);
> +
> +	return 0;
> +}
> +
> +static int tracing_buffers_open(struct inode *inode, struct file *filp);
> +static ssize_t tracing_buffers_read(struct file *filp, char __user *ubuf,
> +				    size_t count, loff_t *ppos);
> +static int tracing_buffers_release(struct inode *inode, struct file *file);
> +static ssize_t tracing_buffers_splice_read(struct file *file, loff_t *ppos,
> +		   struct pipe_inode_info *pipe, size_t len, unsigned int flags);
> +
> +static int snapshot_raw_open(struct inode *inode, struct file *filp)
> +{
> +	struct ftrace_buffer_info *info;
> +	int ret;
> +
> +	ret = tracing_buffers_open(inode, filp);
> +	if (ret < 0)
> +		return ret;
> +
> +	info = filp->private_data;
> +
> +	if (info->iter.trace->use_max_tr) {
> +		tracing_buffers_release(inode, filp);
> +		return -EBUSY;
> +	}
> +
> +	info->iter.snapshot = true;
> +	info->iter.trace_buffer = &info->iter.tr->max_buffer;
> +
> +	return ret;
> +}
> +
>  #endif /* CONFIG_TRACER_SNAPSHOT */
>  
> 
> @@ -4234,10 +4675,9 @@ static const struct file_operations tracing_pipe_fops = {
>  };
>  
>  static const struct file_operations tracing_entries_fops = {
> -	.open		= tracing_entries_open,
> +	.open		= tracing_open_generic,
>  	.read		= tracing_entries_read,
>  	.write		= tracing_entries_write,
> -	.release	= tracing_entries_release,
>  	.llseek		= generic_file_llseek,
>  };
>  
> @@ -4272,20 +4712,23 @@ static const struct file_operations snapshot_fops = {
>  	.read		= seq_read,
>  	.write		= tracing_snapshot_write,
>  	.llseek		= tracing_seek,
> -	.release	= tracing_release,
> +	.release	= tracing_snapshot_release,
>  };
> -#endif /* CONFIG_TRACER_SNAPSHOT */
>  
> -struct ftrace_buffer_info {
> -	struct trace_array	*tr;
> -	void			*spare;
> -	int			cpu;
> -	unsigned int		read;
> +static const struct file_operations snapshot_raw_fops = {
> +	.open		= snapshot_raw_open,
> +	.read		= tracing_buffers_read,
> +	.release	= tracing_buffers_release,
> +	.splice_read	= tracing_buffers_splice_read,
> +	.llseek		= no_llseek,
>  };
>  
> +#endif /* CONFIG_TRACER_SNAPSHOT */
> +
>  static int tracing_buffers_open(struct inode *inode, struct file *filp)
>  {
> -	int cpu = (int)(long)inode->i_private;
> +	struct trace_cpu *tc = inode->i_private;
> +	struct trace_array *tr = tc->tr;
>  	struct ftrace_buffer_info *info;
>  
>  	if (tracing_disabled)
> @@ -4295,72 +4738,131 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
>  	if (!info)
>  		return -ENOMEM;
>  
> -	info->tr	= &global_trace;
> -	info->cpu	= cpu;
> -	info->spare	= NULL;
> +	mutex_lock(&trace_types_lock);
> +
> +	tr->ref++;
> +
> +	info->iter.tr		= tr;
> +	info->iter.cpu_file	= tc->cpu;
> +	info->iter.trace	= tr->current_trace;
> +	info->iter.trace_buffer = &tr->trace_buffer;
> +	info->spare		= NULL;
>  	/* Force reading ring buffer for first read */
> -	info->read	= (unsigned int)-1;
> +	info->read		= (unsigned int)-1;
>  
>  	filp->private_data = info;
>  
> +	mutex_unlock(&trace_types_lock);
> +
>  	return nonseekable_open(inode, filp);
>  }
>  
> +static unsigned int
> +tracing_buffers_poll(struct file *filp, poll_table *poll_table)
> +{
> +	struct ftrace_buffer_info *info = filp->private_data;
> +	struct trace_iterator *iter = &info->iter;
> +
> +	return trace_poll(iter, filp, poll_table);
> +}
> +
>  static ssize_t
>  tracing_buffers_read(struct file *filp, char __user *ubuf,
>  		     size_t count, loff_t *ppos)
>  {
>  	struct ftrace_buffer_info *info = filp->private_data;
> +	struct trace_iterator *iter = &info->iter;
>  	ssize_t ret;
> -	size_t size;
> +	ssize_t size;
>  
>  	if (!count)
>  		return 0;
>  
> +	mutex_lock(&trace_types_lock);
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	if (iter->snapshot && iter->tr->current_trace->use_max_tr) {
> +		size = -EBUSY;
> +		goto out_unlock;
> +	}
> +#endif
> +
>  	if (!info->spare)
> -		info->spare = ring_buffer_alloc_read_page(info->tr->buffer, info->cpu);
> +		info->spare = ring_buffer_alloc_read_page(iter->trace_buffer->buffer,
> +							  iter->cpu_file);
> +	size = -ENOMEM;
>  	if (!info->spare)
> -		return -ENOMEM;
> +		goto out_unlock;
>  
>  	/* Do we have previous read data to read? */
>  	if (info->read < PAGE_SIZE)
>  		goto read;
>  
> -	trace_access_lock(info->cpu);
> -	ret = ring_buffer_read_page(info->tr->buffer,
> + again:
> +	trace_access_lock(iter->cpu_file);
> +	ret = ring_buffer_read_page(iter->trace_buffer->buffer,
>  				    &info->spare,
>  				    count,
> -				    info->cpu, 0);
> -	trace_access_unlock(info->cpu);
> -	if (ret < 0)
> -		return 0;
> +				    iter->cpu_file, 0);
> +	trace_access_unlock(iter->cpu_file);
>  
> -	info->read = 0;
> +	if (ret < 0) {
> +		if (trace_empty(iter)) {
> +			if ((filp->f_flags & O_NONBLOCK)) {
> +				size = -EAGAIN;
> +				goto out_unlock;
> +			}
> +			mutex_unlock(&trace_types_lock);
> +			iter->trace->wait_pipe(iter);
> +			mutex_lock(&trace_types_lock);
> +			if (signal_pending(current)) {
> +				size = -EINTR;
> +				goto out_unlock;
> +			}
> +			goto again;
> +		}
> +		size = 0;
> +		goto out_unlock;
> +	}
>  
> -read:
> +	info->read = 0;
> + read:
>  	size = PAGE_SIZE - info->read;
>  	if (size > count)
>  		size = count;
>  
>  	ret = copy_to_user(ubuf, info->spare + info->read, size);
> -	if (ret == size)
> -		return -EFAULT;
> +	if (ret == size) {
> +		size = -EFAULT;
> +		goto out_unlock;
> +	}
>  	size -= ret;
>  
>  	*ppos += size;
>  	info->read += size;
>  
> + out_unlock:
> +	mutex_unlock(&trace_types_lock);
> +
>  	return size;
>  }
>  
>  static int tracing_buffers_release(struct inode *inode, struct file *file)
>  {
>  	struct ftrace_buffer_info *info = file->private_data;
> +	struct trace_iterator *iter = &info->iter;
> +
> +	mutex_lock(&trace_types_lock);
> +
> +	WARN_ON(!iter->tr->ref);
> +	iter->tr->ref--;
>  
>  	if (info->spare)
> -		ring_buffer_free_read_page(info->tr->buffer, info->spare);
> +		ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare);
>  	kfree(info);
>  
> +	mutex_unlock(&trace_types_lock);
> +
>  	return 0;
>  }
>  
> @@ -4425,6 +4927,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
>  			    unsigned int flags)
>  {
>  	struct ftrace_buffer_info *info = file->private_data;
> +	struct trace_iterator *iter = &info->iter;
>  	struct partial_page partial_def[PIPE_DEF_BUFFERS];
>  	struct page *pages_def[PIPE_DEF_BUFFERS];
>  	struct splice_pipe_desc spd = {
> @@ -4437,10 +4940,21 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
>  	};
>  	struct buffer_ref *ref;
>  	int entries, size, i;
> -	size_t ret;
> +	ssize_t ret;
>  
> -	if (splice_grow_spd(pipe, &spd))
> -		return -ENOMEM;
> +	mutex_lock(&trace_types_lock);
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	if (iter->snapshot && iter->tr->current_trace->use_max_tr) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +#endif
> +
> +	if (splice_grow_spd(pipe, &spd)) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
>  
>  	if (*ppos & (PAGE_SIZE - 1)) {
>  		ret = -EINVAL;
> @@ -4455,8 +4969,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
>  		len &= PAGE_MASK;
>  	}
>  
> -	trace_access_lock(info->cpu);
> -	entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
> + again:
> +	trace_access_lock(iter->cpu_file);
> +	entries = ring_buffer_entries_cpu(iter->trace_buffer->buffer, iter->cpu_file);
>  
>  	for (i = 0; i < pipe->buffers && len && entries; i++, len -= PAGE_SIZE) {
>  		struct page *page;
> @@ -4467,15 +4982,15 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
>  			break;
>  
>  		ref->ref = 1;
> -		ref->buffer = info->tr->buffer;
> -		ref->page = ring_buffer_alloc_read_page(ref->buffer, info->cpu);
> +		ref->buffer = iter->trace_buffer->buffer;
> +		ref->page = ring_buffer_alloc_read_page(ref->buffer, iter->cpu_file);
>  		if (!ref->page) {
>  			kfree(ref);
>  			break;
>  		}
>  
>  		r = ring_buffer_read_page(ref->buffer, &ref->page,
> -					  len, info->cpu, 1);
> +					  len, iter->cpu_file, 1);
>  		if (r < 0) {
>  			ring_buffer_free_read_page(ref->buffer, ref->page);
>  			kfree(ref);
> @@ -4499,31 +5014,40 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
>  		spd.nr_pages++;
>  		*ppos += PAGE_SIZE;
>  
> -		entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
> +		entries = ring_buffer_entries_cpu(iter->trace_buffer->buffer, iter->cpu_file);
>  	}
>  
> -	trace_access_unlock(info->cpu);
> +	trace_access_unlock(iter->cpu_file);
>  	spd.nr_pages = i;
>  
>  	/* did we read anything? */
>  	if (!spd.nr_pages) {
> -		if (flags & SPLICE_F_NONBLOCK)
> +		if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK)) {
>  			ret = -EAGAIN;
> -		else
> -			ret = 0;
> -		/* TODO: block */
> -		goto out;
> +			goto out;
> +		}
> +		mutex_unlock(&trace_types_lock);
> +		iter->trace->wait_pipe(iter);
> +		mutex_lock(&trace_types_lock);
> +		if (signal_pending(current)) {
> +			ret = -EINTR;
> +			goto out;
> +		}
> +		goto again;
>  	}
>  
>  	ret = splice_to_pipe(pipe, &spd);
>  	splice_shrink_spd(&spd);
>  out:
> +	mutex_unlock(&trace_types_lock);
> +
>  	return ret;
>  }
>  
>  static const struct file_operations tracing_buffers_fops = {
>  	.open		= tracing_buffers_open,
>  	.read		= tracing_buffers_read,
> +	.poll		= tracing_buffers_poll,
>  	.release	= tracing_buffers_release,
>  	.splice_read	= tracing_buffers_splice_read,
>  	.llseek		= no_llseek,
> @@ -4533,12 +5057,14 @@ static ssize_t
>  tracing_stats_read(struct file *filp, char __user *ubuf,
>  		   size_t count, loff_t *ppos)
>  {
> -	unsigned long cpu = (unsigned long)filp->private_data;
> -	struct trace_array *tr = &global_trace;
> +	struct trace_cpu *tc = filp->private_data;
> +	struct trace_array *tr = tc->tr;
> +	struct trace_buffer *trace_buf = &tr->trace_buffer;
>  	struct trace_seq *s;
>  	unsigned long cnt;
>  	unsigned long long t;
>  	unsigned long usec_rem;
> +	int cpu = tc->cpu;
>  
>  	s = kmalloc(sizeof(*s), GFP_KERNEL);
>  	if (!s)
> @@ -4546,41 +5072,41 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
>  
>  	trace_seq_init(s);
>  
> -	cnt = ring_buffer_entries_cpu(tr->buffer, cpu);
> +	cnt = ring_buffer_entries_cpu(trace_buf->buffer, cpu);
>  	trace_seq_printf(s, "entries: %ld\n", cnt);
>  
> -	cnt = ring_buffer_overrun_cpu(tr->buffer, cpu);
> +	cnt = ring_buffer_overrun_cpu(trace_buf->buffer, cpu);
>  	trace_seq_printf(s, "overrun: %ld\n", cnt);
>  
> -	cnt = ring_buffer_commit_overrun_cpu(tr->buffer, cpu);
> +	cnt = ring_buffer_commit_overrun_cpu(trace_buf->buffer, cpu);
>  	trace_seq_printf(s, "commit overrun: %ld\n", cnt);
>  
> -	cnt = ring_buffer_bytes_cpu(tr->buffer, cpu);
> +	cnt = ring_buffer_bytes_cpu(trace_buf->buffer, cpu);
>  	trace_seq_printf(s, "bytes: %ld\n", cnt);
>  
>  	if (trace_clocks[trace_clock_id].in_ns) {
>  		/* local or global for trace_clock */
> -		t = ns2usecs(ring_buffer_oldest_event_ts(tr->buffer, cpu));
> +		t = ns2usecs(ring_buffer_oldest_event_ts(trace_buf->buffer, cpu));
>  		usec_rem = do_div(t, USEC_PER_SEC);
>  		trace_seq_printf(s, "oldest event ts: %5llu.%06lu\n",
>  								t, usec_rem);
>  
> -		t = ns2usecs(ring_buffer_time_stamp(tr->buffer, cpu));
> +		t = ns2usecs(ring_buffer_time_stamp(trace_buf->buffer, cpu));
>  		usec_rem = do_div(t, USEC_PER_SEC);
>  		trace_seq_printf(s, "now ts: %5llu.%06lu\n", t, usec_rem);
>  	} else {
>  		/* counter or tsc mode for trace_clock */
>  		trace_seq_printf(s, "oldest event ts: %llu\n",
> -				ring_buffer_oldest_event_ts(tr->buffer, cpu));
> +				ring_buffer_oldest_event_ts(trace_buf->buffer, cpu));
>  
>  		trace_seq_printf(s, "now ts: %llu\n",
> -				ring_buffer_time_stamp(tr->buffer, cpu));
> +				ring_buffer_time_stamp(trace_buf->buffer, cpu));
>  	}
>  
> -	cnt = ring_buffer_dropped_events_cpu(tr->buffer, cpu);
> +	cnt = ring_buffer_dropped_events_cpu(trace_buf->buffer, cpu);
>  	trace_seq_printf(s, "dropped events: %ld\n", cnt);
>  
> -	cnt = ring_buffer_read_events_cpu(tr->buffer, cpu);
> +	cnt = ring_buffer_read_events_cpu(trace_buf->buffer, cpu);
>  	trace_seq_printf(s, "read events: %ld\n", cnt);
>  
>  	count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
> @@ -4632,60 +5158,161 @@ static const struct file_operations tracing_dyn_info_fops = {
>  	.read		= tracing_read_dyn_info,
>  	.llseek		= generic_file_llseek,
>  };
> -#endif
> +#endif /* CONFIG_DYNAMIC_FTRACE */
> +
> +#if defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE)
> +static void
> +ftrace_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
> +{
> +	tracing_snapshot();
> +}
>  
> -static struct dentry *d_tracer;
> +static void
> +ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
> +{
> +	unsigned long *count = (long *)data;
>  
> -struct dentry *tracing_init_dentry(void)
> +	if (!*count)
> +		return;
> +
> +	if (*count != -1)
> +		(*count)--;
> +
> +	tracing_snapshot();
> +}
> +
> +static int
> +ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
> +		      struct ftrace_probe_ops *ops, void *data)
> +{
> +	long count = (long)data;
> +
> +	seq_printf(m, "%ps:", (void *)ip);
> +
> +	seq_printf(m, "snapshot");
> +
> +	if (count == -1)
> +		seq_printf(m, ":unlimited\n");
> +	else
> +		seq_printf(m, ":count=%ld\n", count);
> +
> +	return 0;
> +}
> +
> +static struct ftrace_probe_ops snapshot_probe_ops = {
> +	.func			= ftrace_snapshot,
> +	.print			= ftrace_snapshot_print,
> +};
> +
> +static struct ftrace_probe_ops snapshot_count_probe_ops = {
> +	.func			= ftrace_count_snapshot,
> +	.print			= ftrace_snapshot_print,
> +};
> +
> +static int
> +ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
> +			       char *glob, char *cmd, char *param, int enable)
>  {
> -	static int once;
> +	struct ftrace_probe_ops *ops;
> +	void *count = (void *)-1;
> +	char *number;
> +	int ret;
> +
> +	/* hash funcs only work with set_ftrace_filter */
> +	if (!enable)
> +		return -EINVAL;
> +
> +	ops = param ? &snapshot_count_probe_ops :  &snapshot_probe_ops;
> +
> +	if (glob[0] == '!') {
> +		unregister_ftrace_function_probe_func(glob+1, ops);
> +		return 0;
> +	}
> +
> +	if (!param)
> +		goto out_reg;
> +
> +	number = strsep(&param, ":");
> +
> +	if (!strlen(number))
> +		goto out_reg;
> +
> +	/*
> +	 * We use the callback data field (which is a pointer)
> +	 * as our counter.
> +	 */
> +	ret = kstrtoul(number, 0, (unsigned long *)&count);
> +	if (ret)
> +		return ret;
> +
> + out_reg:
> +	ret = register_ftrace_function_probe(glob, ops, count);
> +
> +	if (ret >= 0)
> +		alloc_snapshot(&global_trace);
> +
> +	return ret < 0 ? ret : 0;
> +}
> +
> +static struct ftrace_func_command ftrace_snapshot_cmd = {
> +	.name			= "snapshot",
> +	.func			= ftrace_trace_snapshot_callback,
> +};
> +
> +static int register_snapshot_cmd(void)
> +{
> +	return register_ftrace_command(&ftrace_snapshot_cmd);
> +}
> +#else
> +static inline int register_snapshot_cmd(void) { return 0; }
> +#endif /* defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE) */
>  
> -	if (d_tracer)
> -		return d_tracer;
> +struct dentry *tracing_init_dentry_tr(struct trace_array *tr)
> +{
> +	if (tr->dir)
> +		return tr->dir;
>  
>  	if (!debugfs_initialized())
>  		return NULL;
>  
> -	d_tracer = debugfs_create_dir("tracing", NULL);
> +	if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
> +		tr->dir = debugfs_create_dir("tracing", NULL);
>  
> -	if (!d_tracer && !once) {
> -		once = 1;
> -		pr_warning("Could not create debugfs directory 'tracing'\n");
> -		return NULL;
> -	}
> +	if (!tr->dir)
> +		pr_warn_once("Could not create debugfs directory 'tracing'\n");
>  
> -	return d_tracer;
> +	return tr->dir;
>  }
>  
> -static struct dentry *d_percpu;
> +struct dentry *tracing_init_dentry(void)
> +{
> +	return tracing_init_dentry_tr(&global_trace);
> +}
>  
> -static struct dentry *tracing_dentry_percpu(void)
> +static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu)
>  {
> -	static int once;
>  	struct dentry *d_tracer;
>  
> -	if (d_percpu)
> -		return d_percpu;
> -
> -	d_tracer = tracing_init_dentry();
> +	if (tr->percpu_dir)
> +		return tr->percpu_dir;
>  
> +	d_tracer = tracing_init_dentry_tr(tr);
>  	if (!d_tracer)
>  		return NULL;
>  
> -	d_percpu = debugfs_create_dir("per_cpu", d_tracer);
> +	tr->percpu_dir = debugfs_create_dir("per_cpu", d_tracer);
>  
> -	if (!d_percpu && !once) {
> -		once = 1;
> -		pr_warning("Could not create debugfs directory 'per_cpu'\n");
> -		return NULL;
> -	}
> +	WARN_ONCE(!tr->percpu_dir,
> +		  "Could not create debugfs directory 'per_cpu/%d'\n", cpu);
>  
> -	return d_percpu;
> +	return tr->percpu_dir;
>  }
>  
> -static void tracing_init_debugfs_percpu(long cpu)
> +static void
> +tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
>  {
> -	struct dentry *d_percpu = tracing_dentry_percpu();
> +	struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
> +	struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
>  	struct dentry *d_cpu;
>  	char cpu_dir[30]; /* 30 characters should be more than enough */
>  
> @@ -4701,20 +5328,28 @@ static void tracing_init_debugfs_percpu(long cpu)
>  
>  	/* per cpu trace_pipe */
>  	trace_create_file("trace_pipe", 0444, d_cpu,
> -			(void *) cpu, &tracing_pipe_fops);
> +			(void *)&data->trace_cpu, &tracing_pipe_fops);
>  
>  	/* per cpu trace */
>  	trace_create_file("trace", 0644, d_cpu,
> -			(void *) cpu, &tracing_fops);
> +			(void *)&data->trace_cpu, &tracing_fops);
>  
>  	trace_create_file("trace_pipe_raw", 0444, d_cpu,
> -			(void *) cpu, &tracing_buffers_fops);
> +			(void *)&data->trace_cpu, &tracing_buffers_fops);
>  
>  	trace_create_file("stats", 0444, d_cpu,
> -			(void *) cpu, &tracing_stats_fops);
> +			(void *)&data->trace_cpu, &tracing_stats_fops);
>  
>  	trace_create_file("buffer_size_kb", 0444, d_cpu,
> -			(void *) cpu, &tracing_entries_fops);
> +			(void *)&data->trace_cpu, &tracing_entries_fops);
> +
> +#ifdef CONFIG_TRACER_SNAPSHOT
> +	trace_create_file("snapshot", 0644, d_cpu,
> +			  (void *)&data->trace_cpu, &snapshot_fops);
> +
> +	trace_create_file("snapshot_raw", 0444, d_cpu,
> +			(void *)&data->trace_cpu, &snapshot_raw_fops);
> +#endif
>  }
>  
>  #ifdef CONFIG_FTRACE_SELFTEST
> @@ -4725,6 +5360,7 @@ static void tracing_init_debugfs_percpu(long cpu)
>  struct trace_option_dentry {
>  	struct tracer_opt		*opt;
>  	struct tracer_flags		*flags;
> +	struct trace_array		*tr;
>  	struct dentry			*entry;
>  };
>  
> @@ -4760,7 +5396,7 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  
>  	if (!!(topt->flags->val & topt->opt->bit) != val) {
>  		mutex_lock(&trace_types_lock);
> -		ret = __set_tracer_option(current_trace, topt->flags,
> +		ret = __set_tracer_option(topt->tr->current_trace, topt->flags,
>  					  topt->opt, !val);
>  		mutex_unlock(&trace_types_lock);
>  		if (ret)
> @@ -4799,6 +5435,7 @@ static ssize_t
>  trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  			 loff_t *ppos)
>  {
> +	struct trace_array *tr = &global_trace;
>  	long index = (long)filp->private_data;
>  	unsigned long val;
>  	int ret;
> @@ -4811,7 +5448,7 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  		return -EINVAL;
>  
>  	mutex_lock(&trace_types_lock);
> -	ret = set_tracer_flag(1 << index, val);
> +	ret = set_tracer_flag(tr, 1 << index, val);
>  	mutex_unlock(&trace_types_lock);
>  
>  	if (ret < 0)
> @@ -4845,40 +5482,41 @@ struct dentry *trace_create_file(const char *name,
>  }
>  
> 
> -static struct dentry *trace_options_init_dentry(void)
> +static struct dentry *trace_options_init_dentry(struct trace_array *tr)
>  {
>  	struct dentry *d_tracer;
> -	static struct dentry *t_options;
>  
> -	if (t_options)
> -		return t_options;
> +	if (tr->options)
> +		return tr->options;
>  
> -	d_tracer = tracing_init_dentry();
> +	d_tracer = tracing_init_dentry_tr(tr);
>  	if (!d_tracer)
>  		return NULL;
>  
> -	t_options = debugfs_create_dir("options", d_tracer);
> -	if (!t_options) {
> +	tr->options = debugfs_create_dir("options", d_tracer);
> +	if (!tr->options) {
>  		pr_warning("Could not create debugfs directory 'options'\n");
>  		return NULL;
>  	}
>  
> -	return t_options;
> +	return tr->options;
>  }
>  
>  static void
> -create_trace_option_file(struct trace_option_dentry *topt,
> +create_trace_option_file(struct trace_array *tr,
> +			 struct trace_option_dentry *topt,
>  			 struct tracer_flags *flags,
>  			 struct tracer_opt *opt)
>  {
>  	struct dentry *t_options;
>  
> -	t_options = trace_options_init_dentry();
> +	t_options = trace_options_init_dentry(tr);
>  	if (!t_options)
>  		return;
>  
>  	topt->flags = flags;
>  	topt->opt = opt;
> +	topt->tr = tr;
>  
>  	topt->entry = trace_create_file(opt->name, 0644, t_options, topt,
>  				    &trace_options_fops);
> @@ -4886,7 +5524,7 @@ create_trace_option_file(struct trace_option_dentry *topt,
>  }
>  
>  static struct trace_option_dentry *
> -create_trace_option_files(struct tracer *tracer)
> +create_trace_option_files(struct trace_array *tr, struct tracer *tracer)
>  {
>  	struct trace_option_dentry *topts;
>  	struct tracer_flags *flags;
> @@ -4911,7 +5549,7 @@ create_trace_option_files(struct tracer *tracer)
>  		return NULL;
>  
>  	for (cnt = 0; opts[cnt].name; cnt++)
> -		create_trace_option_file(&topts[cnt], flags,
> +		create_trace_option_file(tr, &topts[cnt], flags,
>  					 &opts[cnt]);
>  
>  	return topts;
> @@ -4934,11 +5572,12 @@ destroy_trace_option_files(struct trace_option_dentry *topts)
>  }
>  
>  static struct dentry *
> -create_trace_option_core_file(const char *option, long index)
> +create_trace_option_core_file(struct trace_array *tr,
> +			      const char *option, long index)
>  {
>  	struct dentry *t_options;
>  
> -	t_options = trace_options_init_dentry();
> +	t_options = trace_options_init_dentry(tr);
>  	if (!t_options)
>  		return NULL;
>  
> @@ -4946,17 +5585,17 @@ create_trace_option_core_file(const char *option, long index)
>  				    &trace_options_core_fops);
>  }
>  
> -static __init void create_trace_options_dir(void)
> +static __init void create_trace_options_dir(struct trace_array *tr)
>  {
>  	struct dentry *t_options;
>  	int i;
>  
> -	t_options = trace_options_init_dentry();
> +	t_options = trace_options_init_dentry(tr);
>  	if (!t_options)
>  		return;
>  
>  	for (i = 0; trace_options[i]; i++)
> -		create_trace_option_core_file(trace_options[i], i);
> +		create_trace_option_core_file(tr, trace_options[i], i);
>  }
>  
>  static ssize_t
> @@ -4964,7 +5603,7 @@ rb_simple_read(struct file *filp, char __user *ubuf,
>  	       size_t cnt, loff_t *ppos)
>  {
>  	struct trace_array *tr = filp->private_data;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  	char buf[64];
>  	int r;
>  
> @@ -4983,7 +5622,7 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
>  		size_t cnt, loff_t *ppos)
>  {
>  	struct trace_array *tr = filp->private_data;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  	unsigned long val;
>  	int ret;
>  
> @@ -4995,12 +5634,12 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
>  		mutex_lock(&trace_types_lock);
>  		if (val) {
>  			ring_buffer_record_on(buffer);
> -			if (current_trace->start)
> -				current_trace->start(tr);
> +			if (tr->current_trace->start)
> +				tr->current_trace->start(tr);
>  		} else {
>  			ring_buffer_record_off(buffer);
> -			if (current_trace->stop)
> -				current_trace->stop(tr);
> +			if (tr->current_trace->stop)
> +				tr->current_trace->stop(tr);
>  		}
>  		mutex_unlock(&trace_types_lock);
>  	}
> @@ -5017,23 +5656,308 @@ static const struct file_operations rb_simple_fops = {
>  	.llseek		= default_llseek,
>  };
>  
> +struct dentry *trace_instance_dir;
> +
> +static void
> +init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer);
> +
> +static void init_trace_buffers(struct trace_array *tr, struct trace_buffer *buf)
> +{
> +	int cpu;
> +
> +	for_each_tracing_cpu(cpu) {
> +		memset(per_cpu_ptr(buf->data, cpu), 0, sizeof(struct trace_array_cpu));
> +		per_cpu_ptr(buf->data, cpu)->trace_cpu.cpu = cpu;
> +		per_cpu_ptr(buf->data, cpu)->trace_cpu.tr = tr;
> +	}
> +}
> +
> +static int
> +allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size)
> +{
> +	enum ring_buffer_flags rb_flags;
> +
> +	rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
> +
> +	buf->buffer = ring_buffer_alloc(size, rb_flags);
> +	if (!buf->buffer)
> +		return -ENOMEM;
> +
> +	buf->data = alloc_percpu(struct trace_array_cpu);
> +	if (!buf->data) {
> +		ring_buffer_free(buf->buffer);
> +		return -ENOMEM;
> +	}
> +
> +	init_trace_buffers(tr, buf);
> +
> +	/* Allocate the first page for all buffers */
> +	set_buffer_entries(&tr->trace_buffer,
> +			   ring_buffer_size(tr->trace_buffer.buffer, 0));
> +
> +	return 0;
> +}
> +
> +static int allocate_trace_buffers(struct trace_array *tr, int size)
> +{
> +	int ret;
> +
> +	ret = allocate_trace_buffer(tr, &tr->trace_buffer, size);
> +	if (ret)
> +		return ret;
> +
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	ret = allocate_trace_buffer(tr, &tr->max_buffer,
> +				    allocate_snapshot ? size : 1);
> +	if (WARN_ON(ret)) {
> +		ring_buffer_free(tr->trace_buffer.buffer);
> +		free_percpu(tr->trace_buffer.data);
> +		return -ENOMEM;
> +	}
> +	tr->allocated_snapshot = allocate_snapshot;
> +
> +	/*
> +	 * Only the top level trace array gets its snapshot allocated
> +	 * from the kernel command line.
> +	 */
> +	allocate_snapshot = false;
> +#endif
> +	return 0;
> +}
> +
> +static int new_instance_create(const char *name)
> +{
> +	struct trace_array *tr;
> +	int ret;
> +
> +	mutex_lock(&trace_types_lock);
> +
> +	ret = -EEXIST;
> +	list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> +		if (tr->name && strcmp(tr->name, name) == 0)
> +			goto out_unlock;
> +	}
> +
> +	ret = -ENOMEM;
> +	tr = kzalloc(sizeof(*tr), GFP_KERNEL);
> +	if (!tr)
> +		goto out_unlock;
> +
> +	tr->name = kstrdup(name, GFP_KERNEL);
> +	if (!tr->name)
> +		goto out_free_tr;
> +
> +	raw_spin_lock_init(&tr->start_lock);
> +
> +	tr->current_trace = &nop_trace;
> +
> +	INIT_LIST_HEAD(&tr->systems);
> +	INIT_LIST_HEAD(&tr->events);
> +
> +	if (allocate_trace_buffers(tr, trace_buf_size) < 0)
> +		goto out_free_tr;
> +
> +	/* Holder for file callbacks */
> +	tr->trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
> +	tr->trace_cpu.tr = tr;
> +
> +	tr->dir = debugfs_create_dir(name, trace_instance_dir);
> +	if (!tr->dir)
> +		goto out_free_tr;
> +
> +	ret = event_trace_add_tracer(tr->dir, tr);
> +	if (ret)
> +		goto out_free_tr;
> +
> +	init_tracer_debugfs(tr, tr->dir);
> +
> +	list_add(&tr->list, &ftrace_trace_arrays);
> +
> +	mutex_unlock(&trace_types_lock);
> +
> +	return 0;
> +
> + out_free_tr:
> +	if (tr->trace_buffer.buffer)
> +		ring_buffer_free(tr->trace_buffer.buffer);
> +	kfree(tr->name);
> +	kfree(tr);
> +
> + out_unlock:
> +	mutex_unlock(&trace_types_lock);
> +
> +	return ret;
> +
> +}
> +
> +static int instance_delete(const char *name)
> +{
> +	struct trace_array *tr;
> +	int found = 0;
> +	int ret;
> +
> +	mutex_lock(&trace_types_lock);
> +
> +	ret = -ENODEV;
> +	list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> +		if (tr->name && strcmp(tr->name, name) == 0) {
> +			found = 1;
> +			break;
> +		}
> +	}
> +	if (!found)
> +		goto out_unlock;
> +
> +	ret = -EBUSY;
> +	if (tr->ref)
> +		goto out_unlock;
> +
> +	list_del(&tr->list);
> +
> +	event_trace_del_tracer(tr);
> +	debugfs_remove_recursive(tr->dir);
> +	free_percpu(tr->trace_buffer.data);
> +	ring_buffer_free(tr->trace_buffer.buffer);
> +
> +	kfree(tr->name);
> +	kfree(tr);
> +
> +	ret = 0;
> +
> + out_unlock:
> +	mutex_unlock(&trace_types_lock);
> +
> +	return ret;
> +}
> +
> +static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode)
> +{
> +	struct dentry *parent;
> +	int ret;
> +
> +	/* Paranoid: Make sure the parent is the "instances" directory */
> +	parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
> +	if (WARN_ON_ONCE(parent != trace_instance_dir))
> +		return -ENOENT;
> +
> +	/*
> +	 * The inode mutex is locked, but debugfs_create_dir() will also
> +	 * take the mutex. As the instances directory can not be destroyed
> +	 * or changed in any other way, it is safe to unlock it, and
> +	 * let the dentry try. If two users try to make the same dir at
> +	 * the same time, then the new_instance_create() will determine the
> +	 * winner.
> +	 */
> +	mutex_unlock(&inode->i_mutex);
> +
> +	ret = new_instance_create(dentry->d_iname);
> +
> +	mutex_lock(&inode->i_mutex);
> +
> +	return ret;
> +}
> +
> +static int instance_rmdir(struct inode *inode, struct dentry *dentry)
> +{
> +	struct dentry *parent;
> +	int ret;
> +
> +	/* Paranoid: Make sure the parent is the "instances" directory */
> +	parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
> +	if (WARN_ON_ONCE(parent != trace_instance_dir))
> +		return -ENOENT;
> +
> +	/* The caller did a dget() on dentry */
> +	mutex_unlock(&dentry->d_inode->i_mutex);
> +
> +	/*
> +	 * The inode mutex is locked, but debugfs_create_dir() will also
> +	 * take the mutex. As the instances directory can not be destroyed
> +	 * or changed in any other way, it is safe to unlock it, and
> +	 * let the dentry try. If two users try to make the same dir at
> +	 * the same time, then the instance_delete() will determine the
> +	 * winner.
> +	 */
> +	mutex_unlock(&inode->i_mutex);
> +
> +	ret = instance_delete(dentry->d_iname);
> +
> +	mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
> +	mutex_lock(&dentry->d_inode->i_mutex);
> +
> +	return ret;
> +}
> +
> +static const struct inode_operations instance_dir_inode_operations = {
> +	.lookup		= simple_lookup,
> +	.mkdir		= instance_mkdir,
> +	.rmdir		= instance_rmdir,
> +};
> +
> +static __init void create_trace_instances(struct dentry *d_tracer)
> +{
> +	trace_instance_dir = debugfs_create_dir("instances", d_tracer);
> +	if (WARN_ON(!trace_instance_dir))
> +		return;
> +
> +	/* Hijack the dir inode operations, to allow mkdir */
> +	trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations;
> +}
> +
> +static void
> +init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
> +{
> +	int cpu;
> +
> +	trace_create_file("trace_options", 0644, d_tracer,
> +			  tr, &tracing_iter_fops);
> +
> +	trace_create_file("trace", 0644, d_tracer,
> +			(void *)&tr->trace_cpu, &tracing_fops);
> +
> +	trace_create_file("trace_pipe", 0444, d_tracer,
> +			(void *)&tr->trace_cpu, &tracing_pipe_fops);
> +
> +	trace_create_file("buffer_size_kb", 0644, d_tracer,
> +			(void *)&tr->trace_cpu, &tracing_entries_fops);
> +
> +	trace_create_file("buffer_total_size_kb", 0444, d_tracer,
> +			  tr, &tracing_total_entries_fops);
> +
> +	trace_create_file("free_buffer", 0644, d_tracer,
> +			  tr, &tracing_free_buffer_fops);
> +
> +	trace_create_file("trace_marker", 0220, d_tracer,
> +			  tr, &tracing_mark_fops);
> +
> +	trace_create_file("trace_clock", 0644, d_tracer, tr,
> +			  &trace_clock_fops);
> +
> +	trace_create_file("tracing_on", 0644, d_tracer,
> +			    tr, &rb_simple_fops);
> +
> +#ifdef CONFIG_TRACER_SNAPSHOT
> +	trace_create_file("snapshot", 0644, d_tracer,
> +			  (void *)&tr->trace_cpu, &snapshot_fops);
> +#endif
> +
> +	for_each_tracing_cpu(cpu)
> +		tracing_init_debugfs_percpu(tr, cpu);
> +
> +}
> +
>  static __init int tracer_init_debugfs(void)
>  {
>  	struct dentry *d_tracer;
> -	int cpu;
>  
>  	trace_access_lock_init();
>  
>  	d_tracer = tracing_init_dentry();
>  
> -	trace_create_file("trace_options", 0644, d_tracer,
> -			NULL, &tracing_iter_fops);
> +	init_tracer_debugfs(&global_trace, d_tracer);
>  
>  	trace_create_file("tracing_cpumask", 0644, d_tracer,
> -			NULL, &tracing_cpumask_fops);
> -
> -	trace_create_file("trace", 0644, d_tracer,
> -			(void *) TRACE_PIPE_ALL_CPU, &tracing_fops);
> +			&global_trace, &tracing_cpumask_fops);
>  
>  	trace_create_file("available_tracers", 0444, d_tracer,
>  			&global_trace, &show_traces_fops);
> @@ -5052,44 +5976,17 @@ static __init int tracer_init_debugfs(void)
>  	trace_create_file("README", 0444, d_tracer,
>  			NULL, &tracing_readme_fops);
>  
> -	trace_create_file("trace_pipe", 0444, d_tracer,
> -			(void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops);
> -
> -	trace_create_file("buffer_size_kb", 0644, d_tracer,
> -			(void *) RING_BUFFER_ALL_CPUS, &tracing_entries_fops);
> -
> -	trace_create_file("buffer_total_size_kb", 0444, d_tracer,
> -			&global_trace, &tracing_total_entries_fops);
> -
> -	trace_create_file("free_buffer", 0644, d_tracer,
> -			&global_trace, &tracing_free_buffer_fops);
> -
> -	trace_create_file("trace_marker", 0220, d_tracer,
> -			NULL, &tracing_mark_fops);
> -
>  	trace_create_file("saved_cmdlines", 0444, d_tracer,
>  			NULL, &tracing_saved_cmdlines_fops);
>  
> -	trace_create_file("trace_clock", 0644, d_tracer, NULL,
> -			  &trace_clock_fops);
> -
> -	trace_create_file("tracing_on", 0644, d_tracer,
> -			    &global_trace, &rb_simple_fops);
> -
>  #ifdef CONFIG_DYNAMIC_FTRACE
>  	trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
>  			&ftrace_update_tot_cnt, &tracing_dyn_info_fops);
>  #endif
>  
> -#ifdef CONFIG_TRACER_SNAPSHOT
> -	trace_create_file("snapshot", 0644, d_tracer,
> -			  (void *) TRACE_PIPE_ALL_CPU, &snapshot_fops);
> -#endif
> -
> -	create_trace_options_dir();
> +	create_trace_instances(d_tracer);
>  
> -	for_each_tracing_cpu(cpu)
> -		tracing_init_debugfs_percpu(cpu);
> +	create_trace_options_dir(&global_trace);
>  
>  	return 0;
>  }
> @@ -5145,8 +6042,8 @@ void
>  trace_printk_seq(struct trace_seq *s)
>  {
>  	/* Probably should print a warning here. */
> -	if (s->len >= 1000)
> -		s->len = 1000;
> +	if (s->len >= TRACE_MAX_PRINT)
> +		s->len = TRACE_MAX_PRINT;
>  
>  	/* should be zero ended, but we are paranoid. */
>  	s->buffer[s->len] = 0;
> @@ -5159,46 +6056,43 @@ trace_printk_seq(struct trace_seq *s)
>  void trace_init_global_iter(struct trace_iterator *iter)
>  {
>  	iter->tr = &global_trace;
> -	iter->trace = current_trace;
> -	iter->cpu_file = TRACE_PIPE_ALL_CPU;
> +	iter->trace = iter->tr->current_trace;
> +	iter->cpu_file = RING_BUFFER_ALL_CPUS;
> +	iter->trace_buffer = &global_trace.trace_buffer;
>  }
>  
> -static void
> -__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
> +void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
>  {
> -	static arch_spinlock_t ftrace_dump_lock =
> -		(arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
>  	/* use static because iter can be a bit big for the stack */
>  	static struct trace_iterator iter;
> +	static atomic_t dump_running;
>  	unsigned int old_userobj;
> -	static int dump_ran;
>  	unsigned long flags;
>  	int cnt = 0, cpu;
>  
> -	/* only one dump */
> -	local_irq_save(flags);
> -	arch_spin_lock(&ftrace_dump_lock);
> -	if (dump_ran)
> -		goto out;
> -
> -	dump_ran = 1;
> +	/* Only allow one dump user at a time. */
> +	if (atomic_inc_return(&dump_running) != 1) {
> +		atomic_dec(&dump_running);
> +		return;
> +	}
>  
> +	/*
> +	 * Always turn off tracing when we dump.
> +	 * We don't need to show trace output of what happens
> +	 * between multiple crashes.
> +	 *
> +	 * If the user does a sysrq-z, then they can re-enable
> +	 * tracing with echo 1 > tracing_on.
> +	 */
>  	tracing_off();
>  
> -	/* Did function tracer already get disabled? */
> -	if (ftrace_is_dead()) {
> -		printk("# WARNING: FUNCTION TRACING IS CORRUPTED\n");
> -		printk("#          MAY BE MISSING FUNCTION EVENTS\n");
> -	}
> -
> -	if (disable_tracing)
> -		ftrace_kill();
> +	local_irq_save(flags);
>  
>  	/* Simulate the iterator */
>  	trace_init_global_iter(&iter);
>  
>  	for_each_tracing_cpu(cpu) {
> -		atomic_inc(&iter.tr->data[cpu]->disabled);
> +		atomic_inc(&per_cpu_ptr(iter.tr->trace_buffer.data, cpu)->disabled);
>  	}
>  
>  	old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ;
> @@ -5208,7 +6102,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
>  
>  	switch (oops_dump_mode) {
>  	case DUMP_ALL:
> -		iter.cpu_file = TRACE_PIPE_ALL_CPU;
> +		iter.cpu_file = RING_BUFFER_ALL_CPUS;
>  		break;
>  	case DUMP_ORIG:
>  		iter.cpu_file = raw_smp_processor_id();
> @@ -5217,11 +6111,17 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
>  		goto out_enable;
>  	default:
>  		printk(KERN_TRACE "Bad dumping mode, switching to all CPUs dump\n");
> -		iter.cpu_file = TRACE_PIPE_ALL_CPU;
> +		iter.cpu_file = RING_BUFFER_ALL_CPUS;
>  	}
>  
>  	printk(KERN_TRACE "Dumping ftrace buffer:\n");
>  
> +	/* Did function tracer already get disabled? */
> +	if (ftrace_is_dead()) {
> +		printk("# WARNING: FUNCTION TRACING IS CORRUPTED\n");
> +		printk("#          MAY BE MISSING FUNCTION EVENTS\n");
> +	}
> +
>  	/*
>  	 * We need to stop all tracing on all CPUS to read the
>  	 * the next buffer. This is a bit expensive, but is
> @@ -5261,33 +6161,19 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
>  		printk(KERN_TRACE "---------------------------------\n");
>  
>   out_enable:
> -	/* Re-enable tracing if requested */
> -	if (!disable_tracing) {
> -		trace_flags |= old_userobj;
> +	trace_flags |= old_userobj;
>  
> -		for_each_tracing_cpu(cpu) {
> -			atomic_dec(&iter.tr->data[cpu]->disabled);
> -		}
> -		tracing_on();
> +	for_each_tracing_cpu(cpu) {
> +		atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
>  	}
> -
> - out:
> -	arch_spin_unlock(&ftrace_dump_lock);
> + 	atomic_dec(&dump_running);
>  	local_irq_restore(flags);
>  }
> -
> -/* By default: disable tracing after the dump */
> -void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
> -{
> -	__ftrace_dump(true, oops_dump_mode);
> -}
>  EXPORT_SYMBOL_GPL(ftrace_dump);
>  
>  __init static int tracer_alloc_buffers(void)
>  {
>  	int ring_buf_size;
> -	enum ring_buffer_flags rb_flags;
> -	int i;
>  	int ret = -ENOMEM;
>  
> 
> @@ -5308,49 +6194,27 @@ __init static int tracer_alloc_buffers(void)
>  	else
>  		ring_buf_size = 1;
>  
> -	rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
> -
>  	cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
>  	cpumask_copy(tracing_cpumask, cpu_all_mask);
>  
> +	raw_spin_lock_init(&global_trace.start_lock);
> +
>  	/* TODO: make the number of buffers hot pluggable with CPUS */
> -	global_trace.buffer = ring_buffer_alloc(ring_buf_size, rb_flags);
> -	if (!global_trace.buffer) {
> +	if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) {
>  		printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
>  		WARN_ON(1);
>  		goto out_free_cpumask;
>  	}
> +
>  	if (global_trace.buffer_disabled)
>  		tracing_off();
>  
> -
> -#ifdef CONFIG_TRACER_MAX_TRACE
> -	max_tr.buffer = ring_buffer_alloc(1, rb_flags);
> -	if (!max_tr.buffer) {
> -		printk(KERN_ERR "tracer: failed to allocate max ring buffer!\n");
> -		WARN_ON(1);
> -		ring_buffer_free(global_trace.buffer);
> -		goto out_free_cpumask;
> -	}
> -#endif
> -
> -	/* Allocate the first page for all buffers */
> -	for_each_tracing_cpu(i) {
> -		global_trace.data[i] = &per_cpu(global_trace_cpu, i);
> -		max_tr.data[i] = &per_cpu(max_tr_data, i);
> -	}
> -
> -	set_buffer_entries(&global_trace,
> -			   ring_buffer_size(global_trace.buffer, 0));
> -#ifdef CONFIG_TRACER_MAX_TRACE
> -	set_buffer_entries(&max_tr, 1);
> -#endif
> -
>  	trace_init_cmdlines();
> -	init_irq_work(&trace_work_wakeup, trace_wake_up);
>  
>  	register_tracer(&nop_trace);
>  
> +	global_trace.current_trace = &nop_trace;
> +
>  	/* All seems OK, enable tracing */
>  	tracing_disabled = 0;
>  
> @@ -5359,16 +6223,32 @@ __init static int tracer_alloc_buffers(void)
>  
>  	register_die_notifier(&trace_die_notifier);
>  
> +	global_trace.flags = TRACE_ARRAY_FL_GLOBAL;
> +
> +	/* Holder for file callbacks */
> +	global_trace.trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
> +	global_trace.trace_cpu.tr = &global_trace;
> +
> +	INIT_LIST_HEAD(&global_trace.systems);
> +	INIT_LIST_HEAD(&global_trace.events);
> +	list_add(&global_trace.list, &ftrace_trace_arrays);
> +
>  	while (trace_boot_options) {
>  		char *option;
>  
>  		option = strsep(&trace_boot_options, ",");
> -		trace_set_options(option);
> +		trace_set_options(&global_trace, option);
>  	}
>  
> +	register_snapshot_cmd();
> +
>  	return 0;
>  
>  out_free_cpumask:
> +	free_percpu(global_trace.trace_buffer.data);
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	free_percpu(global_trace.max_buffer.data);
> +#endif
>  	free_cpumask_var(tracing_cpumask);
>  out_free_buffer_mask:
>  	free_cpumask_var(tracing_buffer_mask);
> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
> index 2081971..9e01458 100644
> --- a/kernel/trace/trace.h
> +++ b/kernel/trace/trace.h
> @@ -13,6 +13,11 @@
>  #include <linux/trace_seq.h>
>  #include <linux/ftrace_event.h>
>  
> +#ifdef CONFIG_FTRACE_SYSCALLS
> +#include <asm/unistd.h>		/* For NR_SYSCALLS	     */
> +#include <asm/syscall.h>	/* some archs define it here */
> +#endif
> +
>  enum trace_type {
>  	__TRACE_FIRST_TYPE = 0,
>  
> @@ -29,6 +34,7 @@ enum trace_type {
>  	TRACE_GRAPH_ENT,
>  	TRACE_USER_STACK,
>  	TRACE_BLK,
> +	TRACE_BPUTS,
>  
>  	__TRACE_LAST_TYPE,
>  };
> @@ -127,12 +133,21 @@ enum trace_flag_type {
>  
>  #define TRACE_BUF_SIZE		1024
>  
> +struct trace_array;
> +
> +struct trace_cpu {
> +	struct trace_array	*tr;
> +	struct dentry		*dir;
> +	int			cpu;
> +};
> +
>  /*
>   * The CPU trace array - it consists of thousands of trace entries
>   * plus some other descriptor data: (for example which task started
>   * the trace, etc.)
>   */
>  struct trace_array_cpu {
> +	struct trace_cpu	trace_cpu;
>  	atomic_t		disabled;
>  	void			*buffer_page;	/* ring buffer spare */
>  
> @@ -151,20 +166,83 @@ struct trace_array_cpu {
>  	char			comm[TASK_COMM_LEN];
>  };
>  
> +struct tracer;
> +
> +struct trace_buffer {
> +	struct trace_array		*tr;
> +	struct ring_buffer		*buffer;
> +	struct trace_array_cpu __percpu	*data;
> +	cycle_t				time_start;
> +	int				cpu;
> +};
> +
>  /*
>   * The trace array - an array of per-CPU trace arrays. This is the
>   * highest level data structure that individual tracers deal with.
>   * They have on/off state as well:
>   */
>  struct trace_array {
> -	struct ring_buffer	*buffer;
> -	int			cpu;
> +	struct list_head	list;
> +	char			*name;
> +	struct trace_buffer	trace_buffer;
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	/*
> +	 * The max_buffer is used to snapshot the trace when a maximum
> +	 * latency is reached, or when the user initiates a snapshot.
> +	 * Some tracers will use this to store a maximum trace while
> +	 * it continues examining live traces.
> +	 *
> +	 * The buffers for the max_buffer are set up the same as the trace_buffer
> +	 * When a snapshot is taken, the buffer of the max_buffer is swapped
> +	 * with the buffer of the trace_buffer and the buffers are reset for
> +	 * the trace_buffer so the tracing can continue.
> +	 */
> +	struct trace_buffer	max_buffer;
> +	bool			allocated_snapshot;
> +#endif
>  	int			buffer_disabled;
> -	cycle_t			time_start;
> +	struct trace_cpu	trace_cpu;	/* place holder */
> +#ifdef CONFIG_FTRACE_SYSCALLS
> +	int			sys_refcount_enter;
> +	int			sys_refcount_exit;
> +	DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
> +	DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
> +#endif
> +	int			stop_count;
> +	int			clock_id;
> +	struct tracer		*current_trace;
> +	unsigned int		flags;
> +	raw_spinlock_t		start_lock;
> +	struct dentry		*dir;
> +	struct dentry		*options;
> +	struct dentry		*percpu_dir;
> +	struct dentry		*event_dir;
> +	struct list_head	systems;
> +	struct list_head	events;
>  	struct task_struct	*waiter;
> -	struct trace_array_cpu	*data[NR_CPUS];
> +	int			ref;
>  };
>  
> +enum {
> +	TRACE_ARRAY_FL_GLOBAL	= (1 << 0)
> +};
> +
> +extern struct list_head ftrace_trace_arrays;
> +
> +/*
> + * The global tracer (top) should be the first trace array added,
> + * but we check the flag anyway.
> + */
> +static inline struct trace_array *top_trace_array(void)
> +{
> +	struct trace_array *tr;
> +
> +	tr = list_entry(ftrace_trace_arrays.prev,
> +			typeof(*tr), list);
> +	WARN_ON(!(tr->flags & TRACE_ARRAY_FL_GLOBAL));
> +	return tr;
> +}
> +
>  #define FTRACE_CMP_TYPE(var, type) \
>  	__builtin_types_compatible_p(typeof(var), type *)
>  
> @@ -200,6 +278,7 @@ extern void __ftrace_bad_type(void);
>  		IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
>  		IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT);	\
>  		IF_ASSIGN(var, ent, struct bprint_entry, TRACE_BPRINT);	\
> +		IF_ASSIGN(var, ent, struct bputs_entry, TRACE_BPUTS);	\
>  		IF_ASSIGN(var, ent, struct trace_mmiotrace_rw,		\
>  			  TRACE_MMIO_RW);				\
>  		IF_ASSIGN(var, ent, struct trace_mmiotrace_map,		\
> @@ -289,9 +368,10 @@ struct tracer {
>  	struct tracer		*next;
>  	struct tracer_flags	*flags;
>  	bool			print_max;
> -	bool			use_max_tr;
> -	bool			allocated_snapshot;
>  	bool			enabled;
> +#ifdef CONFIG_TRACER_MAX_TRACE
> +	bool			use_max_tr;
> +#endif
>  };
>  
> 
> @@ -427,8 +507,6 @@ static __always_inline void trace_clear_recursion(int bit)
>  	current->trace_recursion = val;
>  }
>  
> -#define TRACE_PIPE_ALL_CPU	-1
> -
>  static inline struct ring_buffer_iter *
>  trace_buffer_iter(struct trace_iterator *iter, int cpu)
>  {
> @@ -439,10 +517,10 @@ trace_buffer_iter(struct trace_iterator *iter, int cpu)
>  
>  int tracer_init(struct tracer *t, struct trace_array *tr);
>  int tracing_is_enabled(void);
> -void tracing_reset(struct trace_array *tr, int cpu);
> -void tracing_reset_online_cpus(struct trace_array *tr);
> +void tracing_reset(struct trace_buffer *buf, int cpu);
> +void tracing_reset_online_cpus(struct trace_buffer *buf);
>  void tracing_reset_current(int cpu);
> -void tracing_reset_current_online_cpus(void);
> +void tracing_reset_all_online_cpus(void);
>  int tracing_open_generic(struct inode *inode, struct file *filp);
>  struct dentry *trace_create_file(const char *name,
>  				 umode_t mode,
> @@ -450,6 +528,7 @@ struct dentry *trace_create_file(const char *name,
>  				 void *data,
>  				 const struct file_operations *fops);
>  
> +struct dentry *tracing_init_dentry_tr(struct trace_array *tr);
>  struct dentry *tracing_init_dentry(void);
>  
>  struct ring_buffer_event;
> @@ -583,7 +662,7 @@ extern int DYN_FTRACE_TEST_NAME(void);
>  #define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
>  extern int DYN_FTRACE_TEST_NAME2(void);
>  
> -extern int ring_buffer_expanded;
> +extern bool ring_buffer_expanded;
>  extern bool tracing_selftest_disabled;
>  DECLARE_PER_CPU(int, ftrace_cpu_disabled);
>  
> @@ -619,6 +698,8 @@ trace_array_vprintk(struct trace_array *tr,
>  		    unsigned long ip, const char *fmt, va_list args);
>  int trace_array_printk(struct trace_array *tr,
>  		       unsigned long ip, const char *fmt, ...);
> +int trace_array_printk_buf(struct ring_buffer *buffer,
> +			   unsigned long ip, const char *fmt, ...);
>  void trace_printk_seq(struct trace_seq *s);
>  enum print_line_t print_trace_line(struct trace_iterator *iter);
>  
> @@ -786,6 +867,7 @@ enum trace_iterator_flags {
>  	TRACE_ITER_STOP_ON_FREE		= 0x400000,
>  	TRACE_ITER_IRQ_INFO		= 0x800000,
>  	TRACE_ITER_MARKERS		= 0x1000000,
> +	TRACE_ITER_FUNCTION		= 0x2000000,
>  };
>  
>  /*
> @@ -832,8 +914,8 @@ enum {
>  
>  struct ftrace_event_field {
>  	struct list_head	link;
> -	char			*name;
> -	char			*type;
> +	const char		*name;
> +	const char		*type;
>  	int			filter_type;
>  	int			offset;
>  	int			size;
> @@ -851,12 +933,19 @@ struct event_filter {
>  struct event_subsystem {
>  	struct list_head	list;
>  	const char		*name;
> -	struct dentry		*entry;
>  	struct event_filter	*filter;
> -	int			nr_events;
>  	int			ref_count;
>  };
>  
> +struct ftrace_subsystem_dir {
> +	struct list_head		list;
> +	struct event_subsystem		*subsystem;
> +	struct trace_array		*tr;
> +	struct dentry			*entry;
> +	int				ref_count;
> +	int				nr_events;
> +};
> +
>  #define FILTER_PRED_INVALID	((unsigned short)-1)
>  #define FILTER_PRED_IS_RIGHT	(1 << 15)
>  #define FILTER_PRED_FOLD	(1 << 15)
> @@ -906,22 +995,20 @@ struct filter_pred {
>  	unsigned short		right;
>  };
>  
> -extern struct list_head ftrace_common_fields;
> -
>  extern enum regex_type
>  filter_parse_regex(char *buff, int len, char **search, int *not);
>  extern void print_event_filter(struct ftrace_event_call *call,
>  			       struct trace_seq *s);
>  extern int apply_event_filter(struct ftrace_event_call *call,
>  			      char *filter_string);
> -extern int apply_subsystem_event_filter(struct event_subsystem *system,
> +extern int apply_subsystem_event_filter(struct ftrace_subsystem_dir *dir,
>  					char *filter_string);
>  extern void print_subsystem_event_filter(struct event_subsystem *system,
>  					 struct trace_seq *s);
>  extern int filter_assign_type(const char *type);
>  
> -struct list_head *
> -trace_get_fields(struct ftrace_event_call *event_call);
> +struct ftrace_event_field *
> +trace_find_event_field(struct ftrace_event_call *call, char *name);
>  
>  static inline int
>  filter_check_discard(struct ftrace_event_call *call, void *rec,
> @@ -938,6 +1025,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
>  }
>  
>  extern void trace_event_enable_cmd_record(bool enable);
> +extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
> +extern int event_trace_del_tracer(struct trace_array *tr);
>  
>  extern struct mutex event_mutex;
>  extern struct list_head ftrace_events;
> @@ -948,7 +1037,18 @@ extern const char *__stop___trace_bprintk_fmt[];
>  void trace_printk_init_buffers(void);
>  void trace_printk_start_comm(void);
>  int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
> -int set_tracer_flag(unsigned int mask, int enabled);
> +int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled);
> +
> +/*
> + * Normal trace_printk() and friends allocates special buffers
> + * to do the manipulation, as well as saves the print formats
> + * into sections to display. But the trace infrastructure wants
> + * to use these without the added overhead at the price of being
> + * a bit slower (used mainly for warnings, where we don't care
> + * about performance). The internal_trace_puts() is for such
> + * a purpose.
> + */
> +#define internal_trace_puts(str) __trace_puts(_THIS_IP_, str, strlen(str))
>  
>  #undef FTRACE_ENTRY
>  #define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter)	\
> diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
> index 95e9684..d594da0 100644
> --- a/kernel/trace/trace_branch.c
> +++ b/kernel/trace/trace_branch.c
> @@ -32,6 +32,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
>  {
>  	struct ftrace_event_call *call = &event_branch;
>  	struct trace_array *tr = branch_tracer;
> +	struct trace_array_cpu *data;
>  	struct ring_buffer_event *event;
>  	struct trace_branch *entry;
>  	struct ring_buffer *buffer;
> @@ -51,11 +52,12 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
>  
>  	local_irq_save(flags);
>  	cpu = raw_smp_processor_id();
> -	if (atomic_inc_return(&tr->data[cpu]->disabled) != 1)
> +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
> +	if (atomic_inc_return(&data->disabled) != 1)
>  		goto out;
>  
>  	pc = preempt_count();
> -	buffer = tr->buffer;
> +	buffer = tr->trace_buffer.buffer;
>  	event = trace_buffer_lock_reserve(buffer, TRACE_BRANCH,
>  					  sizeof(*entry), flags, pc);
>  	if (!event)
> @@ -80,7 +82,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
>  		__buffer_unlock_commit(buffer, event);
>  
>   out:
> -	atomic_dec(&tr->data[cpu]->disabled);
> +	atomic_dec(&data->disabled);
>  	local_irq_restore(flags);
>  }
>  
> diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c
> index aa8f5f4..26dc348 100644
> --- a/kernel/trace/trace_clock.c
> +++ b/kernel/trace/trace_clock.c
> @@ -57,6 +57,16 @@ u64 notrace trace_clock(void)
>  	return local_clock();
>  }
>  
> +/*
> + * trace_jiffy_clock(): Simply use jiffies as a clock counter.
> + */
> +u64 notrace trace_clock_jiffies(void)
> +{
> +	u64 jiffy = jiffies - INITIAL_JIFFIES;
> +
> +	/* Return nsecs */
> +	return (u64)jiffies_to_usecs(jiffy) * 1000ULL;
> +}
>  
>  /*
>   * trace_clock_global(): special globally coherent trace clock
> diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
> index 4108e12..e2d027a 100644
> --- a/kernel/trace/trace_entries.h
> +++ b/kernel/trace/trace_entries.h
> @@ -223,8 +223,8 @@ FTRACE_ENTRY(bprint, bprint_entry,
>  		__dynamic_array(	u32,	buf	)
>  	),
>  
> -	F_printk("%08lx fmt:%p",
> -		 __entry->ip, __entry->fmt),
> +	F_printk("%pf: %s",
> +		 (void *)__entry->ip, __entry->fmt),
>  
>  	FILTER_OTHER
>  );
> @@ -238,8 +238,23 @@ FTRACE_ENTRY(print, print_entry,
>  		__dynamic_array(	char,	buf	)
>  	),
>  
> -	F_printk("%08lx %s",
> -		 __entry->ip, __entry->buf),
> +	F_printk("%pf: %s",
> +		 (void *)__entry->ip, __entry->buf),
> +
> +	FILTER_OTHER
> +);
> +
> +FTRACE_ENTRY(bputs, bputs_entry,
> +
> +	TRACE_BPUTS,
> +
> +	F_STRUCT(
> +		__field(	unsigned long,	ip	)
> +		__field(	const char *,	str	)
> +	),
> +
> +	F_printk("%pf: %s",
> +		 (void *)__entry->ip, __entry->str),
>  
>  	FILTER_OTHER
>  );
> diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
> index 57e9b28..53582e9 100644
> --- a/kernel/trace/trace_events.c
> +++ b/kernel/trace/trace_events.c
> @@ -34,9 +34,27 @@ char event_storage[EVENT_STORAGE_SIZE];
>  EXPORT_SYMBOL_GPL(event_storage);
>  
>  LIST_HEAD(ftrace_events);
> -LIST_HEAD(ftrace_common_fields);
> +static LIST_HEAD(ftrace_common_fields);
>  
> -struct list_head *
> +#define GFP_TRACE (GFP_KERNEL | __GFP_ZERO)
> +
> +static struct kmem_cache *field_cachep;
> +static struct kmem_cache *file_cachep;
> +
> +/* Double loops, do not use break, only goto's work */
> +#define do_for_each_event_file(tr, file)			\
> +	list_for_each_entry(tr, &ftrace_trace_arrays, list) {	\
> +		list_for_each_entry(file, &tr->events, list)
> +
> +#define do_for_each_event_file_safe(tr, file)			\
> +	list_for_each_entry(tr, &ftrace_trace_arrays, list) {	\
> +		struct ftrace_event_file *___n;				\
> +		list_for_each_entry_safe(file, ___n, &tr->events, list)
> +
> +#define while_for_each_event_file()		\
> +	}
> +
> +static struct list_head *
>  trace_get_fields(struct ftrace_event_call *event_call)
>  {
>  	if (!event_call->class->get_fields)
> @@ -44,23 +62,45 @@ trace_get_fields(struct ftrace_event_call *event_call)
>  	return event_call->class->get_fields(event_call);
>  }
>  
> +static struct ftrace_event_field *
> +__find_event_field(struct list_head *head, char *name)
> +{
> +	struct ftrace_event_field *field;
> +
> +	list_for_each_entry(field, head, link) {
> +		if (!strcmp(field->name, name))
> +			return field;
> +	}
> +
> +	return NULL;
> +}
> +
> +struct ftrace_event_field *
> +trace_find_event_field(struct ftrace_event_call *call, char *name)
> +{
> +	struct ftrace_event_field *field;
> +	struct list_head *head;
> +
> +	field = __find_event_field(&ftrace_common_fields, name);
> +	if (field)
> +		return field;
> +
> +	head = trace_get_fields(call);
> +	return __find_event_field(head, name);
> +}
> +
>  static int __trace_define_field(struct list_head *head, const char *type,
>  				const char *name, int offset, int size,
>  				int is_signed, int filter_type)
>  {
>  	struct ftrace_event_field *field;
>  
> -	field = kzalloc(sizeof(*field), GFP_KERNEL);
> +	field = kmem_cache_alloc(field_cachep, GFP_TRACE);
>  	if (!field)
>  		goto err;
>  
> -	field->name = kstrdup(name, GFP_KERNEL);
> -	if (!field->name)
> -		goto err;
> -
> -	field->type = kstrdup(type, GFP_KERNEL);
> -	if (!field->type)
> -		goto err;
> +	field->name = name;
> +	field->type = type;
>  
>  	if (filter_type == FILTER_OTHER)
>  		field->filter_type = filter_assign_type(type);
> @@ -76,9 +116,7 @@ static int __trace_define_field(struct list_head *head, const char *type,
>  	return 0;
>  
>  err:
> -	if (field)
> -		kfree(field->name);
> -	kfree(field);
> +	kmem_cache_free(field_cachep, field);
>  
>  	return -ENOMEM;
>  }
> @@ -120,7 +158,7 @@ static int trace_define_common_fields(void)
>  	return ret;
>  }
>  
> -void trace_destroy_fields(struct ftrace_event_call *call)
> +static void trace_destroy_fields(struct ftrace_event_call *call)
>  {
>  	struct ftrace_event_field *field, *next;
>  	struct list_head *head;
> @@ -128,9 +166,7 @@ void trace_destroy_fields(struct ftrace_event_call *call)
>  	head = trace_get_fields(call);
>  	list_for_each_entry_safe(field, next, head, link) {
>  		list_del(&field->link);
> -		kfree(field->type);
> -		kfree(field->name);
> -		kfree(field);
> +		kmem_cache_free(field_cachep, field);
>  	}
>  }
>  
> @@ -149,15 +185,17 @@ EXPORT_SYMBOL_GPL(trace_event_raw_init);
>  int ftrace_event_reg(struct ftrace_event_call *call,
>  		     enum trace_reg type, void *data)
>  {
> +	struct ftrace_event_file *file = data;
> +
>  	switch (type) {
>  	case TRACE_REG_REGISTER:
>  		return tracepoint_probe_register(call->name,
>  						 call->class->probe,
> -						 call);
> +						 file);
>  	case TRACE_REG_UNREGISTER:
>  		tracepoint_probe_unregister(call->name,
>  					    call->class->probe,
> -					    call);
> +					    file);
>  		return 0;
>  
>  #ifdef CONFIG_PERF_EVENTS
> @@ -183,54 +221,100 @@ EXPORT_SYMBOL_GPL(ftrace_event_reg);
>  
>  void trace_event_enable_cmd_record(bool enable)
>  {
> -	struct ftrace_event_call *call;
> +	struct ftrace_event_file *file;
> +	struct trace_array *tr;
>  
>  	mutex_lock(&event_mutex);
> -	list_for_each_entry(call, &ftrace_events, list) {
> -		if (!(call->flags & TRACE_EVENT_FL_ENABLED))
> +	do_for_each_event_file(tr, file) {
> +
> +		if (!(file->flags & FTRACE_EVENT_FL_ENABLED))
>  			continue;
>  
>  		if (enable) {
>  			tracing_start_cmdline_record();
> -			call->flags |= TRACE_EVENT_FL_RECORDED_CMD;
> +			set_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
>  		} else {
>  			tracing_stop_cmdline_record();
> -			call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD;
> +			clear_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
>  		}
> -	}
> +	} while_for_each_event_file();
>  	mutex_unlock(&event_mutex);
>  }
>  
> -static int ftrace_event_enable_disable(struct ftrace_event_call *call,
> -					int enable)
> +static int __ftrace_event_enable_disable(struct ftrace_event_file *file,
> +					 int enable, int soft_disable)
>  {
> +	struct ftrace_event_call *call = file->event_call;
>  	int ret = 0;
> +	int disable;
>  
>  	switch (enable) {
>  	case 0:
> -		if (call->flags & TRACE_EVENT_FL_ENABLED) {
> -			call->flags &= ~TRACE_EVENT_FL_ENABLED;
> -			if (call->flags & TRACE_EVENT_FL_RECORDED_CMD) {
> +		/*
> +		 * When soft_disable is set and enable is cleared, we want
> +		 * to clear the SOFT_DISABLED flag but leave the event in the
> +		 * state that it was. That is, if the event was enabled and
> +		 * SOFT_DISABLED isn't set, then do nothing. But if SOFT_DISABLED
> +		 * is set we do not want the event to be enabled before we
> +		 * clear the bit.
> +		 *
> +		 * When soft_disable is not set but the SOFT_MODE flag is,
> +		 * we do nothing. Do not disable the tracepoint, otherwise
> +		 * "soft enable"s (clearing the SOFT_DISABLED bit) wont work.
> +		 */
> +		if (soft_disable) {
> +			disable = file->flags & FTRACE_EVENT_FL_SOFT_DISABLED;
> +			clear_bit(FTRACE_EVENT_FL_SOFT_MODE_BIT, &file->flags);
> +		} else
> +			disable = !(file->flags & FTRACE_EVENT_FL_SOFT_MODE);
> +
> +		if (disable && (file->flags & FTRACE_EVENT_FL_ENABLED)) {
> +			clear_bit(FTRACE_EVENT_FL_ENABLED_BIT, &file->flags);
> +			if (file->flags & FTRACE_EVENT_FL_RECORDED_CMD) {
>  				tracing_stop_cmdline_record();
> -				call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD;
> +				clear_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
>  			}
> -			call->class->reg(call, TRACE_REG_UNREGISTER, NULL);
> +			call->class->reg(call, TRACE_REG_UNREGISTER, file);
>  		}
> +		/* If in SOFT_MODE, just set the SOFT_DISABLE_BIT */
> +		if (file->flags & FTRACE_EVENT_FL_SOFT_MODE)
> +			set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
>  		break;
>  	case 1:
> -		if (!(call->flags & TRACE_EVENT_FL_ENABLED)) {
> +		/*
> +		 * When soft_disable is set and enable is set, we want to
> +		 * register the tracepoint for the event, but leave the event
> +		 * as is. That means, if the event was already enabled, we do
> +		 * nothing (but set SOFT_MODE). If the event is disabled, we
> +		 * set SOFT_DISABLED before enabling the event tracepoint, so
> +		 * it still seems to be disabled.
> +		 */
> +		if (!soft_disable)
> +			clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
> +		else
> +			set_bit(FTRACE_EVENT_FL_SOFT_MODE_BIT, &file->flags);
> +
> +		if (!(file->flags & FTRACE_EVENT_FL_ENABLED)) {
> +
> +			/* Keep the event disabled, when going to SOFT_MODE. */
> +			if (soft_disable)
> +				set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
> +
>  			if (trace_flags & TRACE_ITER_RECORD_CMD) {
>  				tracing_start_cmdline_record();
> -				call->flags |= TRACE_EVENT_FL_RECORDED_CMD;
> +				set_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
>  			}
> -			ret = call->class->reg(call, TRACE_REG_REGISTER, NULL);
> +			ret = call->class->reg(call, TRACE_REG_REGISTER, file);
>  			if (ret) {
>  				tracing_stop_cmdline_record();
>  				pr_info("event trace: Could not enable event "
>  					"%s\n", call->name);
>  				break;
>  			}
> -			call->flags |= TRACE_EVENT_FL_ENABLED;
> +			set_bit(FTRACE_EVENT_FL_ENABLED_BIT, &file->flags);
> +
> +			/* WAS_ENABLED gets set but never cleared. */
> +			call->flags |= TRACE_EVENT_FL_WAS_ENABLED;
>  		}
>  		break;
>  	}
> @@ -238,13 +322,19 @@ static int ftrace_event_enable_disable(struct ftrace_event_call *call,
>  	return ret;
>  }
>  
> -static void ftrace_clear_events(void)
> +static int ftrace_event_enable_disable(struct ftrace_event_file *file,
> +				       int enable)
>  {
> -	struct ftrace_event_call *call;
> +	return __ftrace_event_enable_disable(file, enable, 0);
> +}
> +
> +static void ftrace_clear_events(struct trace_array *tr)
> +{
> +	struct ftrace_event_file *file;
>  
>  	mutex_lock(&event_mutex);
> -	list_for_each_entry(call, &ftrace_events, list) {
> -		ftrace_event_enable_disable(call, 0);
> +	list_for_each_entry(file, &tr->events, list) {
> +		ftrace_event_enable_disable(file, 0);
>  	}
>  	mutex_unlock(&event_mutex);
>  }
> @@ -257,11 +347,12 @@ static void __put_system(struct event_subsystem *system)
>  	if (--system->ref_count)
>  		return;
>  
> +	list_del(&system->list);
> +
>  	if (filter) {
>  		kfree(filter->filter_string);
>  		kfree(filter);
>  	}
> -	kfree(system->name);
>  	kfree(system);
>  }
>  
> @@ -271,24 +362,45 @@ static void __get_system(struct event_subsystem *system)
>  	system->ref_count++;
>  }
>  
> -static void put_system(struct event_subsystem *system)
> +static void __get_system_dir(struct ftrace_subsystem_dir *dir)
> +{
> +	WARN_ON_ONCE(dir->ref_count == 0);
> +	dir->ref_count++;
> +	__get_system(dir->subsystem);
> +}
> +
> +static void __put_system_dir(struct ftrace_subsystem_dir *dir)
> +{
> +	WARN_ON_ONCE(dir->ref_count == 0);
> +	/* If the subsystem is about to be freed, the dir must be too */
> +	WARN_ON_ONCE(dir->subsystem->ref_count == 1 && dir->ref_count != 1);
> +
> +	__put_system(dir->subsystem);
> +	if (!--dir->ref_count)
> +		kfree(dir);
> +}
> +
> +static void put_system(struct ftrace_subsystem_dir *dir)
>  {
>  	mutex_lock(&event_mutex);
> -	__put_system(system);
> +	__put_system_dir(dir);
>  	mutex_unlock(&event_mutex);
>  }
>  
>  /*
>   * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events.
>   */
> -static int __ftrace_set_clr_event(const char *match, const char *sub,
> -				  const char *event, int set)
> +static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
> +				  const char *sub, const char *event, int set)
>  {
> +	struct ftrace_event_file *file;
>  	struct ftrace_event_call *call;
>  	int ret = -EINVAL;
>  
>  	mutex_lock(&event_mutex);
> -	list_for_each_entry(call, &ftrace_events, list) {
> +	list_for_each_entry(file, &tr->events, list) {
> +
> +		call = file->event_call;
>  
>  		if (!call->name || !call->class || !call->class->reg)
>  			continue;
> @@ -307,7 +419,7 @@ static int __ftrace_set_clr_event(const char *match, const char *sub,
>  		if (event && strcmp(event, call->name) != 0)
>  			continue;
>  
> -		ftrace_event_enable_disable(call, set);
> +		ftrace_event_enable_disable(file, set);
>  
>  		ret = 0;
>  	}
> @@ -316,7 +428,7 @@ static int __ftrace_set_clr_event(const char *match, const char *sub,
>  	return ret;
>  }
>  
> -static int ftrace_set_clr_event(char *buf, int set)
> +static int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set)
>  {
>  	char *event = NULL, *sub = NULL, *match;
>  
> @@ -344,7 +456,7 @@ static int ftrace_set_clr_event(char *buf, int set)
>  			event = NULL;
>  	}
>  
> -	return __ftrace_set_clr_event(match, sub, event, set);
> +	return __ftrace_set_clr_event(tr, match, sub, event, set);
>  }
>  
>  /**
> @@ -361,7 +473,9 @@ static int ftrace_set_clr_event(char *buf, int set)
>   */
>  int trace_set_clr_event(const char *system, const char *event, int set)
>  {
> -	return __ftrace_set_clr_event(NULL, system, event, set);
> +	struct trace_array *tr = top_trace_array();
> +
> +	return __ftrace_set_clr_event(tr, NULL, system, event, set);
>  }
>  EXPORT_SYMBOL_GPL(trace_set_clr_event);
>  
> @@ -373,6 +487,8 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
>  		   size_t cnt, loff_t *ppos)
>  {
>  	struct trace_parser parser;
> +	struct seq_file *m = file->private_data;
> +	struct trace_array *tr = m->private;
>  	ssize_t read, ret;
>  
>  	if (!cnt)
> @@ -395,7 +511,7 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
>  
>  		parser.buffer[parser.idx] = 0;
>  
> -		ret = ftrace_set_clr_event(parser.buffer + !set, set);
> +		ret = ftrace_set_clr_event(tr, parser.buffer + !set, set);
>  		if (ret)
>  			goto out_put;
>  	}
> @@ -411,17 +527,20 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
>  static void *
>  t_next(struct seq_file *m, void *v, loff_t *pos)
>  {
> -	struct ftrace_event_call *call = v;
> +	struct ftrace_event_file *file = v;
> +	struct ftrace_event_call *call;
> +	struct trace_array *tr = m->private;
>  
>  	(*pos)++;
>  
> -	list_for_each_entry_continue(call, &ftrace_events, list) {
> +	list_for_each_entry_continue(file, &tr->events, list) {
> +		call = file->event_call;
>  		/*
>  		 * The ftrace subsystem is for showing formats only.
>  		 * They can not be enabled or disabled via the event files.
>  		 */
>  		if (call->class && call->class->reg)
> -			return call;
> +			return file;
>  	}
>  
>  	return NULL;
> @@ -429,30 +548,32 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
>  
>  static void *t_start(struct seq_file *m, loff_t *pos)
>  {
> -	struct ftrace_event_call *call;
> +	struct ftrace_event_file *file;
> +	struct trace_array *tr = m->private;
>  	loff_t l;
>  
>  	mutex_lock(&event_mutex);
>  
> -	call = list_entry(&ftrace_events, struct ftrace_event_call, list);
> +	file = list_entry(&tr->events, struct ftrace_event_file, list);
>  	for (l = 0; l <= *pos; ) {
> -		call = t_next(m, call, &l);
> -		if (!call)
> +		file = t_next(m, file, &l);
> +		if (!file)
>  			break;
>  	}
> -	return call;
> +	return file;
>  }
>  
>  static void *
>  s_next(struct seq_file *m, void *v, loff_t *pos)
>  {
> -	struct ftrace_event_call *call = v;
> +	struct ftrace_event_file *file = v;
> +	struct trace_array *tr = m->private;
>  
>  	(*pos)++;
>  
> -	list_for_each_entry_continue(call, &ftrace_events, list) {
> -		if (call->flags & TRACE_EVENT_FL_ENABLED)
> -			return call;
> +	list_for_each_entry_continue(file, &tr->events, list) {
> +		if (file->flags & FTRACE_EVENT_FL_ENABLED)
> +			return file;
>  	}
>  
>  	return NULL;
> @@ -460,23 +581,25 @@ s_next(struct seq_file *m, void *v, loff_t *pos)
>  
>  static void *s_start(struct seq_file *m, loff_t *pos)
>  {
> -	struct ftrace_event_call *call;
> +	struct ftrace_event_file *file;
> +	struct trace_array *tr = m->private;
>  	loff_t l;
>  
>  	mutex_lock(&event_mutex);
>  
> -	call = list_entry(&ftrace_events, struct ftrace_event_call, list);
> +	file = list_entry(&tr->events, struct ftrace_event_file, list);
>  	for (l = 0; l <= *pos; ) {
> -		call = s_next(m, call, &l);
> -		if (!call)
> +		file = s_next(m, file, &l);
> +		if (!file)
>  			break;
>  	}
> -	return call;
> +	return file;
>  }
>  
>  static int t_show(struct seq_file *m, void *v)
>  {
> -	struct ftrace_event_call *call = v;
> +	struct ftrace_event_file *file = v;
> +	struct ftrace_event_call *call = file->event_call;
>  
>  	if (strcmp(call->class->system, TRACE_SYSTEM) != 0)
>  		seq_printf(m, "%s:", call->class->system);
> @@ -494,25 +617,31 @@ static ssize_t
>  event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
>  		  loff_t *ppos)
>  {
> -	struct ftrace_event_call *call = filp->private_data;
> +	struct ftrace_event_file *file = filp->private_data;
>  	char *buf;
>  
> -	if (call->flags & TRACE_EVENT_FL_ENABLED)
> -		buf = "1\n";
> -	else
> +	if (file->flags & FTRACE_EVENT_FL_ENABLED) {
> +		if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED)
> +			buf = "0*\n";
> +		else
> +			buf = "1\n";
> +	} else
>  		buf = "0\n";
>  
> -	return simple_read_from_buffer(ubuf, cnt, ppos, buf, 2);
> +	return simple_read_from_buffer(ubuf, cnt, ppos, buf, strlen(buf));
>  }
>  
>  static ssize_t
>  event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  		   loff_t *ppos)
>  {
> -	struct ftrace_event_call *call = filp->private_data;
> +	struct ftrace_event_file *file = filp->private_data;
>  	unsigned long val;
>  	int ret;
>  
> +	if (!file)
> +		return -EINVAL;
> +
>  	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
>  	if (ret)
>  		return ret;
> @@ -525,7 +654,7 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  	case 0:
>  	case 1:
>  		mutex_lock(&event_mutex);
> -		ret = ftrace_event_enable_disable(call, val);
> +		ret = ftrace_event_enable_disable(file, val);
>  		mutex_unlock(&event_mutex);
>  		break;
>  
> @@ -543,14 +672,18 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
>  		   loff_t *ppos)
>  {
>  	const char set_to_char[4] = { '?', '0', '1', 'X' };
> -	struct event_subsystem *system = filp->private_data;
> +	struct ftrace_subsystem_dir *dir = filp->private_data;
> +	struct event_subsystem *system = dir->subsystem;
>  	struct ftrace_event_call *call;
> +	struct ftrace_event_file *file;
> +	struct trace_array *tr = dir->tr;
>  	char buf[2];
>  	int set = 0;
>  	int ret;
>  
>  	mutex_lock(&event_mutex);
> -	list_for_each_entry(call, &ftrace_events, list) {
> +	list_for_each_entry(file, &tr->events, list) {
> +		call = file->event_call;
>  		if (!call->name || !call->class || !call->class->reg)
>  			continue;
>  
> @@ -562,7 +695,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
>  		 * or if all events or cleared, or if we have
>  		 * a mixture.
>  		 */
> -		set |= (1 << !!(call->flags & TRACE_EVENT_FL_ENABLED));
> +		set |= (1 << !!(file->flags & FTRACE_EVENT_FL_ENABLED));
>  
>  		/*
>  		 * If we have a mixture, no need to look further.
> @@ -584,7 +717,8 @@ static ssize_t
>  system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  		    loff_t *ppos)
>  {
> -	struct event_subsystem *system = filp->private_data;
> +	struct ftrace_subsystem_dir *dir = filp->private_data;
> +	struct event_subsystem *system = dir->subsystem;
>  	const char *name = NULL;
>  	unsigned long val;
>  	ssize_t ret;
> @@ -607,7 +741,7 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  	if (system)
>  		name = system->name;
>  
> -	ret = __ftrace_set_clr_event(NULL, name, NULL, val);
> +	ret = __ftrace_set_clr_event(dir->tr, NULL, name, NULL, val);
>  	if (ret)
>  		goto out;
>  
> @@ -845,43 +979,75 @@ static LIST_HEAD(event_subsystems);
>  static int subsystem_open(struct inode *inode, struct file *filp)
>  {
>  	struct event_subsystem *system = NULL;
> +	struct ftrace_subsystem_dir *dir = NULL; /* Initialize for gcc */
> +	struct trace_array *tr;
>  	int ret;
>  
> -	if (!inode->i_private)
> -		goto skip_search;
> -
>  	/* Make sure the system still exists */
>  	mutex_lock(&event_mutex);
> -	list_for_each_entry(system, &event_subsystems, list) {
> -		if (system == inode->i_private) {
> -			/* Don't open systems with no events */
> -			if (!system->nr_events) {
> -				system = NULL;
> -				break;
> +	list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> +		list_for_each_entry(dir, &tr->systems, list) {
> +			if (dir == inode->i_private) {
> +				/* Don't open systems with no events */
> +				if (dir->nr_events) {
> +					__get_system_dir(dir);
> +					system = dir->subsystem;
> +				}
> +				goto exit_loop;
>  			}
> -			__get_system(system);
> -			break;
>  		}
>  	}
> + exit_loop:
>  	mutex_unlock(&event_mutex);
>  
> -	if (system != inode->i_private)
> +	if (!system)
>  		return -ENODEV;
>  
> - skip_search:
> +	/* Some versions of gcc think dir can be uninitialized here */
> +	WARN_ON(!dir);
> +
> +	ret = tracing_open_generic(inode, filp);
> +	if (ret < 0)
> +		put_system(dir);
> +
> +	return ret;
> +}
> +
> +static int system_tr_open(struct inode *inode, struct file *filp)
> +{
> +	struct ftrace_subsystem_dir *dir;
> +	struct trace_array *tr = inode->i_private;
> +	int ret;
> +
> +	/* Make a temporary dir that has no system but points to tr */
> +	dir = kzalloc(sizeof(*dir), GFP_KERNEL);
> +	if (!dir)
> +		return -ENOMEM;
> +
> +	dir->tr = tr;
> +
>  	ret = tracing_open_generic(inode, filp);
> -	if (ret < 0 && system)
> -		put_system(system);
> +	if (ret < 0)
> +		kfree(dir);
> +
> +	filp->private_data = dir;
>  
>  	return ret;
>  }
>  
>  static int subsystem_release(struct inode *inode, struct file *file)
>  {
> -	struct event_subsystem *system = inode->i_private;
> +	struct ftrace_subsystem_dir *dir = file->private_data;
>  
> -	if (system)
> -		put_system(system);
> +	/*
> +	 * If dir->subsystem is NULL, then this is a temporary
> +	 * descriptor that was made for a trace_array to enable
> +	 * all subsystems.
> +	 */
> +	if (dir->subsystem)
> +		put_system(dir);
> +	else
> +		kfree(dir);
>  
>  	return 0;
>  }
> @@ -890,7 +1056,8 @@ static ssize_t
>  subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
>  		      loff_t *ppos)
>  {
> -	struct event_subsystem *system = filp->private_data;
> +	struct ftrace_subsystem_dir *dir = filp->private_data;
> +	struct event_subsystem *system = dir->subsystem;
>  	struct trace_seq *s;
>  	int r;
>  
> @@ -915,7 +1082,7 @@ static ssize_t
>  subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  		       loff_t *ppos)
>  {
> -	struct event_subsystem *system = filp->private_data;
> +	struct ftrace_subsystem_dir *dir = filp->private_data;
>  	char *buf;
>  	int err;
>  
> @@ -932,7 +1099,7 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
>  	}
>  	buf[cnt] = '\0';
>  
> -	err = apply_subsystem_event_filter(system, buf);
> +	err = apply_subsystem_event_filter(dir, buf);
>  	free_page((unsigned long) buf);
>  	if (err < 0)
>  		return err;
> @@ -1041,30 +1208,35 @@ static const struct file_operations ftrace_system_enable_fops = {
>  	.release = subsystem_release,
>  };
>  
> +static const struct file_operations ftrace_tr_enable_fops = {
> +	.open = system_tr_open,
> +	.read = system_enable_read,
> +	.write = system_enable_write,
> +	.llseek = default_llseek,
> +	.release = subsystem_release,
> +};
> +
>  static const struct file_operations ftrace_show_header_fops = {
>  	.open = tracing_open_generic,
>  	.read = show_header,
>  	.llseek = default_llseek,
>  };
>  
> -static struct dentry *event_trace_events_dir(void)
> +static int
> +ftrace_event_open(struct inode *inode, struct file *file,
> +		  const struct seq_operations *seq_ops)
>  {
> -	static struct dentry *d_tracer;
> -	static struct dentry *d_events;
> -
> -	if (d_events)
> -		return d_events;
> -
> -	d_tracer = tracing_init_dentry();
> -	if (!d_tracer)
> -		return NULL;
> +	struct seq_file *m;
> +	int ret;
>  
> -	d_events = debugfs_create_dir("events", d_tracer);
> -	if (!d_events)
> -		pr_warning("Could not create debugfs "
> -			   "'events' directory\n");
> +	ret = seq_open(file, seq_ops);
> +	if (ret < 0)
> +		return ret;
> +	m = file->private_data;
> +	/* copy tr over to seq ops */
> +	m->private = inode->i_private;
>  
> -	return d_events;
> +	return ret;
>  }
>  
>  static int
> @@ -1072,117 +1244,165 @@ ftrace_event_avail_open(struct inode *inode, struct file *file)
>  {
>  	const struct seq_operations *seq_ops = &show_event_seq_ops;
>  
> -	return seq_open(file, seq_ops);
> +	return ftrace_event_open(inode, file, seq_ops);
>  }
>  
>  static int
>  ftrace_event_set_open(struct inode *inode, struct file *file)
>  {
>  	const struct seq_operations *seq_ops = &show_set_event_seq_ops;
> +	struct trace_array *tr = inode->i_private;
>  
>  	if ((file->f_mode & FMODE_WRITE) &&
>  	    (file->f_flags & O_TRUNC))
> -		ftrace_clear_events();
> +		ftrace_clear_events(tr);
> +
> +	return ftrace_event_open(inode, file, seq_ops);
> +}
> +
> +static struct event_subsystem *
> +create_new_subsystem(const char *name)
> +{
> +	struct event_subsystem *system;
> +
> +	/* need to create new entry */
> +	system = kmalloc(sizeof(*system), GFP_KERNEL);
> +	if (!system)
> +		return NULL;
> +
> +	system->ref_count = 1;
> +	system->name = name;
> +
> +	system->filter = NULL;
> +
> +	system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL);
> +	if (!system->filter)
> +		goto out_free;
> +
> +	list_add(&system->list, &event_subsystems);
> +
> +	return system;
>  
> -	return seq_open(file, seq_ops);
> + out_free:
> +	kfree(system);
> +	return NULL;
>  }
>  
>  static struct dentry *
> -event_subsystem_dir(const char *name, struct dentry *d_events)
> +event_subsystem_dir(struct trace_array *tr, const char *name,
> +		    struct ftrace_event_file *file, struct dentry *parent)
>  {
> +	struct ftrace_subsystem_dir *dir;
>  	struct event_subsystem *system;
>  	struct dentry *entry;
>  
>  	/* First see if we did not already create this dir */
> -	list_for_each_entry(system, &event_subsystems, list) {
> +	list_for_each_entry(dir, &tr->systems, list) {
> +		system = dir->subsystem;
>  		if (strcmp(system->name, name) == 0) {
> -			system->nr_events++;
> -			return system->entry;
> +			dir->nr_events++;
> +			file->system = dir;
> +			return dir->entry;
>  		}
>  	}
>  
> -	/* need to create new entry */
> -	system = kmalloc(sizeof(*system), GFP_KERNEL);
> -	if (!system) {
> -		pr_warning("No memory to create event subsystem %s\n",
> -			   name);
> -		return d_events;
> +	/* Now see if the system itself exists. */
> +	list_for_each_entry(system, &event_subsystems, list) {
> +		if (strcmp(system->name, name) == 0)
> +			break;
>  	}
> +	/* Reset system variable when not found */
> +	if (&system->list == &event_subsystems)
> +		system = NULL;
>  
> -	system->entry = debugfs_create_dir(name, d_events);
> -	if (!system->entry) {
> -		pr_warning("Could not create event subsystem %s\n",
> -			   name);
> -		kfree(system);
> -		return d_events;
> -	}
> +	dir = kmalloc(sizeof(*dir), GFP_KERNEL);
> +	if (!dir)
> +		goto out_fail;
>  
> -	system->nr_events = 1;
> -	system->ref_count = 1;
> -	system->name = kstrdup(name, GFP_KERNEL);
> -	if (!system->name) {
> -		debugfs_remove(system->entry);
> -		kfree(system);
> -		return d_events;
> +	if (!system) {
> +		system = create_new_subsystem(name);
> +		if (!system)
> +			goto out_free;
> +	} else
> +		__get_system(system);
> +
> +	dir->entry = debugfs_create_dir(name, parent);
> +	if (!dir->entry) {
> +		pr_warning("Failed to create system directory %s\n", name);
> +		__put_system(system);
> +		goto out_free;
>  	}
>  
> -	list_add(&system->list, &event_subsystems);
> -
> -	system->filter = NULL;
> -
> -	system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL);
> -	if (!system->filter) {
> -		pr_warning("Could not allocate filter for subsystem "
> -			   "'%s'\n", name);
> -		return system->entry;
> -	}
> +	dir->tr = tr;
> +	dir->ref_count = 1;
> +	dir->nr_events = 1;
> +	dir->subsystem = system;
> +	file->system = dir;
>  
> -	entry = debugfs_create_file("filter", 0644, system->entry, system,
> +	entry = debugfs_create_file("filter", 0644, dir->entry, dir,
>  				    &ftrace_subsystem_filter_fops);
>  	if (!entry) {
>  		kfree(system->filter);
>  		system->filter = NULL;
> -		pr_warning("Could not create debugfs "
> -			   "'%s/filter' entry\n", name);
> +		pr_warning("Could not create debugfs '%s/filter' entry\n", name);
>  	}
>  
> -	trace_create_file("enable", 0644, system->entry, system,
> +	trace_create_file("enable", 0644, dir->entry, dir,
>  			  &ftrace_system_enable_fops);
>  
> -	return system->entry;
> +	list_add(&dir->list, &tr->systems);
> +
> +	return dir->entry;
> +
> + out_free:
> +	kfree(dir);
> + out_fail:
> +	/* Only print this message if failed on memory allocation */
> +	if (!dir || !system)
> +		pr_warning("No memory to create event subsystem %s\n",
> +			   name);
> +	return NULL;
>  }
>  
>  static int
> -event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
> +event_create_dir(struct dentry *parent,
> +		 struct ftrace_event_file *file,
>  		 const struct file_operations *id,
>  		 const struct file_operations *enable,
>  		 const struct file_operations *filter,
>  		 const struct file_operations *format)
>  {
> +	struct ftrace_event_call *call = file->event_call;
> +	struct trace_array *tr = file->tr;
>  	struct list_head *head;
> +	struct dentry *d_events;
>  	int ret;
>  
>  	/*
>  	 * If the trace point header did not define TRACE_SYSTEM
>  	 * then the system would be called "TRACE_SYSTEM".
>  	 */
> -	if (strcmp(call->class->system, TRACE_SYSTEM) != 0)
> -		d_events = event_subsystem_dir(call->class->system, d_events);
> -
> -	call->dir = debugfs_create_dir(call->name, d_events);
> -	if (!call->dir) {
> -		pr_warning("Could not create debugfs "
> -			   "'%s' directory\n", call->name);
> +	if (strcmp(call->class->system, TRACE_SYSTEM) != 0) {
> +		d_events = event_subsystem_dir(tr, call->class->system, file, parent);
> +		if (!d_events)
> +			return -ENOMEM;
> +	} else
> +		d_events = parent;
> +
> +	file->dir = debugfs_create_dir(call->name, d_events);
> +	if (!file->dir) {
> +		pr_warning("Could not create debugfs '%s' directory\n",
> +			   call->name);
>  		return -1;
>  	}
>  
>  	if (call->class->reg && !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
> -		trace_create_file("enable", 0644, call->dir, call,
> +		trace_create_file("enable", 0644, file->dir, file,
>  				  enable);
>  
>  #ifdef CONFIG_PERF_EVENTS
>  	if (call->event.type && call->class->reg)
> -		trace_create_file("id", 0444, call->dir, call,
> +		trace_create_file("id", 0444, file->dir, call,
>  		 		  id);
>  #endif
>  
> @@ -1196,23 +1416,76 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
>  		if (ret < 0) {
>  			pr_warning("Could not initialize trace point"
>  				   " events/%s\n", call->name);
> -			return ret;
> +			return -1;
>  		}
>  	}
> -	trace_create_file("filter", 0644, call->dir, call,
> +	trace_create_file("filter", 0644, file->dir, call,
>  			  filter);
>  
> -	trace_create_file("format", 0444, call->dir, call,
> +	trace_create_file("format", 0444, file->dir, call,
>  			  format);
>  
>  	return 0;
>  }
>  
> +static void remove_subsystem(struct ftrace_subsystem_dir *dir)
> +{
> +	if (!dir)
> +		return;
> +
> +	if (!--dir->nr_events) {
> +		debugfs_remove_recursive(dir->entry);
> +		list_del(&dir->list);
> +		__put_system_dir(dir);
> +	}
> +}
> +
> +static void remove_event_from_tracers(struct ftrace_event_call *call)
> +{
> +	struct ftrace_event_file *file;
> +	struct trace_array *tr;
> +
> +	do_for_each_event_file_safe(tr, file) {
> +
> +		if (file->event_call != call)
> +			continue;
> +
> +		list_del(&file->list);
> +		debugfs_remove_recursive(file->dir);
> +		remove_subsystem(file->system);
> +		kmem_cache_free(file_cachep, file);
> +
> +		/*
> +		 * The do_for_each_event_file_safe() is
> +		 * a double loop. After finding the call for this
> +		 * trace_array, we use break to jump to the next
> +		 * trace_array.
> +		 */
> +		break;
> +	} while_for_each_event_file();
> +}
> +
>  static void event_remove(struct ftrace_event_call *call)
>  {
> -	ftrace_event_enable_disable(call, 0);
> +	struct trace_array *tr;
> +	struct ftrace_event_file *file;
> +
> +	do_for_each_event_file(tr, file) {
> +		if (file->event_call != call)
> +			continue;
> +		ftrace_event_enable_disable(file, 0);
> +		/*
> +		 * The do_for_each_event_file() is
> +		 * a double loop. After finding the call for this
> +		 * trace_array, we use break to jump to the next
> +		 * trace_array.
> +		 */
> +		break;
> +	} while_for_each_event_file();
> +
>  	if (call->event.funcs)
>  		__unregister_ftrace_event(&call->event);
> +	remove_event_from_tracers(call);
>  	list_del(&call->list);
>  }
>  
> @@ -1234,82 +1507,99 @@ static int event_init(struct ftrace_event_call *call)
>  }
>  
>  static int
> -__trace_add_event_call(struct ftrace_event_call *call, struct module *mod,
> -		       const struct file_operations *id,
> -		       const struct file_operations *enable,
> -		       const struct file_operations *filter,
> -		       const struct file_operations *format)
> +__register_event(struct ftrace_event_call *call, struct module *mod)
>  {
> -	struct dentry *d_events;
>  	int ret;
>  
>  	ret = event_init(call);
>  	if (ret < 0)
>  		return ret;
>  
> -	d_events = event_trace_events_dir();
> -	if (!d_events)
> -		return -ENOENT;
> -
> -	ret = event_create_dir(call, d_events, id, enable, filter, format);
> -	if (!ret)
> -		list_add(&call->list, &ftrace_events);
> +	list_add(&call->list, &ftrace_events);
>  	call->mod = mod;
>  
> -	return ret;
> +	return 0;
> +}
> +
> +/* Add an event to a trace directory */
> +static int
> +__trace_add_new_event(struct ftrace_event_call *call,
> +		      struct trace_array *tr,
> +		      const struct file_operations *id,
> +		      const struct file_operations *enable,
> +		      const struct file_operations *filter,
> +		      const struct file_operations *format)
> +{
> +	struct ftrace_event_file *file;
> +
> +	file = kmem_cache_alloc(file_cachep, GFP_TRACE);
> +	if (!file)
> +		return -ENOMEM;
> +
> +	file->event_call = call;
> +	file->tr = tr;
> +	list_add(&file->list, &tr->events);
> +
> +	return event_create_dir(tr->event_dir, file, id, enable, filter, format);
> +}
> +
> +/*
> + * Just create a decriptor for early init. A descriptor is required
> + * for enabling events at boot. We want to enable events before
> + * the filesystem is initialized.
> + */
> +static __init int
> +__trace_early_add_new_event(struct ftrace_event_call *call,
> +			    struct trace_array *tr)
> +{
> +	struct ftrace_event_file *file;
> +
> +	file = kmem_cache_alloc(file_cachep, GFP_TRACE);
> +	if (!file)
> +		return -ENOMEM;
> +
> +	file->event_call = call;
> +	file->tr = tr;
> +	list_add(&file->list, &tr->events);
> +
> +	return 0;
>  }
>  
> +struct ftrace_module_file_ops;
> +static void __add_event_to_tracers(struct ftrace_event_call *call,
> +				   struct ftrace_module_file_ops *file_ops);
> +
>  /* Add an additional event_call dynamically */
>  int trace_add_event_call(struct ftrace_event_call *call)
>  {
>  	int ret;
>  	mutex_lock(&event_mutex);
> -	ret = __trace_add_event_call(call, NULL, &ftrace_event_id_fops,
> -				     &ftrace_enable_fops,
> -				     &ftrace_event_filter_fops,
> -				     &ftrace_event_format_fops);
> -	mutex_unlock(&event_mutex);
> -	return ret;
> -}
>  
> -static void remove_subsystem_dir(const char *name)
> -{
> -	struct event_subsystem *system;
> -
> -	if (strcmp(name, TRACE_SYSTEM) == 0)
> -		return;
> +	ret = __register_event(call, NULL);
> +	if (ret >= 0)
> +		__add_event_to_tracers(call, NULL);
>  
> -	list_for_each_entry(system, &event_subsystems, list) {
> -		if (strcmp(system->name, name) == 0) {
> -			if (!--system->nr_events) {
> -				debugfs_remove_recursive(system->entry);
> -				list_del(&system->list);
> -				__put_system(system);
> -			}
> -			break;
> -		}
> -	}
> +	mutex_unlock(&event_mutex);
> +	return ret;
>  }
>  
>  /*
> - * Must be called under locking both of event_mutex and trace_event_mutex.
> + * Must be called under locking both of event_mutex and trace_event_sem.
>   */
>  static void __trace_remove_event_call(struct ftrace_event_call *call)
>  {
>  	event_remove(call);
>  	trace_destroy_fields(call);
>  	destroy_preds(call);
> -	debugfs_remove_recursive(call->dir);
> -	remove_subsystem_dir(call->class->system);
>  }
>  
>  /* Remove an event_call */
>  void trace_remove_event_call(struct ftrace_event_call *call)
>  {
>  	mutex_lock(&event_mutex);
> -	down_write(&trace_event_mutex);
> +	down_write(&trace_event_sem);
>  	__trace_remove_event_call(call);
> -	up_write(&trace_event_mutex);
> +	up_write(&trace_event_sem);
>  	mutex_unlock(&event_mutex);
>  }
>  
> @@ -1336,6 +1626,26 @@ struct ftrace_module_file_ops {
>  };
>  
>  static struct ftrace_module_file_ops *
> +find_ftrace_file_ops(struct ftrace_module_file_ops *file_ops, struct module *mod)
> +{
> +	/*
> +	 * As event_calls are added in groups by module,
> +	 * when we find one file_ops, we don't need to search for
> +	 * each call in that module, as the rest should be the
> +	 * same. Only search for a new one if the last one did
> +	 * not match.
> +	 */
> +	if (file_ops && mod == file_ops->mod)
> +		return file_ops;
> +
> +	list_for_each_entry(file_ops, &ftrace_module_file_list, list) {
> +		if (file_ops->mod == mod)
> +			return file_ops;
> +	}
> +	return NULL;
> +}
> +
> +static struct ftrace_module_file_ops *
>  trace_create_file_ops(struct module *mod)
>  {
>  	struct ftrace_module_file_ops *file_ops;
> @@ -1386,9 +1696,8 @@ static void trace_module_add_events(struct module *mod)
>  		return;
>  
>  	for_each_event(call, start, end) {
> -		__trace_add_event_call(*call, mod,
> -				       &file_ops->id, &file_ops->enable,
> -				       &file_ops->filter, &file_ops->format);
> +		__register_event(*call, mod);
> +		__add_event_to_tracers(*call, file_ops);
>  	}
>  }
>  
> @@ -1396,12 +1705,13 @@ static void trace_module_remove_events(struct module *mod)
>  {
>  	struct ftrace_module_file_ops *file_ops;
>  	struct ftrace_event_call *call, *p;
> -	bool found = false;
> +	bool clear_trace = false;
>  
> -	down_write(&trace_event_mutex);
> +	down_write(&trace_event_sem);
>  	list_for_each_entry_safe(call, p, &ftrace_events, list) {
>  		if (call->mod == mod) {
> -			found = true;
> +			if (call->flags & TRACE_EVENT_FL_WAS_ENABLED)
> +				clear_trace = true;
>  			__trace_remove_event_call(call);
>  		}
>  	}
> @@ -1415,14 +1725,18 @@ static void trace_module_remove_events(struct module *mod)
>  		list_del(&file_ops->list);
>  		kfree(file_ops);
>  	}
> +	up_write(&trace_event_sem);
>  
>  	/*
>  	 * It is safest to reset the ring buffer if the module being unloaded
> -	 * registered any events.
> +	 * registered any events that were used. The only worry is if
> +	 * a new module gets loaded, and takes on the same id as the events
> +	 * of this module. When printing out the buffer, traced events left
> +	 * over from this module may be passed to the new module events and
> +	 * unexpected results may occur.
>  	 */
> -	if (found)
> -		tracing_reset_current_online_cpus();
> -	up_write(&trace_event_mutex);
> +	if (clear_trace)
> +		tracing_reset_all_online_cpus();
>  }
>  
>  static int trace_module_notify(struct notifier_block *self,
> @@ -1443,36 +1757,575 @@ static int trace_module_notify(struct notifier_block *self,
>  
>  	return 0;
>  }
> +
> +static int
> +__trace_add_new_mod_event(struct ftrace_event_call *call,
> +			  struct trace_array *tr,
> +			  struct ftrace_module_file_ops *file_ops)
> +{
> +	return __trace_add_new_event(call, tr,
> +				     &file_ops->id, &file_ops->enable,
> +				     &file_ops->filter, &file_ops->format);
> +}
> +
>  #else
> -static int trace_module_notify(struct notifier_block *self,
> -			       unsigned long val, void *data)
> +static inline struct ftrace_module_file_ops *
> +find_ftrace_file_ops(struct ftrace_module_file_ops *file_ops, struct module *mod)
> +{
> +	return NULL;
> +}
> +static inline int trace_module_notify(struct notifier_block *self,
> +				      unsigned long val, void *data)
>  {
>  	return 0;
>  }
> +static inline int
> +__trace_add_new_mod_event(struct ftrace_event_call *call,
> +			  struct trace_array *tr,
> +			  struct ftrace_module_file_ops *file_ops)
> +{
> +	return -ENODEV;
> +}
>  #endif /* CONFIG_MODULES */
>  
> -static struct notifier_block trace_module_nb = {
> -	.notifier_call = trace_module_notify,
> -	.priority = 0,
> -};
> -
> -extern struct ftrace_event_call *__start_ftrace_events[];
> -extern struct ftrace_event_call *__stop_ftrace_events[];
> -
> -static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
> -
> -static __init int setup_trace_event(char *str)
> +/* Create a new event directory structure for a trace directory. */
> +static void
> +__trace_add_event_dirs(struct trace_array *tr)
>  {
> -	strlcpy(bootup_event_buf, str, COMMAND_LINE_SIZE);
> -	ring_buffer_expanded = 1;
> -	tracing_selftest_disabled = 1;
> +	struct ftrace_module_file_ops *file_ops = NULL;
> +	struct ftrace_event_call *call;
> +	int ret;
> +
> +	list_for_each_entry(call, &ftrace_events, list) {
> +		if (call->mod) {
> +			/*
> +			 * Directories for events by modules need to
> +			 * keep module ref counts when opened (as we don't
> +			 * want the module to disappear when reading one
> +			 * of these files). The file_ops keep account of
> +			 * the module ref count.
> +			 */
> +			file_ops = find_ftrace_file_ops(file_ops, call->mod);
> +			if (!file_ops)
> +				continue; /* Warn? */
> +			ret = __trace_add_new_mod_event(call, tr, file_ops);
> +			if (ret < 0)
> +				pr_warning("Could not create directory for event %s\n",
> +					   call->name);
> +			continue;
> +		}
> +		ret = __trace_add_new_event(call, tr,
> +					    &ftrace_event_id_fops,
> +					    &ftrace_enable_fops,
> +					    &ftrace_event_filter_fops,
> +					    &ftrace_event_format_fops);
> +		if (ret < 0)
> +			pr_warning("Could not create directory for event %s\n",
> +				   call->name);
> +	}
> +}
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +
> +/* Avoid typos */
> +#define ENABLE_EVENT_STR	"enable_event"
> +#define DISABLE_EVENT_STR	"disable_event"
> +
> +struct event_probe_data {
> +	struct ftrace_event_file	*file;
> +	unsigned long			count;
> +	int				ref;
> +	bool				enable;
> +};
> +
> +static struct ftrace_event_file *
> +find_event_file(struct trace_array *tr, const char *system,  const char *event)
> +{
> +	struct ftrace_event_file *file;
> +	struct ftrace_event_call *call;
> +
> +	list_for_each_entry(file, &tr->events, list) {
> +
> +		call = file->event_call;
> +
> +		if (!call->name || !call->class || !call->class->reg)
> +			continue;
> +
> +		if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
> +			continue;
> +
> +		if (strcmp(event, call->name) == 0 &&
> +		    strcmp(system, call->class->system) == 0)
> +			return file;
> +	}
> +	return NULL;
> +}
> +
> +static void
> +event_enable_probe(unsigned long ip, unsigned long parent_ip, void **_data)
> +{
> +	struct event_probe_data **pdata = (struct event_probe_data **)_data;
> +	struct event_probe_data *data = *pdata;
> +
> +	if (!data)
> +		return;
> +
> +	if (data->enable)
> +		clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &data->file->flags);
> +	else
> +		set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &data->file->flags);
> +}
> +
> +static void
> +event_enable_count_probe(unsigned long ip, unsigned long parent_ip, void **_data)
> +{
> +	struct event_probe_data **pdata = (struct event_probe_data **)_data;
> +	struct event_probe_data *data = *pdata;
> +
> +	if (!data)
> +		return;
> +
> +	if (!data->count)
> +		return;
> +
> +	/* Skip if the event is in a state we want to switch to */
> +	if (data->enable == !(data->file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
> +		return;
> +
> +	if (data->count != -1)
> +		(data->count)--;
> +
> +	event_enable_probe(ip, parent_ip, _data);
> +}
> +
> +static int
> +event_enable_print(struct seq_file *m, unsigned long ip,
> +		      struct ftrace_probe_ops *ops, void *_data)
> +{
> +	struct event_probe_data *data = _data;
> +
> +	seq_printf(m, "%ps:", (void *)ip);
> +
> +	seq_printf(m, "%s:%s:%s",
> +		   data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
> +		   data->file->event_call->class->system,
> +		   data->file->event_call->name);
> +
> +	if (data->count == -1)
> +		seq_printf(m, ":unlimited\n");
> +	else
> +		seq_printf(m, ":count=%ld\n", data->count);
> +
> +	return 0;
> +}
> +
> +static int
> +event_enable_init(struct ftrace_probe_ops *ops, unsigned long ip,
> +		  void **_data)
> +{
> +	struct event_probe_data **pdata = (struct event_probe_data **)_data;
> +	struct event_probe_data *data = *pdata;
> +
> +	data->ref++;
> +	return 0;
> +}
> +
> +static void
> +event_enable_free(struct ftrace_probe_ops *ops, unsigned long ip,
> +		  void **_data)
> +{
> +	struct event_probe_data **pdata = (struct event_probe_data **)_data;
> +	struct event_probe_data *data = *pdata;
> +
> +	if (WARN_ON_ONCE(data->ref <= 0))
> +		return;
> +
> +	data->ref--;
> +	if (!data->ref) {
> +		/* Remove the SOFT_MODE flag */
> +		__ftrace_event_enable_disable(data->file, 0, 1);
> +		module_put(data->file->event_call->mod);
> +		kfree(data);
> +	}
> +	*pdata = NULL;
> +}
> +
> +static struct ftrace_probe_ops event_enable_probe_ops = {
> +	.func			= event_enable_probe,
> +	.print			= event_enable_print,
> +	.init			= event_enable_init,
> +	.free			= event_enable_free,
> +};
> +
> +static struct ftrace_probe_ops event_enable_count_probe_ops = {
> +	.func			= event_enable_count_probe,
> +	.print			= event_enable_print,
> +	.init			= event_enable_init,
> +	.free			= event_enable_free,
> +};
> +
> +static struct ftrace_probe_ops event_disable_probe_ops = {
> +	.func			= event_enable_probe,
> +	.print			= event_enable_print,
> +	.init			= event_enable_init,
> +	.free			= event_enable_free,
> +};
> +
> +static struct ftrace_probe_ops event_disable_count_probe_ops = {
> +	.func			= event_enable_count_probe,
> +	.print			= event_enable_print,
> +	.init			= event_enable_init,
> +	.free			= event_enable_free,
> +};
> +
> +static int
> +event_enable_func(struct ftrace_hash *hash,
> +		  char *glob, char *cmd, char *param, int enabled)
> +{
> +	struct trace_array *tr = top_trace_array();
> +	struct ftrace_event_file *file;
> +	struct ftrace_probe_ops *ops;
> +	struct event_probe_data *data;
> +	const char *system;
> +	const char *event;
> +	char *number;
> +	bool enable;
> +	int ret;
> +
> +	/* hash funcs only work with set_ftrace_filter */
> +	if (!enabled)
> +		return -EINVAL;
> +
> +	if (!param)
> +		return -EINVAL;
> +
> +	system = strsep(&param, ":");
> +	if (!param)
> +		return -EINVAL;
> +
> +	event = strsep(&param, ":");
> +
> +	mutex_lock(&event_mutex);
> +
> +	ret = -EINVAL;
> +	file = find_event_file(tr, system, event);
> +	if (!file)
> +		goto out;
> +
> +	enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
> +
> +	if (enable)
> +		ops = param ? &event_enable_count_probe_ops : &event_enable_probe_ops;
> +	else
> +		ops = param ? &event_disable_count_probe_ops : &event_disable_probe_ops;
> +
> +	if (glob[0] == '!') {
> +		unregister_ftrace_function_probe_func(glob+1, ops);
> +		ret = 0;
> +		goto out;
> +	}
> +
> +	ret = -ENOMEM;
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		goto out;
> +
> +	data->enable = enable;
> +	data->count = -1;
> +	data->file = file;
> +
> +	if (!param)
> +		goto out_reg;
> +
> +	number = strsep(&param, ":");
> +
> +	ret = -EINVAL;
> +	if (!strlen(number))
> +		goto out_free;
> +
> +	/*
> +	 * We use the callback data field (which is a pointer)
> +	 * as our counter.
> +	 */
> +	ret = kstrtoul(number, 0, &data->count);
> +	if (ret)
> +		goto out_free;
> +
> + out_reg:
> +	/* Don't let event modules unload while probe registered */
> +	ret = try_module_get(file->event_call->mod);
> +	if (!ret)
> +		goto out_free;
> +
> +	ret = __ftrace_event_enable_disable(file, 1, 1);
> +	if (ret < 0)
> +		goto out_put;
> +	ret = register_ftrace_function_probe(glob, ops, data);
> +	if (!ret)
> +		goto out_disable;
> + out:
> +	mutex_unlock(&event_mutex);
> +	return ret;
> +
> + out_disable:
> +	__ftrace_event_enable_disable(file, 0, 1);
> + out_put:
> +	module_put(file->event_call->mod);
> + out_free:
> +	kfree(data);
> +	goto out;
> +}
> +
> +static struct ftrace_func_command event_enable_cmd = {
> +	.name			= ENABLE_EVENT_STR,
> +	.func			= event_enable_func,
> +};
> +
> +static struct ftrace_func_command event_disable_cmd = {
> +	.name			= DISABLE_EVENT_STR,
> +	.func			= event_enable_func,
> +};
> +
> +static __init int register_event_cmds(void)
> +{
> +	int ret;
> +
> +	ret = register_ftrace_command(&event_enable_cmd);
> +	if (WARN_ON(ret < 0))
> +		return ret;
> +	ret = register_ftrace_command(&event_disable_cmd);
> +	if (WARN_ON(ret < 0))
> +		unregister_ftrace_command(&event_enable_cmd);
> +	return ret;
> +}
> +#else
> +static inline int register_event_cmds(void) { return 0; }
> +#endif /* CONFIG_DYNAMIC_FTRACE */
> +
> +/*
> + * The top level array has already had its ftrace_event_file
> + * descriptors created in order to allow for early events to
> + * be recorded. This function is called after the debugfs has been
> + * initialized, and we now have to create the files associated
> + * to the events.
> + */
> +static __init void
> +__trace_early_add_event_dirs(struct trace_array *tr)
> +{
> +	struct ftrace_event_file *file;
> +	int ret;
> +
> +
> +	list_for_each_entry(file, &tr->events, list) {
> +		ret = event_create_dir(tr->event_dir, file,
> +				       &ftrace_event_id_fops,
> +				       &ftrace_enable_fops,
> +				       &ftrace_event_filter_fops,
> +				       &ftrace_event_format_fops);
> +		if (ret < 0)
> +			pr_warning("Could not create directory for event %s\n",
> +				   file->event_call->name);
> +	}
> +}
> +
> +/*
> + * For early boot up, the top trace array requires to have
> + * a list of events that can be enabled. This must be done before
> + * the filesystem is set up in order to allow events to be traced
> + * early.
> + */
> +static __init void
> +__trace_early_add_events(struct trace_array *tr)
> +{
> +	struct ftrace_event_call *call;
> +	int ret;
> +
> +	list_for_each_entry(call, &ftrace_events, list) {
> +		/* Early boot up should not have any modules loaded */
> +		if (WARN_ON_ONCE(call->mod))
> +			continue;
> +
> +		ret = __trace_early_add_new_event(call, tr);
> +		if (ret < 0)
> +			pr_warning("Could not create early event %s\n",
> +				   call->name);
> +	}
> +}
> +
> +/* Remove the event directory structure for a trace directory. */
> +static void
> +__trace_remove_event_dirs(struct trace_array *tr)
> +{
> +	struct ftrace_event_file *file, *next;
> +
> +	list_for_each_entry_safe(file, next, &tr->events, list) {
> +		list_del(&file->list);
> +		debugfs_remove_recursive(file->dir);
> +		remove_subsystem(file->system);
> +		kmem_cache_free(file_cachep, file);
> +	}
> +}
> +
> +static void
> +__add_event_to_tracers(struct ftrace_event_call *call,
> +		       struct ftrace_module_file_ops *file_ops)
> +{
> +	struct trace_array *tr;
> +
> +	list_for_each_entry(tr, &ftrace_trace_arrays, list) {
> +		if (file_ops)
> +			__trace_add_new_mod_event(call, tr, file_ops);
> +		else
> +			__trace_add_new_event(call, tr,
> +					      &ftrace_event_id_fops,
> +					      &ftrace_enable_fops,
> +					      &ftrace_event_filter_fops,
> +					      &ftrace_event_format_fops);
> +	}
> +}
> +
> +static struct notifier_block trace_module_nb = {
> +	.notifier_call = trace_module_notify,
> +	.priority = 0,
> +};
> +
> +extern struct ftrace_event_call *__start_ftrace_events[];
> +extern struct ftrace_event_call *__stop_ftrace_events[];
> +
> +static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
> +
> +static __init int setup_trace_event(char *str)
> +{
> +	strlcpy(bootup_event_buf, str, COMMAND_LINE_SIZE);
> +	ring_buffer_expanded = true;
> +	tracing_selftest_disabled = true;
>  
>  	return 1;
>  }
>  __setup("trace_event=", setup_trace_event);
>  
> +/* Expects to have event_mutex held when called */
> +static int
> +create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
> +{
> +	struct dentry *d_events;
> +	struct dentry *entry;
> +
> +	entry = debugfs_create_file("set_event", 0644, parent,
> +				    tr, &ftrace_set_event_fops);
> +	if (!entry) {
> +		pr_warning("Could not create debugfs 'set_event' entry\n");
> +		return -ENOMEM;
> +	}
> +
> +	d_events = debugfs_create_dir("events", parent);
> +	if (!d_events) {
> +		pr_warning("Could not create debugfs 'events' directory\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* ring buffer internal formats */
> +	trace_create_file("header_page", 0444, d_events,
> +			  ring_buffer_print_page_header,
> +			  &ftrace_show_header_fops);
> +
> +	trace_create_file("header_event", 0444, d_events,
> +			  ring_buffer_print_entry_header,
> +			  &ftrace_show_header_fops);
> +
> +	trace_create_file("enable", 0644, d_events,
> +			  tr, &ftrace_tr_enable_fops);
> +
> +	tr->event_dir = d_events;
> +
> +	return 0;
> +}
> +
> +/**
> + * event_trace_add_tracer - add a instance of a trace_array to events
> + * @parent: The parent dentry to place the files/directories for events in
> + * @tr: The trace array associated with these events
> + *
> + * When a new instance is created, it needs to set up its events
> + * directory, as well as other files associated with events. It also
> + * creates the event hierachry in the @parent/events directory.
> + *
> + * Returns 0 on success.
> + */
> +int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
> +{
> +	int ret;
> +
> +	mutex_lock(&event_mutex);
> +
> +	ret = create_event_toplevel_files(parent, tr);
> +	if (ret)
> +		goto out_unlock;
> +
> +	down_write(&trace_event_sem);
> +	__trace_add_event_dirs(tr);
> +	up_write(&trace_event_sem);
> +
> + out_unlock:
> +	mutex_unlock(&event_mutex);
> +
> +	return ret;
> +}
> +
> +/*
> + * The top trace array already had its file descriptors created.
> + * Now the files themselves need to be created.
> + */
> +static __init int
> +early_event_add_tracer(struct dentry *parent, struct trace_array *tr)
> +{
> +	int ret;
> +
> +	mutex_lock(&event_mutex);
> +
> +	ret = create_event_toplevel_files(parent, tr);
> +	if (ret)
> +		goto out_unlock;
> +
> +	down_write(&trace_event_sem);
> +	__trace_early_add_event_dirs(tr);
> +	up_write(&trace_event_sem);
> +
> + out_unlock:
> +	mutex_unlock(&event_mutex);
> +
> +	return ret;
> +}
> +
> +int event_trace_del_tracer(struct trace_array *tr)
> +{
> +	/* Disable any running events */
> +	__ftrace_set_clr_event(tr, NULL, NULL, NULL, 0);
> +
> +	mutex_lock(&event_mutex);
> +
> +	down_write(&trace_event_sem);
> +	__trace_remove_event_dirs(tr);
> +	debugfs_remove_recursive(tr->event_dir);
> +	up_write(&trace_event_sem);
> +
> +	tr->event_dir = NULL;
> +
> +	mutex_unlock(&event_mutex);
> +
> +	return 0;
> +}
> +
> +static __init int event_trace_memsetup(void)
> +{
> +	field_cachep = KMEM_CACHE(ftrace_event_field, SLAB_PANIC);
> +	file_cachep = KMEM_CACHE(ftrace_event_file, SLAB_PANIC);
> +	return 0;
> +}
> +
>  static __init int event_trace_enable(void)
>  {
> +	struct trace_array *tr = top_trace_array();
>  	struct ftrace_event_call **iter, *call;
>  	char *buf = bootup_event_buf;
>  	char *token;
> @@ -1486,6 +2339,14 @@ static __init int event_trace_enable(void)
>  			list_add(&call->list, &ftrace_events);
>  	}
>  
> +	/*
> +	 * We need the top trace array to have a working set of trace
> +	 * points at early init, before the debug files and directories
> +	 * are created. Create the file entries now, and attach them
> +	 * to the actual file dentries later.
> +	 */
> +	__trace_early_add_events(tr);
> +
>  	while (true) {
>  		token = strsep(&buf, ",");
>  
> @@ -1494,73 +2355,43 @@ static __init int event_trace_enable(void)
>  		if (!*token)
>  			continue;
>  
> -		ret = ftrace_set_clr_event(token, 1);
> +		ret = ftrace_set_clr_event(tr, token, 1);
>  		if (ret)
>  			pr_warn("Failed to enable trace event: %s\n", token);
>  	}
>  
>  	trace_printk_start_comm();
>  
> +	register_event_cmds();
> +
>  	return 0;
>  }
>  
>  static __init int event_trace_init(void)
>  {
> -	struct ftrace_event_call *call;
> +	struct trace_array *tr;
>  	struct dentry *d_tracer;
>  	struct dentry *entry;
> -	struct dentry *d_events;
>  	int ret;
>  
> +	tr = top_trace_array();
> +
>  	d_tracer = tracing_init_dentry();
>  	if (!d_tracer)
>  		return 0;
>  
>  	entry = debugfs_create_file("available_events", 0444, d_tracer,
> -				    NULL, &ftrace_avail_fops);
> +				    tr, &ftrace_avail_fops);
>  	if (!entry)
>  		pr_warning("Could not create debugfs "
>  			   "'available_events' entry\n");
>  
> -	entry = debugfs_create_file("set_event", 0644, d_tracer,
> -				    NULL, &ftrace_set_event_fops);
> -	if (!entry)
> -		pr_warning("Could not create debugfs "
> -			   "'set_event' entry\n");
> -
> -	d_events = event_trace_events_dir();
> -	if (!d_events)
> -		return 0;
> -
> -	/* ring buffer internal formats */
> -	trace_create_file("header_page", 0444, d_events,
> -			  ring_buffer_print_page_header,
> -			  &ftrace_show_header_fops);
> -
> -	trace_create_file("header_event", 0444, d_events,
> -			  ring_buffer_print_entry_header,
> -			  &ftrace_show_header_fops);
> -
> -	trace_create_file("enable", 0644, d_events,
> -			  NULL, &ftrace_system_enable_fops);
> -
>  	if (trace_define_common_fields())
>  		pr_warning("tracing: Failed to allocate common fields");
>  
> -	/*
> -	 * Early initialization already enabled ftrace event.
> -	 * Now it's only necessary to create the event directory.
> -	 */
> -	list_for_each_entry(call, &ftrace_events, list) {
> -
> -		ret = event_create_dir(call, d_events,
> -				       &ftrace_event_id_fops,
> -				       &ftrace_enable_fops,
> -				       &ftrace_event_filter_fops,
> -				       &ftrace_event_format_fops);
> -		if (ret < 0)
> -			event_remove(call);
> -	}
> +	ret = early_event_add_tracer(d_tracer, tr);
> +	if (ret)
> +		return ret;
>  
>  	ret = register_module_notifier(&trace_module_nb);
>  	if (ret)
> @@ -1568,6 +2399,7 @@ static __init int event_trace_init(void)
>  
>  	return 0;
>  }
> +early_initcall(event_trace_memsetup);
>  core_initcall(event_trace_enable);
>  fs_initcall(event_trace_init);
>  
> @@ -1627,13 +2459,20 @@ static __init void event_test_stuff(void)
>   */
>  static __init void event_trace_self_tests(void)
>  {
> +	struct ftrace_subsystem_dir *dir;
> +	struct ftrace_event_file *file;
>  	struct ftrace_event_call *call;
>  	struct event_subsystem *system;
> +	struct trace_array *tr;
>  	int ret;
>  
> +	tr = top_trace_array();
> +
>  	pr_info("Running tests on trace events:\n");
>  
> -	list_for_each_entry(call, &ftrace_events, list) {
> +	list_for_each_entry(file, &tr->events, list) {
> +
> +		call = file->event_call;
>  
>  		/* Only test those that have a probe */
>  		if (!call->class || !call->class->probe)
> @@ -1657,15 +2496,15 @@ static __init void event_trace_self_tests(void)
>  		 * If an event is already enabled, someone is using
>  		 * it and the self test should not be on.
>  		 */
> -		if (call->flags & TRACE_EVENT_FL_ENABLED) {
> +		if (file->flags & FTRACE_EVENT_FL_ENABLED) {
>  			pr_warning("Enabled event during self test!\n");
>  			WARN_ON_ONCE(1);
>  			continue;
>  		}
>  
> -		ftrace_event_enable_disable(call, 1);
> +		ftrace_event_enable_disable(file, 1);
>  		event_test_stuff();
> -		ftrace_event_enable_disable(call, 0);
> +		ftrace_event_enable_disable(file, 0);
>  
>  		pr_cont("OK\n");
>  	}
> @@ -1674,7 +2513,9 @@ static __init void event_trace_self_tests(void)
>  
>  	pr_info("Running tests on trace event systems:\n");
>  
> -	list_for_each_entry(system, &event_subsystems, list) {
> +	list_for_each_entry(dir, &tr->systems, list) {
> +
> +		system = dir->subsystem;
>  
>  		/* the ftrace system is special, skip it */
>  		if (strcmp(system->name, "ftrace") == 0)
> @@ -1682,7 +2523,7 @@ static __init void event_trace_self_tests(void)
>  
>  		pr_info("Testing event system %s: ", system->name);
>  
> -		ret = __ftrace_set_clr_event(NULL, system->name, NULL, 1);
> +		ret = __ftrace_set_clr_event(tr, NULL, system->name, NULL, 1);
>  		if (WARN_ON_ONCE(ret)) {
>  			pr_warning("error enabling system %s\n",
>  				   system->name);
> @@ -1691,7 +2532,7 @@ static __init void event_trace_self_tests(void)
>  
>  		event_test_stuff();
>  
> -		ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0);
> +		ret = __ftrace_set_clr_event(tr, NULL, system->name, NULL, 0);
>  		if (WARN_ON_ONCE(ret)) {
>  			pr_warning("error disabling system %s\n",
>  				   system->name);
> @@ -1706,7 +2547,7 @@ static __init void event_trace_self_tests(void)
>  	pr_info("Running tests on all trace events:\n");
>  	pr_info("Testing all events: ");
>  
> -	ret = __ftrace_set_clr_event(NULL, NULL, NULL, 1);
> +	ret = __ftrace_set_clr_event(tr, NULL, NULL, NULL, 1);
>  	if (WARN_ON_ONCE(ret)) {
>  		pr_warning("error enabling all events\n");
>  		return;
> @@ -1715,7 +2556,7 @@ static __init void event_trace_self_tests(void)
>  	event_test_stuff();
>  
>  	/* reset sysname */
> -	ret = __ftrace_set_clr_event(NULL, NULL, NULL, 0);
> +	ret = __ftrace_set_clr_event(tr, NULL, NULL, NULL, 0);
>  	if (WARN_ON_ONCE(ret)) {
>  		pr_warning("error disabling all events\n");
>  		return;
> diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
> index e5b0ca8..a636117 100644
> --- a/kernel/trace/trace_events_filter.c
> +++ b/kernel/trace/trace_events_filter.c
> @@ -658,33 +658,6 @@ void print_subsystem_event_filter(struct event_subsystem *system,
>  	mutex_unlock(&event_mutex);
>  }
>  
> -static struct ftrace_event_field *
> -__find_event_field(struct list_head *head, char *name)
> -{
> -	struct ftrace_event_field *field;
> -
> -	list_for_each_entry(field, head, link) {
> -		if (!strcmp(field->name, name))
> -			return field;
> -	}
> -
> -	return NULL;
> -}
> -
> -static struct ftrace_event_field *
> -find_event_field(struct ftrace_event_call *call, char *name)
> -{
> -	struct ftrace_event_field *field;
> -	struct list_head *head;
> -
> -	field = __find_event_field(&ftrace_common_fields, name);
> -	if (field)
> -		return field;
> -
> -	head = trace_get_fields(call);
> -	return __find_event_field(head, name);
> -}
> -
>  static int __alloc_pred_stack(struct pred_stack *stack, int n_preds)
>  {
>  	stack->preds = kcalloc(n_preds + 1, sizeof(*stack->preds), GFP_KERNEL);
> @@ -1337,7 +1310,7 @@ static struct filter_pred *create_pred(struct filter_parse_state *ps,
>  		return NULL;
>  	}
>  
> -	field = find_event_field(call, operand1);
> +	field = trace_find_event_field(call, operand1);
>  	if (!field) {
>  		parse_error(ps, FILT_ERR_FIELD_NOT_FOUND, 0);
>  		return NULL;
> @@ -1907,16 +1880,17 @@ out_unlock:
>  	return err;
>  }
>  
> -int apply_subsystem_event_filter(struct event_subsystem *system,
> +int apply_subsystem_event_filter(struct ftrace_subsystem_dir *dir,
>  				 char *filter_string)
>  {
> +	struct event_subsystem *system = dir->subsystem;
>  	struct event_filter *filter;
>  	int err = 0;
>  
>  	mutex_lock(&event_mutex);
>  
>  	/* Make sure the system still has events */
> -	if (!system->nr_events) {
> +	if (!dir->nr_events) {
>  		err = -ENODEV;
>  		goto out_unlock;
>  	}
> diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
> index e039906..d21a746 100644
> --- a/kernel/trace/trace_export.c
> +++ b/kernel/trace/trace_export.c
> @@ -129,7 +129,7 @@ static void __always_unused ____ftrace_check_##name(void)		\
>  
>  #undef FTRACE_ENTRY
>  #define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter)	\
> -int									\
> +static int __init							\
>  ftrace_define_fields_##name(struct ftrace_event_call *event_call)	\
>  {									\
>  	struct struct_name field;					\
> @@ -168,7 +168,7 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call)	\
>  #define FTRACE_ENTRY_REG(call, struct_name, etype, tstruct, print, filter,\
>  			 regfn)						\
>  									\
> -struct ftrace_event_class event_class_ftrace_##call = {			\
> +struct ftrace_event_class __refdata event_class_ftrace_##call = {	\
>  	.system			= __stringify(TRACE_SYSTEM),		\
>  	.define_fields		= ftrace_define_fields_##call,		\
>  	.fields			= LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
> diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
> index 6011525..c4d6d71 100644
> --- a/kernel/trace/trace_functions.c
> +++ b/kernel/trace/trace_functions.c
> @@ -28,7 +28,7 @@ static void tracing_stop_function_trace(void);
>  static int function_trace_init(struct trace_array *tr)
>  {
>  	func_trace = tr;
> -	tr->cpu = get_cpu();
> +	tr->trace_buffer.cpu = get_cpu();
>  	put_cpu();
>  
>  	tracing_start_cmdline_record();
> @@ -44,7 +44,7 @@ static void function_trace_reset(struct trace_array *tr)
>  
>  static void function_trace_start(struct trace_array *tr)
>  {
> -	tracing_reset_online_cpus(tr);
> +	tracing_reset_online_cpus(&tr->trace_buffer);
>  }
>  
>  /* Our option */
> @@ -76,7 +76,7 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,
>  		goto out;
>  
>  	cpu = smp_processor_id();
> -	data = tr->data[cpu];
> +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
>  	if (!atomic_read(&data->disabled)) {
>  		local_save_flags(flags);
>  		trace_function(tr, ip, parent_ip, flags, pc);
> @@ -107,7 +107,7 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
>  	 */
>  	local_irq_save(flags);
>  	cpu = raw_smp_processor_id();
> -	data = tr->data[cpu];
> +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
>  	disabled = atomic_inc_return(&data->disabled);
>  
>  	if (likely(disabled == 1)) {
> @@ -214,66 +214,89 @@ static struct tracer function_trace __read_mostly =
>  };
>  
>  #ifdef CONFIG_DYNAMIC_FTRACE
> -static void
> -ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
> +static int update_count(void **data)
>  {
> -	long *count = (long *)data;
> -
> -	if (tracing_is_on())
> -		return;
> +	unsigned long *count = (long *)data;
>  
>  	if (!*count)
> -		return;
> +		return 0;
>  
>  	if (*count != -1)
>  		(*count)--;
>  
> -	tracing_on();
> +	return 1;
>  }
>  
>  static void
> -ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
> +ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, void **data)
>  {
> -	long *count = (long *)data;
> +	if (tracing_is_on())
> +		return;
> +
> +	if (update_count(data))
> +		tracing_on();
> +}
>  
> +static void
> +ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, void **data)
> +{
>  	if (!tracing_is_on())
>  		return;
>  
> -	if (!*count)
> +	if (update_count(data))
> +		tracing_off();
> +}
> +
> +static void
> +ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
> +{
> +	if (tracing_is_on())
>  		return;
>  
> -	if (*count != -1)
> -		(*count)--;
> +	tracing_on();
> +}
> +
> +static void
> +ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
> +{
> +	if (!tracing_is_on())
> +		return;
>  
>  	tracing_off();
>  }
>  
> -static int
> -ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
> -			 struct ftrace_probe_ops *ops, void *data);
> +/*
> + * Skip 4:
> + *   ftrace_stacktrace()
> + *   function_trace_probe_call()
> + *   ftrace_ops_list_func()
> + *   ftrace_call()
> + */
> +#define STACK_SKIP 4
>  
> -static struct ftrace_probe_ops traceon_probe_ops = {
> -	.func			= ftrace_traceon,
> -	.print			= ftrace_trace_onoff_print,
> -};
> +static void
> +ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, void **data)
> +{
> +	trace_dump_stack(STACK_SKIP);
> +}
>  
> -static struct ftrace_probe_ops traceoff_probe_ops = {
> -	.func			= ftrace_traceoff,
> -	.print			= ftrace_trace_onoff_print,
> -};
> +static void
> +ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data)
> +{
> +	if (!tracing_is_on())
> +		return;
> +
> +	if (update_count(data))
> +		trace_dump_stack(STACK_SKIP);
> +}
>  
>  static int
> -ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
> -			 struct ftrace_probe_ops *ops, void *data)
> +ftrace_probe_print(const char *name, struct seq_file *m,
> +		   unsigned long ip, void *data)
>  {
>  	long count = (long)data;
>  
> -	seq_printf(m, "%ps:", (void *)ip);
> -
> -	if (ops == &traceon_probe_ops)
> -		seq_printf(m, "traceon");
> -	else
> -		seq_printf(m, "traceoff");
> +	seq_printf(m, "%ps:%s", (void *)ip, name);
>  
>  	if (count == -1)
>  		seq_printf(m, ":unlimited\n");
> @@ -284,26 +307,61 @@ ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
>  }
>  
>  static int
> -ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param)
> +ftrace_traceon_print(struct seq_file *m, unsigned long ip,
> +			 struct ftrace_probe_ops *ops, void *data)
>  {
> -	struct ftrace_probe_ops *ops;
> -
> -	/* we register both traceon and traceoff to this callback */
> -	if (strcmp(cmd, "traceon") == 0)
> -		ops = &traceon_probe_ops;
> -	else
> -		ops = &traceoff_probe_ops;
> +	return ftrace_probe_print("traceon", m, ip, data);
> +}
>  
> -	unregister_ftrace_function_probe_func(glob, ops);
> +static int
> +ftrace_traceoff_print(struct seq_file *m, unsigned long ip,
> +			 struct ftrace_probe_ops *ops, void *data)
> +{
> +	return ftrace_probe_print("traceoff", m, ip, data);
> +}
>  
> -	return 0;
> +static int
> +ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
> +			struct ftrace_probe_ops *ops, void *data)
> +{
> +	return ftrace_probe_print("stacktrace", m, ip, data);
>  }
>  
> +static struct ftrace_probe_ops traceon_count_probe_ops = {
> +	.func			= ftrace_traceon_count,
> +	.print			= ftrace_traceon_print,
> +};
> +
> +static struct ftrace_probe_ops traceoff_count_probe_ops = {
> +	.func			= ftrace_traceoff_count,
> +	.print			= ftrace_traceoff_print,
> +};
> +
> +static struct ftrace_probe_ops stacktrace_count_probe_ops = {
> +	.func			= ftrace_stacktrace_count,
> +	.print			= ftrace_stacktrace_print,
> +};
> +
> +static struct ftrace_probe_ops traceon_probe_ops = {
> +	.func			= ftrace_traceon,
> +	.print			= ftrace_traceon_print,
> +};
> +
> +static struct ftrace_probe_ops traceoff_probe_ops = {
> +	.func			= ftrace_traceoff,
> +	.print			= ftrace_traceoff_print,
> +};
> +
> +static struct ftrace_probe_ops stacktrace_probe_ops = {
> +	.func			= ftrace_stacktrace,
> +	.print			= ftrace_stacktrace_print,
> +};
> +
>  static int
> -ftrace_trace_onoff_callback(struct ftrace_hash *hash,
> -			    char *glob, char *cmd, char *param, int enable)
> +ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
> +			    struct ftrace_hash *hash, char *glob,
> +			    char *cmd, char *param, int enable)
>  {
> -	struct ftrace_probe_ops *ops;
>  	void *count = (void *)-1;
>  	char *number;
>  	int ret;
> @@ -312,14 +370,10 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,
>  	if (!enable)
>  		return -EINVAL;
>  
> -	if (glob[0] == '!')
> -		return ftrace_trace_onoff_unreg(glob+1, cmd, param);
> -
> -	/* we register both traceon and traceoff to this callback */
> -	if (strcmp(cmd, "traceon") == 0)
> -		ops = &traceon_probe_ops;
> -	else
> -		ops = &traceoff_probe_ops;
> +	if (glob[0] == '!') {
> +		unregister_ftrace_function_probe_func(glob+1, ops);
> +		return 0;
> +	}
>  
>  	if (!param)
>  		goto out_reg;
> @@ -343,6 +397,34 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,
>  	return ret < 0 ? ret : 0;
>  }
>  
> +static int
> +ftrace_trace_onoff_callback(struct ftrace_hash *hash,
> +			    char *glob, char *cmd, char *param, int enable)
> +{
> +	struct ftrace_probe_ops *ops;
> +
> +	/* we register both traceon and traceoff to this callback */
> +	if (strcmp(cmd, "traceon") == 0)
> +		ops = param ? &traceon_count_probe_ops : &traceon_probe_ops;
> +	else
> +		ops = param ? &traceoff_count_probe_ops : &traceoff_probe_ops;
> +
> +	return ftrace_trace_probe_callback(ops, hash, glob, cmd,
> +					   param, enable);
> +}
> +
> +static int
> +ftrace_stacktrace_callback(struct ftrace_hash *hash,
> +			   char *glob, char *cmd, char *param, int enable)
> +{
> +	struct ftrace_probe_ops *ops;
> +
> +	ops = param ? &stacktrace_count_probe_ops : &stacktrace_probe_ops;
> +
> +	return ftrace_trace_probe_callback(ops, hash, glob, cmd,
> +					   param, enable);
> +}
> +
>  static struct ftrace_func_command ftrace_traceon_cmd = {
>  	.name			= "traceon",
>  	.func			= ftrace_trace_onoff_callback,
> @@ -353,6 +435,11 @@ static struct ftrace_func_command ftrace_traceoff_cmd = {
>  	.func			= ftrace_trace_onoff_callback,
>  };
>  
> +static struct ftrace_func_command ftrace_stacktrace_cmd = {
> +	.name			= "stacktrace",
> +	.func			= ftrace_stacktrace_callback,
> +};
> +
>  static int __init init_func_cmd_traceon(void)
>  {
>  	int ret;
> @@ -364,6 +451,12 @@ static int __init init_func_cmd_traceon(void)
>  	ret = register_ftrace_command(&ftrace_traceon_cmd);
>  	if (ret)
>  		unregister_ftrace_command(&ftrace_traceoff_cmd);
> +
> +	ret = register_ftrace_command(&ftrace_stacktrace_cmd);
> +	if (ret) {
> +		unregister_ftrace_command(&ftrace_traceoff_cmd);
> +		unregister_ftrace_command(&ftrace_traceon_cmd);
> +	}
>  	return ret;
>  }
>  #else
> diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
> index 39ada66..8388bc9 100644
> --- a/kernel/trace/trace_functions_graph.c
> +++ b/kernel/trace/trace_functions_graph.c
> @@ -218,7 +218,7 @@ int __trace_graph_entry(struct trace_array *tr,
>  {
>  	struct ftrace_event_call *call = &event_funcgraph_entry;
>  	struct ring_buffer_event *event;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  	struct ftrace_graph_ent_entry *entry;
>  
>  	if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
> @@ -265,7 +265,7 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)
>  
>  	local_irq_save(flags);
>  	cpu = raw_smp_processor_id();
> -	data = tr->data[cpu];
> +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
>  	disabled = atomic_inc_return(&data->disabled);
>  	if (likely(disabled == 1)) {
>  		pc = preempt_count();
> @@ -323,7 +323,7 @@ void __trace_graph_return(struct trace_array *tr,
>  {
>  	struct ftrace_event_call *call = &event_funcgraph_exit;
>  	struct ring_buffer_event *event;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  	struct ftrace_graph_ret_entry *entry;
>  
>  	if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
> @@ -350,7 +350,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace)
>  
>  	local_irq_save(flags);
>  	cpu = raw_smp_processor_id();
> -	data = tr->data[cpu];
> +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
>  	disabled = atomic_inc_return(&data->disabled);
>  	if (likely(disabled == 1)) {
>  		pc = preempt_count();
> @@ -560,9 +560,9 @@ get_return_for_leaf(struct trace_iterator *iter,
>  			 * We need to consume the current entry to see
>  			 * the next one.
>  			 */
> -			ring_buffer_consume(iter->tr->buffer, iter->cpu,
> +			ring_buffer_consume(iter->trace_buffer->buffer, iter->cpu,
>  					    NULL, NULL);
> -			event = ring_buffer_peek(iter->tr->buffer, iter->cpu,
> +			event = ring_buffer_peek(iter->trace_buffer->buffer, iter->cpu,
>  						 NULL, NULL);
>  		}
>  
> diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
> index 443b25b..b19d065 100644
> --- a/kernel/trace/trace_irqsoff.c
> +++ b/kernel/trace/trace_irqsoff.c
> @@ -33,6 +33,7 @@ enum {
>  static int trace_type __read_mostly;
>  
>  static int save_flags;
> +static bool function_enabled;
>  
>  static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
>  static int start_irqsoff_tracer(struct trace_array *tr, int graph);
> @@ -121,7 +122,7 @@ static int func_prolog_dec(struct trace_array *tr,
>  	if (!irqs_disabled_flags(*flags))
>  		return 0;
>  
> -	*data = tr->data[cpu];
> +	*data = per_cpu_ptr(tr->trace_buffer.data, cpu);
>  	disabled = atomic_inc_return(&(*data)->disabled);
>  
>  	if (likely(disabled == 1))
> @@ -175,7 +176,7 @@ static int irqsoff_set_flag(u32 old_flags, u32 bit, int set)
>  		per_cpu(tracing_cpu, cpu) = 0;
>  
>  	tracing_max_latency = 0;
> -	tracing_reset_online_cpus(irqsoff_trace);
> +	tracing_reset_online_cpus(&irqsoff_trace->trace_buffer);
>  
>  	return start_irqsoff_tracer(irqsoff_trace, set);
>  }
> @@ -380,7 +381,7 @@ start_critical_timing(unsigned long ip, unsigned long parent_ip)
>  	if (per_cpu(tracing_cpu, cpu))
>  		return;
>  
> -	data = tr->data[cpu];
> +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
>  
>  	if (unlikely(!data) || atomic_read(&data->disabled))
>  		return;
> @@ -418,7 +419,7 @@ stop_critical_timing(unsigned long ip, unsigned long parent_ip)
>  	if (!tracer_enabled)
>  		return;
>  
> -	data = tr->data[cpu];
> +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);
>  
>  	if (unlikely(!data) ||
>  	    !data->critical_start || atomic_read(&data->disabled))
> @@ -528,15 +529,60 @@ void trace_preempt_off(unsigned long a0, unsigned long a1)
>  }
>  #endif /* CONFIG_PREEMPT_TRACER */
>  
> -static int start_irqsoff_tracer(struct trace_array *tr, int graph)
> +static int register_irqsoff_function(int graph, int set)
>  {
> -	int ret = 0;
> +	int ret;
>  
> -	if (!graph)
> -		ret = register_ftrace_function(&trace_ops);
> -	else
> +	/* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
> +	if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
> +		return 0;
> +
> +	if (graph)
>  		ret = register_ftrace_graph(&irqsoff_graph_return,
>  					    &irqsoff_graph_entry);
> +	else
> +		ret = register_ftrace_function(&trace_ops);
> +
> +	if (!ret)
> +		function_enabled = true;
> +
> +	return ret;
> +}
> +
> +static void unregister_irqsoff_function(int graph)
> +{
> +	if (!function_enabled)
> +		return;
> +
> +	if (graph)
> +		unregister_ftrace_graph();
> +	else
> +		unregister_ftrace_function(&trace_ops);
> +
> +	function_enabled = false;
> +}
> +
> +static void irqsoff_function_set(int set)
> +{
> +	if (set)
> +		register_irqsoff_function(is_graph(), 1);
> +	else
> +		unregister_irqsoff_function(is_graph());
> +}
> +
> +static int irqsoff_flag_changed(struct tracer *tracer, u32 mask, int set)
> +{
> +	if (mask & TRACE_ITER_FUNCTION)
> +		irqsoff_function_set(set);
> +
> +	return trace_keep_overwrite(tracer, mask, set);
> +}
> +
> +static int start_irqsoff_tracer(struct trace_array *tr, int graph)
> +{
> +	int ret;
> +
> +	ret = register_irqsoff_function(graph, 0);
>  
>  	if (!ret && tracing_is_enabled())
>  		tracer_enabled = 1;
> @@ -550,10 +596,7 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
>  {
>  	tracer_enabled = 0;
>  
> -	if (!graph)
> -		unregister_ftrace_function(&trace_ops);
> -	else
> -		unregister_ftrace_graph();
> +	unregister_irqsoff_function(graph);
>  }
>  
>  static void __irqsoff_tracer_init(struct trace_array *tr)
> @@ -561,14 +604,14 @@ static void __irqsoff_tracer_init(struct trace_array *tr)
>  	save_flags = trace_flags;
>  
>  	/* non overwrite screws up the latency tracers */
> -	set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
> -	set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
> +	set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
> +	set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
>  
>  	tracing_max_latency = 0;
>  	irqsoff_trace = tr;
>  	/* make sure that the tracer is visible */
>  	smp_wmb();
> -	tracing_reset_online_cpus(tr);
> +	tracing_reset_online_cpus(&tr->trace_buffer);
>  
>  	if (start_irqsoff_tracer(tr, is_graph()))
>  		printk(KERN_ERR "failed to start irqsoff tracer\n");
> @@ -581,8 +624,8 @@ static void irqsoff_tracer_reset(struct trace_array *tr)
>  
>  	stop_irqsoff_tracer(tr, is_graph());
>  
> -	set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
> -	set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
> +	set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
> +	set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
>  }
>  
>  static void irqsoff_tracer_start(struct trace_array *tr)
> @@ -615,7 +658,7 @@ static struct tracer irqsoff_tracer __read_mostly =
>  	.print_line     = irqsoff_print_line,
>  	.flags		= &tracer_flags,
>  	.set_flag	= irqsoff_set_flag,
> -	.flag_changed	= trace_keep_overwrite,
> +	.flag_changed	= irqsoff_flag_changed,
>  #ifdef CONFIG_FTRACE_SELFTEST
>  	.selftest    = trace_selftest_startup_irqsoff,
>  #endif
> @@ -649,7 +692,7 @@ static struct tracer preemptoff_tracer __read_mostly =
>  	.print_line     = irqsoff_print_line,
>  	.flags		= &tracer_flags,
>  	.set_flag	= irqsoff_set_flag,
> -	.flag_changed	= trace_keep_overwrite,
> +	.flag_changed	= irqsoff_flag_changed,
>  #ifdef CONFIG_FTRACE_SELFTEST
>  	.selftest    = trace_selftest_startup_preemptoff,
>  #endif
> @@ -685,7 +728,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
>  	.print_line     = irqsoff_print_line,
>  	.flags		= &tracer_flags,
>  	.set_flag	= irqsoff_set_flag,
> -	.flag_changed	= trace_keep_overwrite,
> +	.flag_changed	= irqsoff_flag_changed,
>  #ifdef CONFIG_FTRACE_SELFTEST
>  	.selftest    = trace_selftest_startup_preemptirqsoff,
>  #endif
> diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c
> index 3c5c5df..bd90e1b 100644
> --- a/kernel/trace/trace_kdb.c
> +++ b/kernel/trace/trace_kdb.c
> @@ -26,7 +26,7 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
>  	trace_init_global_iter(&iter);
>  
>  	for_each_tracing_cpu(cpu) {
> -		atomic_inc(&iter.tr->data[cpu]->disabled);
> +		atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
>  	}
>  
>  	old_userobj = trace_flags;
> @@ -43,17 +43,17 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
>  	iter.iter_flags |= TRACE_FILE_LAT_FMT;
>  	iter.pos = -1;
>  
> -	if (cpu_file == TRACE_PIPE_ALL_CPU) {
> +	if (cpu_file == RING_BUFFER_ALL_CPUS) {
>  		for_each_tracing_cpu(cpu) {
>  			iter.buffer_iter[cpu] =
> -			ring_buffer_read_prepare(iter.tr->buffer, cpu);
> +			ring_buffer_read_prepare(iter.trace_buffer->buffer, cpu);
>  			ring_buffer_read_start(iter.buffer_iter[cpu]);
>  			tracing_iter_reset(&iter, cpu);
>  		}
>  	} else {
>  		iter.cpu_file = cpu_file;
>  		iter.buffer_iter[cpu_file] =
> -			ring_buffer_read_prepare(iter.tr->buffer, cpu_file);
> +			ring_buffer_read_prepare(iter.trace_buffer->buffer, cpu_file);
>  		ring_buffer_read_start(iter.buffer_iter[cpu_file]);
>  		tracing_iter_reset(&iter, cpu_file);
>  	}
> @@ -83,7 +83,7 @@ out:
>  	trace_flags = old_userobj;
>  
>  	for_each_tracing_cpu(cpu) {
> -		atomic_dec(&iter.tr->data[cpu]->disabled);
> +		atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
>  	}
>  
>  	for_each_tracing_cpu(cpu)
> @@ -115,7 +115,7 @@ static int kdb_ftdump(int argc, const char **argv)
>  		    !cpu_online(cpu_file))
>  			return KDB_BADINT;
>  	} else {
> -		cpu_file = TRACE_PIPE_ALL_CPU;
> +		cpu_file = RING_BUFFER_ALL_CPUS;
>  	}
>  
>  	kdb_trap_printk++;
> diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c
> index fd3c8aa..a5e8f48 100644
> --- a/kernel/trace/trace_mmiotrace.c
> +++ b/kernel/trace/trace_mmiotrace.c
> @@ -31,7 +31,7 @@ static void mmio_reset_data(struct trace_array *tr)
>  	overrun_detected = false;
>  	prev_overruns = 0;
>  
> -	tracing_reset_online_cpus(tr);
> +	tracing_reset_online_cpus(&tr->trace_buffer);
>  }
>  
>  static int mmio_trace_init(struct trace_array *tr)
> @@ -128,7 +128,7 @@ static void mmio_close(struct trace_iterator *iter)
>  static unsigned long count_overruns(struct trace_iterator *iter)
>  {
>  	unsigned long cnt = atomic_xchg(&dropped_count, 0);
> -	unsigned long over = ring_buffer_overruns(iter->tr->buffer);
> +	unsigned long over = ring_buffer_overruns(iter->trace_buffer->buffer);
>  
>  	if (over > prev_overruns)
>  		cnt += over - prev_overruns;
> @@ -309,7 +309,7 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
>  				struct mmiotrace_rw *rw)
>  {
>  	struct ftrace_event_call *call = &event_mmiotrace_rw;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  	struct ring_buffer_event *event;
>  	struct trace_mmiotrace_rw *entry;
>  	int pc = preempt_count();
> @@ -330,7 +330,7 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
>  void mmio_trace_rw(struct mmiotrace_rw *rw)
>  {
>  	struct trace_array *tr = mmio_trace_array;
> -	struct trace_array_cpu *data = tr->data[smp_processor_id()];
> +	struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, smp_processor_id());
>  	__trace_mmiotrace_rw(tr, data, rw);
>  }
>  
> @@ -339,7 +339,7 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
>  				struct mmiotrace_map *map)
>  {
>  	struct ftrace_event_call *call = &event_mmiotrace_map;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  	struct ring_buffer_event *event;
>  	struct trace_mmiotrace_map *entry;
>  	int pc = preempt_count();
> @@ -363,7 +363,7 @@ void mmio_trace_mapping(struct mmiotrace_map *map)
>  	struct trace_array_cpu *data;
>  
>  	preempt_disable();
> -	data = tr->data[smp_processor_id()];
> +	data = per_cpu_ptr(tr->trace_buffer.data, smp_processor_id());
>  	__trace_mmiotrace_map(tr, data, map);
>  	preempt_enable();
>  }
> diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
> index 194d796..f475b2a 100644
> --- a/kernel/trace/trace_output.c
> +++ b/kernel/trace/trace_output.c
> @@ -14,7 +14,7 @@
>  /* must be a power of 2 */
>  #define EVENT_HASHSIZE	128
>  
> -DECLARE_RWSEM(trace_event_mutex);
> +DECLARE_RWSEM(trace_event_sem);
>  
>  static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
>  
> @@ -37,6 +37,22 @@ int trace_print_seq(struct seq_file *m, struct trace_seq *s)
>  	return ret;
>  }
>  
> +enum print_line_t trace_print_bputs_msg_only(struct trace_iterator *iter)
> +{
> +	struct trace_seq *s = &iter->seq;
> +	struct trace_entry *entry = iter->ent;
> +	struct bputs_entry *field;
> +	int ret;
> +
> +	trace_assign_type(field, entry);
> +
> +	ret = trace_seq_puts(s, field->str);
> +	if (!ret)
> +		return TRACE_TYPE_PARTIAL_LINE;
> +
> +	return TRACE_TYPE_HANDLED;
> +}
> +
>  enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
>  {
>  	struct trace_seq *s = &iter->seq;
> @@ -397,6 +413,32 @@ ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len)
>  }
>  EXPORT_SYMBOL(ftrace_print_hex_seq);
>  
> +int ftrace_raw_output_prep(struct trace_iterator *iter,
> +			   struct trace_event *trace_event)
> +{
> +	struct ftrace_event_call *event;
> +	struct trace_seq *s = &iter->seq;
> +	struct trace_seq *p = &iter->tmp_seq;
> +	struct trace_entry *entry;
> +	int ret;
> +
> +	event = container_of(trace_event, struct ftrace_event_call, event);
> +	entry = iter->ent;
> +
> +	if (entry->type != event->event.type) {
> +		WARN_ON_ONCE(1);
> +		return TRACE_TYPE_UNHANDLED;
> +	}
> +
> +	trace_seq_init(p);
> +	ret = trace_seq_printf(s, "%s: ", event->name);
> +	if (!ret)
> +		return TRACE_TYPE_PARTIAL_LINE;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ftrace_raw_output_prep);
> +
>  #ifdef CONFIG_KRETPROBES
>  static inline const char *kretprobed(const char *name)
>  {
> @@ -617,7 +659,7 @@ lat_print_timestamp(struct trace_iterator *iter, u64 next_ts)
>  {
>  	unsigned long verbose = trace_flags & TRACE_ITER_VERBOSE;
>  	unsigned long in_ns = iter->iter_flags & TRACE_FILE_TIME_IN_NS;
> -	unsigned long long abs_ts = iter->ts - iter->tr->time_start;
> +	unsigned long long abs_ts = iter->ts - iter->trace_buffer->time_start;
>  	unsigned long long rel_ts = next_ts - iter->ts;
>  	struct trace_seq *s = &iter->seq;
>  
> @@ -784,12 +826,12 @@ static int trace_search_list(struct list_head **list)
>  
>  void trace_event_read_lock(void)
>  {
> -	down_read(&trace_event_mutex);
> +	down_read(&trace_event_sem);
>  }
>  
>  void trace_event_read_unlock(void)
>  {
> -	up_read(&trace_event_mutex);
> +	up_read(&trace_event_sem);
>  }
>  
>  /**
> @@ -812,7 +854,7 @@ int register_ftrace_event(struct trace_event *event)
>  	unsigned key;
>  	int ret = 0;
>  
> -	down_write(&trace_event_mutex);
> +	down_write(&trace_event_sem);
>  
>  	if (WARN_ON(!event))
>  		goto out;
> @@ -867,14 +909,14 @@ int register_ftrace_event(struct trace_event *event)
>  
>  	ret = event->type;
>   out:
> -	up_write(&trace_event_mutex);
> +	up_write(&trace_event_sem);
>  
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(register_ftrace_event);
>  
>  /*
> - * Used by module code with the trace_event_mutex held for write.
> + * Used by module code with the trace_event_sem held for write.
>   */
>  int __unregister_ftrace_event(struct trace_event *event)
>  {
> @@ -889,9 +931,9 @@ int __unregister_ftrace_event(struct trace_event *event)
>   */
>  int unregister_ftrace_event(struct trace_event *event)
>  {
> -	down_write(&trace_event_mutex);
> +	down_write(&trace_event_sem);
>  	__unregister_ftrace_event(event);
> -	up_write(&trace_event_mutex);
> +	up_write(&trace_event_sem);
>  
>  	return 0;
>  }
> @@ -1218,6 +1260,64 @@ static struct trace_event trace_user_stack_event = {
>  	.funcs		= &trace_user_stack_funcs,
>  };
>  
> +/* TRACE_BPUTS */
> +static enum print_line_t
> +trace_bputs_print(struct trace_iterator *iter, int flags,
> +		   struct trace_event *event)
> +{
> +	struct trace_entry *entry = iter->ent;
> +	struct trace_seq *s = &iter->seq;
> +	struct bputs_entry *field;
> +
> +	trace_assign_type(field, entry);
> +
> +	if (!seq_print_ip_sym(s, field->ip, flags))
> +		goto partial;
> +
> +	if (!trace_seq_puts(s, ": "))
> +		goto partial;
> +
> +	if (!trace_seq_puts(s, field->str))
> +		goto partial;
> +
> +	return TRACE_TYPE_HANDLED;
> +
> + partial:
> +	return TRACE_TYPE_PARTIAL_LINE;
> +}
> +
> +
> +static enum print_line_t
> +trace_bputs_raw(struct trace_iterator *iter, int flags,
> +		struct trace_event *event)
> +{
> +	struct bputs_entry *field;
> +	struct trace_seq *s = &iter->seq;
> +
> +	trace_assign_type(field, iter->ent);
> +
> +	if (!trace_seq_printf(s, ": %lx : ", field->ip))
> +		goto partial;
> +
> +	if (!trace_seq_puts(s, field->str))
> +		goto partial;
> +
> +	return TRACE_TYPE_HANDLED;
> +
> + partial:
> +	return TRACE_TYPE_PARTIAL_LINE;
> +}
> +
> +static struct trace_event_functions trace_bputs_funcs = {
> +	.trace		= trace_bputs_print,
> +	.raw		= trace_bputs_raw,
> +};
> +
> +static struct trace_event trace_bputs_event = {
> +	.type		= TRACE_BPUTS,
> +	.funcs		= &trace_bputs_funcs,
> +};
> +
>  /* TRACE_BPRINT */
>  static enum print_line_t
>  trace_bprint_print(struct trace_iterator *iter, int flags,
> @@ -1330,6 +1430,7 @@ static struct trace_event *events[] __initdata = {
>  	&trace_wake_event,
>  	&trace_stack_event,
>  	&trace_user_stack_event,
> +	&trace_bputs_event,
>  	&trace_bprint_event,
>  	&trace_print_event,
>  	NULL
> diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
> index c038eba..127a9d8 100644
> --- a/kernel/trace/trace_output.h
> +++ b/kernel/trace/trace_output.h
> @@ -5,6 +5,8 @@
>  #include "trace.h"
>  
>  extern enum print_line_t
> +trace_print_bputs_msg_only(struct trace_iterator *iter);
> +extern enum print_line_t
>  trace_print_bprintk_msg_only(struct trace_iterator *iter);
>  extern enum print_line_t
>  trace_print_printk_msg_only(struct trace_iterator *iter);
> @@ -31,7 +33,7 @@ trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry);
>  
>  /* used by module unregistering */
>  extern int __unregister_ftrace_event(struct trace_event *event);
> -extern struct rw_semaphore trace_event_mutex;
> +extern struct rw_semaphore trace_event_sem;
>  
>  #define MAX_MEMHEX_BYTES	8
>  #define HEX_CHARS		(MAX_MEMHEX_BYTES*2 + 1)
> diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c
> index 3374c79..4e98e3b 100644
> --- a/kernel/trace/trace_sched_switch.c
> +++ b/kernel/trace/trace_sched_switch.c
> @@ -28,7 +28,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
>  			   unsigned long flags, int pc)
>  {
>  	struct ftrace_event_call *call = &event_context_switch;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  	struct ring_buffer_event *event;
>  	struct ctx_switch_entry *entry;
>  
> @@ -69,7 +69,7 @@ probe_sched_switch(void *ignore, struct task_struct *prev, struct task_struct *n
>  	pc = preempt_count();
>  	local_irq_save(flags);
>  	cpu = raw_smp_processor_id();
> -	data = ctx_trace->data[cpu];
> +	data = per_cpu_ptr(ctx_trace->trace_buffer.data, cpu);
>  
>  	if (likely(!atomic_read(&data->disabled)))
>  		tracing_sched_switch_trace(ctx_trace, prev, next, flags, pc);
> @@ -86,7 +86,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
>  	struct ftrace_event_call *call = &event_wakeup;
>  	struct ring_buffer_event *event;
>  	struct ctx_switch_entry *entry;
> -	struct ring_buffer *buffer = tr->buffer;
> +	struct ring_buffer *buffer = tr->trace_buffer.buffer;
>  
>  	event = trace_buffer_lock_reserve(buffer, TRACE_WAKE,
>  					  sizeof(*entry), flags, pc);
> @@ -123,7 +123,7 @@ probe_sched_wakeup(void *ignore, struct task_struct *wakee, int success)
>  	pc = preempt_count();
>  	local_irq_save(flags);
>  	cpu = raw_smp_processor_id();
> -	data = ctx_trace->data[cpu];
> +	data = per_cpu_ptr(ctx_trace->trace_buffer.data, cpu);
>  
>  	if (likely(!atomic_read(&data->disabled)))
>  		tracing_sched_wakeup_trace(ctx_trace, wakee, current,
> diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
> index fde652c..fee77e1 100644
> --- a/kernel/trace/trace_sched_wakeup.c
> +++ b/kernel/trace/trace_sched_wakeup.c
> @@ -37,6 +37,7 @@ static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
>  static void wakeup_graph_return(struct ftrace_graph_ret *trace);
>  
>  static int save_flags;
> +static bool function_enabled;
>  
>  #define TRACE_DISPLAY_GRAPH     1
>  
> @@ -89,7 +90,7 @@ func_prolog_preempt_disable(struct trace_array *tr,
>  	if (cpu != wakeup_current_cpu)
>  		goto out_enable;
>  
> -	*data = tr->data[cpu];
> +	*data = per_cpu_ptr(tr->trace_buffer.data, cpu);
>  	disabled = atomic_inc_return(&(*data)->disabled);
>  	if (unlikely(disabled != 1))
>  		goto out;
> @@ -134,15 +135,60 @@ static struct ftrace_ops trace_ops __read_mostly =
>  };
>  #endif /* CONFIG_FUNCTION_TRACER */
>  
> -static int start_func_tracer(int graph)
> +static int register_wakeup_function(int graph, int set)
>  {
>  	int ret;
>  
> -	if (!graph)
> -		ret = register_ftrace_function(&trace_ops);
> -	else
> +	/* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
> +	if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
> +		return 0;
> +
> +	if (graph)
>  		ret = register_ftrace_graph(&wakeup_graph_return,
>  					    &wakeup_graph_entry);
> +	else
> +		ret = register_ftrace_function(&trace_ops);
> +
> +	if (!ret)
> +		function_enabled = true;
> +
> +	return ret;
> +}
> +
> +static void unregister_wakeup_function(int graph)
> +{
> +	if (!function_enabled)
> +		return;
> +
> +	if (graph)
> +		unregister_ftrace_graph();
> +	else
> +		unregister_ftrace_function(&trace_ops);
> +
> +	function_enabled = false;
> +}
> +
> +static void wakeup_function_set(int set)
> +{
> +	if (set)
> +		register_wakeup_function(is_graph(), 1);
> +	else
> +		unregister_wakeup_function(is_graph());
> +}
> +
> +static int wakeup_flag_changed(struct tracer *tracer, u32 mask, int set)
> +{
> +	if (mask & TRACE_ITER_FUNCTION)
> +		wakeup_function_set(set);
> +
> +	return trace_keep_overwrite(tracer, mask, set);
> +}
> +
> +static int start_func_tracer(int graph)
> +{
> +	int ret;
> +
> +	ret = register_wakeup_function(graph, 0);
>  
>  	if (!ret && tracing_is_enabled())
>  		tracer_enabled = 1;
> @@ -156,10 +202,7 @@ static void stop_func_tracer(int graph)
>  {
>  	tracer_enabled = 0;
>  
> -	if (!graph)
> -		unregister_ftrace_function(&trace_ops);
> -	else
> -		unregister_ftrace_graph();
> +	unregister_wakeup_function(graph);
>  }
>  
>  #ifdef CONFIG_FUNCTION_GRAPH_TRACER
> @@ -353,7 +396,7 @@ probe_wakeup_sched_switch(void *ignore,
>  
>  	/* disable local data, not wakeup_cpu data */
>  	cpu = raw_smp_processor_id();
> -	disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
> +	disabled = atomic_inc_return(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
>  	if (likely(disabled != 1))
>  		goto out;
>  
> @@ -365,7 +408,7 @@ probe_wakeup_sched_switch(void *ignore,
>  		goto out_unlock;
>  
>  	/* The task we are waiting for is waking up */
> -	data = wakeup_trace->data[wakeup_cpu];
> +	data = per_cpu_ptr(wakeup_trace->trace_buffer.data, wakeup_cpu);
>  
>  	__trace_function(wakeup_trace, CALLER_ADDR0, CALLER_ADDR1, flags, pc);
>  	tracing_sched_switch_trace(wakeup_trace, prev, next, flags, pc);
> @@ -387,7 +430,7 @@ out_unlock:
>  	arch_spin_unlock(&wakeup_lock);
>  	local_irq_restore(flags);
>  out:
> -	atomic_dec(&wakeup_trace->data[cpu]->disabled);
> +	atomic_dec(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
>  }
>  
>  static void __wakeup_reset(struct trace_array *tr)
> @@ -405,7 +448,7 @@ static void wakeup_reset(struct trace_array *tr)
>  {
>  	unsigned long flags;
>  
> -	tracing_reset_online_cpus(tr);
> +	tracing_reset_online_cpus(&tr->trace_buffer);
>  
>  	local_irq_save(flags);
>  	arch_spin_lock(&wakeup_lock);
> @@ -435,7 +478,7 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)
>  		return;
>  
>  	pc = preempt_count();
> -	disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
> +	disabled = atomic_inc_return(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
>  	if (unlikely(disabled != 1))
>  		goto out;
>  
> @@ -458,7 +501,7 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)
>  
>  	local_save_flags(flags);
>  
> -	data = wakeup_trace->data[wakeup_cpu];
> +	data = per_cpu_ptr(wakeup_trace->trace_buffer.data, wakeup_cpu);
>  	data->preempt_timestamp = ftrace_now(cpu);
>  	tracing_sched_wakeup_trace(wakeup_trace, p, current, flags, pc);
>  
> @@ -472,7 +515,7 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)
>  out_locked:
>  	arch_spin_unlock(&wakeup_lock);
>  out:
> -	atomic_dec(&wakeup_trace->data[cpu]->disabled);
> +	atomic_dec(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
>  }
>  
>  static void start_wakeup_tracer(struct trace_array *tr)
> @@ -543,8 +586,8 @@ static int __wakeup_tracer_init(struct trace_array *tr)
>  	save_flags = trace_flags;
>  
>  	/* non overwrite screws up the latency tracers */
> -	set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
> -	set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
> +	set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
> +	set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
>  
>  	tracing_max_latency = 0;
>  	wakeup_trace = tr;
> @@ -573,8 +616,8 @@ static void wakeup_tracer_reset(struct trace_array *tr)
>  	/* make sure we put back any tasks we are tracing */
>  	wakeup_reset(tr);
>  
> -	set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
> -	set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
> +	set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
> +	set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
>  }
>  
>  static void wakeup_tracer_start(struct trace_array *tr)
> @@ -600,7 +643,7 @@ static struct tracer wakeup_tracer __read_mostly =
>  	.print_line	= wakeup_print_line,
>  	.flags		= &tracer_flags,
>  	.set_flag	= wakeup_set_flag,
> -	.flag_changed	= trace_keep_overwrite,
> +	.flag_changed	= wakeup_flag_changed,
>  #ifdef CONFIG_FTRACE_SELFTEST
>  	.selftest    = trace_selftest_startup_wakeup,
>  #endif
> @@ -622,7 +665,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
>  	.print_line	= wakeup_print_line,
>  	.flags		= &tracer_flags,
>  	.set_flag	= wakeup_set_flag,
> -	.flag_changed	= trace_keep_overwrite,
> +	.flag_changed	= wakeup_flag_changed,
>  #ifdef CONFIG_FTRACE_SELFTEST
>  	.selftest    = trace_selftest_startup_wakeup,
>  #endif
> diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
> index 51c819c..55e2cf6 100644
> --- a/kernel/trace/trace_selftest.c
> +++ b/kernel/trace/trace_selftest.c
> @@ -21,13 +21,13 @@ static inline int trace_valid_entry(struct trace_entry *entry)
>  	return 0;
>  }
>  
> -static int trace_test_buffer_cpu(struct trace_array *tr, int cpu)
> +static int trace_test_buffer_cpu(struct trace_buffer *buf, int cpu)
>  {
>  	struct ring_buffer_event *event;
>  	struct trace_entry *entry;
>  	unsigned int loops = 0;
>  
> -	while ((event = ring_buffer_consume(tr->buffer, cpu, NULL, NULL))) {
> +	while ((event = ring_buffer_consume(buf->buffer, cpu, NULL, NULL))) {
>  		entry = ring_buffer_event_data(event);
>  
>  		/*
> @@ -58,7 +58,7 @@ static int trace_test_buffer_cpu(struct trace_array *tr, int cpu)
>   * Test the trace buffer to see if all the elements
>   * are still sane.
>   */
> -static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
> +static int trace_test_buffer(struct trace_buffer *buf, unsigned long *count)
>  {
>  	unsigned long flags, cnt = 0;
>  	int cpu, ret = 0;
> @@ -67,7 +67,7 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
>  	local_irq_save(flags);
>  	arch_spin_lock(&ftrace_max_lock);
>  
> -	cnt = ring_buffer_entries(tr->buffer);
> +	cnt = ring_buffer_entries(buf->buffer);
>  
>  	/*
>  	 * The trace_test_buffer_cpu runs a while loop to consume all data.
> @@ -78,7 +78,7 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
>  	 */
>  	tracing_off();
>  	for_each_possible_cpu(cpu) {
> -		ret = trace_test_buffer_cpu(tr, cpu);
> +		ret = trace_test_buffer_cpu(buf, cpu);
>  		if (ret)
>  			break;
>  	}
> @@ -355,7 +355,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
>  	msleep(100);
>  
>  	/* we should have nothing in the buffer */
> -	ret = trace_test_buffer(tr, &count);
> +	ret = trace_test_buffer(&tr->trace_buffer, &count);
>  	if (ret)
>  		goto out;
>  
> @@ -376,7 +376,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
>  	ftrace_enabled = 0;
>  
>  	/* check the trace buffer */
> -	ret = trace_test_buffer(tr, &count);
> +	ret = trace_test_buffer(&tr->trace_buffer, &count);
>  	tracing_start();
>  
>  	/* we should only have one item */
> @@ -666,7 +666,7 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
>  	ftrace_enabled = 0;
>  
>  	/* check the trace buffer */
> -	ret = trace_test_buffer(tr, &count);
> +	ret = trace_test_buffer(&tr->trace_buffer, &count);
>  	trace->reset(tr);
>  	tracing_start();
>  
> @@ -703,8 +703,6 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
>  /* Maximum number of functions to trace before diagnosing a hang */
>  #define GRAPH_MAX_FUNC_TEST	100000000
>  
> -static void
> -__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode);
>  static unsigned int graph_hang_thresh;
>  
>  /* Wrap the real function entry probe to avoid possible hanging */
> @@ -714,8 +712,11 @@ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace)
>  	if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) {
>  		ftrace_graph_stop();
>  		printk(KERN_WARNING "BUG: Function graph tracer hang!\n");
> -		if (ftrace_dump_on_oops)
> -			__ftrace_dump(false, DUMP_ALL);
> +		if (ftrace_dump_on_oops) {
> +			ftrace_dump(DUMP_ALL);
> +			/* ftrace_dump() disables tracing */
> +			tracing_on();
> +		}
>  		return 0;
>  	}
>  
> @@ -737,7 +738,7 @@ trace_selftest_startup_function_graph(struct tracer *trace,
>  	 * Simulate the init() callback but we attach a watchdog callback
>  	 * to detect and recover from possible hangs
>  	 */
> -	tracing_reset_online_cpus(tr);
> +	tracing_reset_online_cpus(&tr->trace_buffer);
>  	set_graph_array(tr);
>  	ret = register_ftrace_graph(&trace_graph_return,
>  				    &trace_graph_entry_watchdog);
> @@ -760,7 +761,7 @@ trace_selftest_startup_function_graph(struct tracer *trace,
>  	tracing_stop();
>  
>  	/* check the trace buffer */
> -	ret = trace_test_buffer(tr, &count);
> +	ret = trace_test_buffer(&tr->trace_buffer, &count);
>  
>  	trace->reset(tr);
>  	tracing_start();
> @@ -815,9 +816,9 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr)
>  	/* stop the tracing. */
>  	tracing_stop();
>  	/* check both trace buffers */
> -	ret = trace_test_buffer(tr, NULL);
> +	ret = trace_test_buffer(&tr->trace_buffer, NULL);
>  	if (!ret)
> -		ret = trace_test_buffer(&max_tr, &count);
> +		ret = trace_test_buffer(&tr->max_buffer, &count);
>  	trace->reset(tr);
>  	tracing_start();
>  
> @@ -877,9 +878,9 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr)
>  	/* stop the tracing. */
>  	tracing_stop();
>  	/* check both trace buffers */
> -	ret = trace_test_buffer(tr, NULL);
> +	ret = trace_test_buffer(&tr->trace_buffer, NULL);
>  	if (!ret)
> -		ret = trace_test_buffer(&max_tr, &count);
> +		ret = trace_test_buffer(&tr->max_buffer, &count);
>  	trace->reset(tr);
>  	tracing_start();
>  
> @@ -943,11 +944,11 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
>  	/* stop the tracing. */
>  	tracing_stop();
>  	/* check both trace buffers */
> -	ret = trace_test_buffer(tr, NULL);
> +	ret = trace_test_buffer(&tr->trace_buffer, NULL);
>  	if (ret)
>  		goto out;
>  
> -	ret = trace_test_buffer(&max_tr, &count);
> +	ret = trace_test_buffer(&tr->max_buffer, &count);
>  	if (ret)
>  		goto out;
>  
> @@ -973,11 +974,11 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
>  	/* stop the tracing. */
>  	tracing_stop();
>  	/* check both trace buffers */
> -	ret = trace_test_buffer(tr, NULL);
> +	ret = trace_test_buffer(&tr->trace_buffer, NULL);
>  	if (ret)
>  		goto out;
>  
> -	ret = trace_test_buffer(&max_tr, &count);
> +	ret = trace_test_buffer(&tr->max_buffer, &count);
>  
>  	if (!ret && !count) {
>  		printk(KERN_CONT ".. no entries found ..");
> @@ -1084,10 +1085,10 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)
>  	/* stop the tracing. */
>  	tracing_stop();
>  	/* check both trace buffers */
> -	ret = trace_test_buffer(tr, NULL);
> +	ret = trace_test_buffer(&tr->trace_buffer, NULL);
>  	printk("ret = %d\n", ret);
>  	if (!ret)
> -		ret = trace_test_buffer(&max_tr, &count);
> +		ret = trace_test_buffer(&tr->max_buffer, &count);
>  
> 
>  	trace->reset(tr);
> @@ -1126,7 +1127,7 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr
>  	/* stop the tracing. */
>  	tracing_stop();
>  	/* check the trace buffer */
> -	ret = trace_test_buffer(tr, &count);
> +	ret = trace_test_buffer(&tr->trace_buffer, &count);
>  	trace->reset(tr);
>  	tracing_start();
>  
> diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
> index 42ca822..aab277b 100644
> --- a/kernel/trace/trace_stack.c
> +++ b/kernel/trace/trace_stack.c
> @@ -20,13 +20,24 @@
>  
>  #define STACK_TRACE_ENTRIES 500
>  
> +#ifdef CC_USING_FENTRY
> +# define fentry		1
> +#else
> +# define fentry		0
> +#endif
> +
>  static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] =
>  	 { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX };
>  static unsigned stack_dump_index[STACK_TRACE_ENTRIES];
>  
> +/*
> + * Reserve one entry for the passed in ip. This will allow
> + * us to remove most or all of the stack size overhead
> + * added by the stack tracer itself.
> + */
>  static struct stack_trace max_stack_trace = {
> -	.max_entries		= STACK_TRACE_ENTRIES,
> -	.entries		= stack_dump_trace,
> +	.max_entries		= STACK_TRACE_ENTRIES - 1,
> +	.entries		= &stack_dump_trace[1],
>  };
>  
>  static unsigned long max_stack_size;
> @@ -39,25 +50,34 @@ static DEFINE_MUTEX(stack_sysctl_mutex);
>  int stack_tracer_enabled;
>  static int last_stack_tracer_enabled;
>  
> -static inline void check_stack(void)
> +static inline void
> +check_stack(unsigned long ip, unsigned long *stack)
>  {
>  	unsigned long this_size, flags;
>  	unsigned long *p, *top, *start;
> +	static int tracer_frame;
> +	int frame_size = ACCESS_ONCE(tracer_frame);
>  	int i;
>  
> -	this_size = ((unsigned long)&this_size) & (THREAD_SIZE-1);
> +	this_size = ((unsigned long)stack) & (THREAD_SIZE-1);
>  	this_size = THREAD_SIZE - this_size;
> +	/* Remove the frame of the tracer */
> +	this_size -= frame_size;
>  
>  	if (this_size <= max_stack_size)
>  		return;
>  
>  	/* we do not handle interrupt stacks yet */
> -	if (!object_is_on_stack(&this_size))
> +	if (!object_is_on_stack(stack))
>  		return;
>  
>  	local_irq_save(flags);
>  	arch_spin_lock(&max_stack_lock);
>  
> +	/* In case another CPU set the tracer_frame on us */
> +	if (unlikely(!frame_size))
> +		this_size -= tracer_frame;
> +
>  	/* a race could have already updated it */
>  	if (this_size <= max_stack_size)
>  		goto out;
> @@ -70,10 +90,18 @@ static inline void check_stack(void)
>  	save_stack_trace(&max_stack_trace);
>  
>  	/*
> +	 * Add the passed in ip from the function tracer.
> +	 * Searching for this on the stack will skip over
> +	 * most of the overhead from the stack tracer itself.
> +	 */
> +	stack_dump_trace[0] = ip;
> +	max_stack_trace.nr_entries++;
> +
> +	/*
>  	 * Now find where in the stack these are.
>  	 */
>  	i = 0;
> -	start = &this_size;
> +	start = stack;
>  	top = (unsigned long *)
>  		(((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE);
>  
> @@ -97,6 +125,18 @@ static inline void check_stack(void)
>  				found = 1;
>  				/* Start the search from here */
>  				start = p + 1;
> +				/*
> +				 * We do not want to show the overhead
> +				 * of the stack tracer stack in the
> +				 * max stack. If we haven't figured
> +				 * out what that is, then figure it out
> +				 * now.
> +				 */
> +				if (unlikely(!tracer_frame) && i == 1) {
> +					tracer_frame = (p - stack) *
> +						sizeof(unsigned long);
> +					max_stack_size -= tracer_frame;
> +				}
>  			}
>  		}
>  
> @@ -113,6 +153,7 @@ static void
>  stack_trace_call(unsigned long ip, unsigned long parent_ip,
>  		 struct ftrace_ops *op, struct pt_regs *pt_regs)
>  {
> +	unsigned long stack;
>  	int cpu;
>  
>  	preempt_disable_notrace();
> @@ -122,7 +163,26 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip,
>  	if (per_cpu(trace_active, cpu)++ != 0)
>  		goto out;
>  
> -	check_stack();
> +	/*
> +	 * When fentry is used, the traced function does not get
> +	 * its stack frame set up, and we lose the parent.
> +	 * The ip is pretty useless because the function tracer
> +	 * was called before that function set up its stack frame.
> +	 * In this case, we use the parent ip.
> +	 *
> +	 * By adding the return address of either the parent ip
> +	 * or the current ip we can disregard most of the stack usage
> +	 * caused by the stack tracer itself.
> +	 *
> +	 * The function tracer always reports the address of where the
> +	 * mcount call was, but the stack will hold the return address.
> +	 */
> +	if (fentry)
> +		ip = parent_ip;
> +	else
> +		ip += MCOUNT_INSN_SIZE;
> +
> +	check_stack(ip, &stack);
>  
>   out:
>  	per_cpu(trace_active, cpu)--;
> diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
> index 7a809e3..8f2ac73 100644
> --- a/kernel/trace/trace_syscalls.c
> +++ b/kernel/trace/trace_syscalls.c
> @@ -12,10 +12,6 @@
>  #include "trace.h"
>  
>  static DEFINE_MUTEX(syscall_trace_lock);
> -static int sys_refcount_enter;
> -static int sys_refcount_exit;
> -static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
> -static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
>  
>  static int syscall_enter_register(struct ftrace_event_call *event,
>  				 enum trace_reg type, void *data);
> @@ -41,7 +37,7 @@ static inline bool arch_syscall_match_sym_name(const char *sym, const char *name
>  	/*
>  	 * Only compare after the "sys" prefix. Archs that use
>  	 * syscall wrappers may have syscalls symbols aliases prefixed
> -	 * with "SyS" instead of "sys", leading to an unwanted
> +	 * with ".SyS" or ".sys" instead of "sys", leading to an unwanted
>  	 * mismatch.
>  	 */
>  	return !strcmp(sym + 3, name + 3);
> @@ -265,7 +261,7 @@ static void free_syscall_print_fmt(struct ftrace_event_call *call)
>  		kfree(call->print_fmt);
>  }
>  
> -static int syscall_enter_define_fields(struct ftrace_event_call *call)
> +static int __init syscall_enter_define_fields(struct ftrace_event_call *call)
>  {
>  	struct syscall_trace_enter trace;
>  	struct syscall_metadata *meta = call->data;
> @@ -288,7 +284,7 @@ static int syscall_enter_define_fields(struct ftrace_event_call *call)
>  	return ret;
>  }
>  
> -static int syscall_exit_define_fields(struct ftrace_event_call *call)
> +static int __init syscall_exit_define_fields(struct ftrace_event_call *call)
>  {
>  	struct syscall_trace_exit trace;
>  	int ret;
> @@ -303,8 +299,9 @@ static int syscall_exit_define_fields(struct ftrace_event_call *call)
>  	return ret;
>  }
>  
> -static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
> +static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
>  {
> +	struct trace_array *tr = data;
>  	struct syscall_trace_enter *entry;
>  	struct syscall_metadata *sys_data;
>  	struct ring_buffer_event *event;
> @@ -315,7 +312,7 @@ static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
>  	syscall_nr = trace_get_syscall_nr(current, regs);
>  	if (syscall_nr < 0)
>  		return;
> -	if (!test_bit(syscall_nr, enabled_enter_syscalls))
> +	if (!test_bit(syscall_nr, tr->enabled_enter_syscalls))
>  		return;
>  
>  	sys_data = syscall_nr_to_meta(syscall_nr);
> @@ -324,7 +321,8 @@ static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
>  
>  	size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
>  
> -	event = trace_current_buffer_lock_reserve(&buffer,
> +	buffer = tr->trace_buffer.buffer;
> +	event = trace_buffer_lock_reserve(buffer,
>  			sys_data->enter_event->event.type, size, 0, 0);
>  	if (!event)
>  		return;
> @@ -338,8 +336,9 @@ static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
>  		trace_current_buffer_unlock_commit(buffer, event, 0, 0);
>  }
>  
> -static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
> +static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
>  {
> +	struct trace_array *tr = data;
>  	struct syscall_trace_exit *entry;
>  	struct syscall_metadata *sys_data;
>  	struct ring_buffer_event *event;
> @@ -349,14 +348,15 @@ static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
>  	syscall_nr = trace_get_syscall_nr(current, regs);
>  	if (syscall_nr < 0)
>  		return;
> -	if (!test_bit(syscall_nr, enabled_exit_syscalls))
> +	if (!test_bit(syscall_nr, tr->enabled_exit_syscalls))
>  		return;
>  
>  	sys_data = syscall_nr_to_meta(syscall_nr);
>  	if (!sys_data)
>  		return;
>  
> -	event = trace_current_buffer_lock_reserve(&buffer,
> +	buffer = tr->trace_buffer.buffer;
> +	event = trace_buffer_lock_reserve(buffer,
>  			sys_data->exit_event->event.type, sizeof(*entry), 0, 0);
>  	if (!event)
>  		return;
> @@ -370,8 +370,10 @@ static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
>  		trace_current_buffer_unlock_commit(buffer, event, 0, 0);
>  }
>  
> -static int reg_event_syscall_enter(struct ftrace_event_call *call)
> +static int reg_event_syscall_enter(struct ftrace_event_file *file,
> +				   struct ftrace_event_call *call)
>  {
> +	struct trace_array *tr = file->tr;
>  	int ret = 0;
>  	int num;
>  
> @@ -379,33 +381,37 @@ static int reg_event_syscall_enter(struct ftrace_event_call *call)
>  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
>  		return -ENOSYS;
>  	mutex_lock(&syscall_trace_lock);
> -	if (!sys_refcount_enter)
> -		ret = register_trace_sys_enter(ftrace_syscall_enter, NULL);
> +	if (!tr->sys_refcount_enter)
> +		ret = register_trace_sys_enter(ftrace_syscall_enter, tr);
>  	if (!ret) {
> -		set_bit(num, enabled_enter_syscalls);
> -		sys_refcount_enter++;
> +		set_bit(num, tr->enabled_enter_syscalls);
> +		tr->sys_refcount_enter++;
>  	}
>  	mutex_unlock(&syscall_trace_lock);
>  	return ret;
>  }
>  
> -static void unreg_event_syscall_enter(struct ftrace_event_call *call)
> +static void unreg_event_syscall_enter(struct ftrace_event_file *file,
> +				      struct ftrace_event_call *call)
>  {
> +	struct trace_array *tr = file->tr;
>  	int num;
>  
>  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
>  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
>  		return;
>  	mutex_lock(&syscall_trace_lock);
> -	sys_refcount_enter--;
> -	clear_bit(num, enabled_enter_syscalls);
> -	if (!sys_refcount_enter)
> -		unregister_trace_sys_enter(ftrace_syscall_enter, NULL);
> +	tr->sys_refcount_enter--;
> +	clear_bit(num, tr->enabled_enter_syscalls);
> +	if (!tr->sys_refcount_enter)
> +		unregister_trace_sys_enter(ftrace_syscall_enter, tr);
>  	mutex_unlock(&syscall_trace_lock);
>  }
>  
> -static int reg_event_syscall_exit(struct ftrace_event_call *call)
> +static int reg_event_syscall_exit(struct ftrace_event_file *file,
> +				  struct ftrace_event_call *call)
>  {
> +	struct trace_array *tr = file->tr;
>  	int ret = 0;
>  	int num;
>  
> @@ -413,28 +419,30 @@ static int reg_event_syscall_exit(struct ftrace_event_call *call)
>  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
>  		return -ENOSYS;
>  	mutex_lock(&syscall_trace_lock);
> -	if (!sys_refcount_exit)
> -		ret = register_trace_sys_exit(ftrace_syscall_exit, NULL);
> +	if (!tr->sys_refcount_exit)
> +		ret = register_trace_sys_exit(ftrace_syscall_exit, tr);
>  	if (!ret) {
> -		set_bit(num, enabled_exit_syscalls);
> -		sys_refcount_exit++;
> +		set_bit(num, tr->enabled_exit_syscalls);
> +		tr->sys_refcount_exit++;
>  	}
>  	mutex_unlock(&syscall_trace_lock);
>  	return ret;
>  }
>  
> -static void unreg_event_syscall_exit(struct ftrace_event_call *call)
> +static void unreg_event_syscall_exit(struct ftrace_event_file *file,
> +				     struct ftrace_event_call *call)
>  {
> +	struct trace_array *tr = file->tr;
>  	int num;
>  
>  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
>  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
>  		return;
>  	mutex_lock(&syscall_trace_lock);
> -	sys_refcount_exit--;
> -	clear_bit(num, enabled_exit_syscalls);
> -	if (!sys_refcount_exit)
> -		unregister_trace_sys_exit(ftrace_syscall_exit, NULL);
> +	tr->sys_refcount_exit--;
> +	clear_bit(num, tr->enabled_exit_syscalls);
> +	if (!tr->sys_refcount_exit)
> +		unregister_trace_sys_exit(ftrace_syscall_exit, tr);
>  	mutex_unlock(&syscall_trace_lock);
>  }
>  
> @@ -471,7 +479,7 @@ struct trace_event_functions exit_syscall_print_funcs = {
>  	.trace		= print_syscall_exit,
>  };
>  
> -struct ftrace_event_class event_class_syscall_enter = {
> +struct ftrace_event_class __refdata event_class_syscall_enter = {
>  	.system		= "syscalls",
>  	.reg		= syscall_enter_register,
>  	.define_fields	= syscall_enter_define_fields,
> @@ -479,7 +487,7 @@ struct ftrace_event_class event_class_syscall_enter = {
>  	.raw_init	= init_syscall_trace,
>  };
>  
> -struct ftrace_event_class event_class_syscall_exit = {
> +struct ftrace_event_class __refdata event_class_syscall_exit = {
>  	.system		= "syscalls",
>  	.reg		= syscall_exit_register,
>  	.define_fields	= syscall_exit_define_fields,
> @@ -685,11 +693,13 @@ static void perf_sysexit_disable(struct ftrace_event_call *call)
>  static int syscall_enter_register(struct ftrace_event_call *event,
>  				 enum trace_reg type, void *data)
>  {
> +	struct ftrace_event_file *file = data;
> +
>  	switch (type) {
>  	case TRACE_REG_REGISTER:
> -		return reg_event_syscall_enter(event);
> +		return reg_event_syscall_enter(file, event);
>  	case TRACE_REG_UNREGISTER:
> -		unreg_event_syscall_enter(event);
> +		unreg_event_syscall_enter(file, event);
>  		return 0;
>  
>  #ifdef CONFIG_PERF_EVENTS
> @@ -711,11 +721,13 @@ static int syscall_enter_register(struct ftrace_event_call *event,
>  static int syscall_exit_register(struct ftrace_event_call *event,
>  				 enum trace_reg type, void *data)
>  {
> +	struct ftrace_event_file *file = data;
> +
>  	switch (type) {
>  	case TRACE_REG_REGISTER:
> -		return reg_event_syscall_exit(event);
> +		return reg_event_syscall_exit(file, event);
>  	case TRACE_REG_UNREGISTER:
> -		unreg_event_syscall_exit(event);
> +		unreg_event_syscall_exit(file, event);
>  		return 0;
>  
>  #ifdef CONFIG_PERF_EVENTS
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ