Merge branches 'tracing/ftrace', 'tracing/ring-buffer' and 'tracing/urgent' into...
authorIngo Molnar <mingo@elte.hu>
Fri, 19 Dec 2008 08:42:40 +0000 (09:42 +0100)
committerIngo Molnar <mingo@elte.hu>
Fri, 19 Dec 2008 08:42:40 +0000 (09:42 +0100)
Conflicts:
include/linux/ftrace.h

1  2  3 
include/linux/ftrace.h
kernel/fork.c
kernel/sched.c
kernel/trace/trace.c

diff --combined include/linux/ftrace.h
@@@@ -6,9 -6,9 -6,8 +6,10 @@@@
   #include <linux/ktime.h>
   #include <linux/init.h>
   #include <linux/types.h>
++ #include <linux/module.h>
   #include <linux/kallsyms.h>
  +#include <linux/bitops.h>
  +#include <linux/sched.h>
   
   #ifdef CONFIG_FUNCTION_TRACER
   
@@@@ -25,45 -25,45 -24,6 +26,45 @@@@ struct ftrace_ops 
        struct ftrace_ops *next;
   };
   
  +extern int function_trace_stop;
  +
  +/*
  + * Type of the current tracing.
  + */
  +enum ftrace_tracing_type_t {
  +     FTRACE_TYPE_ENTER = 0, /* Hook the call of the function */
  +     FTRACE_TYPE_RETURN,     /* Hook the return of the function */
  +};
  +
  +/* Current tracing type, default is FTRACE_TYPE_ENTER */
  +extern enum ftrace_tracing_type_t ftrace_tracing_type;
  +
  +/**
  + * ftrace_stop - stop function tracer.
  + *
  + * A quick way to stop the function tracer. Note this an on off switch,
  + * it is not something that is recursive like preempt_disable.
  + * This does not disable the calling of mcount, it only stops the
  + * calling of functions from mcount.
  + */
  +static inline void ftrace_stop(void)
  +{
  +     function_trace_stop = 1;
  +}
  +
  +/**
  + * ftrace_start - start the function tracer.
  + *
  + * This function is the inverse of ftrace_stop. This does not enable
  + * the function tracing if the function tracer is disabled. This only
  + * sets the function tracer flag to continue calling the functions
  + * from mcount.
  + */
  +static inline void ftrace_start(void)
  +{
  +     function_trace_stop = 0;
  +}
  +
   /*
    * The ftrace_ops must be a static and should also
    * be read_mostly.  These functions do modify read_mostly variables
@@@@ -82,21 -82,13 -42,9 +83,21 @@@@ extern void ftrace_stub(unsigned long a
   # define unregister_ftrace_function(ops) do { } while (0)
   # define clear_ftrace_function(ops) do { } while (0)
   static inline void ftrace_kill(void) { }
  +static inline void ftrace_stop(void) { }
  +static inline void ftrace_start(void) { }
   #endif /* CONFIG_FUNCTION_TRACER */
   
 ++#ifdef CONFIG_STACK_TRACER
 ++extern int stack_tracer_enabled;
 ++int
 ++stack_trace_sysctl(struct ctl_table *table, int write,
 ++                struct file *file, void __user *buffer, size_t *lenp,
 ++                loff_t *ppos);
 ++#endif
 ++
   #ifdef CONFIG_DYNAMIC_FTRACE
  +/* asm/ftrace.h must be defined for archs supporting dynamic ftrace */
  +#include <asm/ftrace.h>
   
   enum {
        FTRACE_FL_FREE          = (1 << 0),
@@@@ -112,7 -104,7 -60,6 +113,7 @@@@ struct dyn_ftrace 
        struct list_head        list;
        unsigned long           ip; /* address of mcount call-site */
        unsigned long           flags;
  +     struct dyn_arch_ftrace  arch;
   };
   
   int ftrace_force_update(void);
@@@@ -120,48 -112,48 -67,19 +121,48 @@@@ void ftrace_set_filter(unsigned char *b
   
   /* defined in arch */
   extern int ftrace_ip_converted(unsigned long ip);
  -extern unsigned char *ftrace_nop_replace(void);
  -extern unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr);
   extern int ftrace_dyn_arch_init(void *data);
   extern int ftrace_update_ftrace_func(ftrace_func_t func);
   extern void ftrace_caller(void);
   extern void ftrace_call(void);
   extern void mcount_call(void);
  +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  +extern void ftrace_graph_caller(void);
  +extern int ftrace_enable_ftrace_graph_caller(void);
  +extern int ftrace_disable_ftrace_graph_caller(void);
  +#else
  +static inline int ftrace_enable_ftrace_graph_caller(void) { return 0; }
  +static inline int ftrace_disable_ftrace_graph_caller(void) { return 0; }
  +#endif
  +
  +/**
  + * ftrace_make_nop - convert code into top
  + * @mod: module structure if called by module load initialization
  + * @rec: the mcount call site record
  + * @addr: the address that the call site should be calling
  + *
  + * This is a very sensitive operation and great care needs
  + * to be taken by the arch.  The operation should carefully
  + * read the location, check to see if what is read is indeed
  + * what we expect it to be, and then on success of the compare,
  + * it should write to the location.
  + *
  + * The code segment at @rec->ip should be a caller to @addr
  + *
  + * Return must be:
  + *  0 on success
  + *  -EFAULT on error reading the location
  + *  -EINVAL on a failed compare of the contents
  + *  -EPERM  on error writing to the location
  + * Any other value will be considered a failure.
  + */
  +extern int ftrace_make_nop(struct module *mod,
  +                        struct dyn_ftrace *rec, unsigned long addr);
   
   /**
  - * ftrace_modify_code - modify code segment
  - * @ip: the address of the code segment
  - * @old_code: the contents of what is expected to be there
  - * @new_code: the code to patch in
  + * ftrace_make_call - convert a nop call site into a call to addr
  + * @rec: the mcount call site record
  + * @addr: the address that the call site should call
    *
    * This is a very sensitive operation and great care needs
    * to be taken by the arch.  The operation should carefully
    * what we expect it to be, and then on success of the compare,
    * it should write to the location.
    *
  + * The code segment at @rec->ip should be a nop
  + *
    * Return must be:
    *  0 on success
    *  -EFAULT on error reading the location
    *  -EPERM  on error writing to the location
    * Any other value will be considered a failure.
    */
  -extern int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
  -                           unsigned char *new_code);
  +extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
  +
  +
  +/* May be defined in arch */
  +extern int ftrace_arch_read_dyn_info(char *buf, int size);
   
   extern int skip_trace(unsigned long ip);
   
@@@@ -190,6 -182,6 -103,7 +191,6 @@@@ extern void ftrace_release(void *start
   
   extern void ftrace_disable_daemon(void);
   extern void ftrace_enable_daemon(void);
  -
   #else
   # define skip_trace(ip)                              ({ 0; })
   # define ftrace_force_update()                       ({ 0; })
@@@@ -268,12 -260,12 -182,6 +269,12 @@@@ static inline void __ftrace_enabled_res
   #endif
   
   #ifdef CONFIG_TRACING
  +extern int ftrace_dump_on_oops;
  +
  +extern void tracing_start(void);
  +extern void tracing_stop(void);
  +extern void ftrace_off_permanent(void);
  +
   extern void
   ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3);
   
@@@@ -304,9 -296,9 -212,6 +305,9 @@@@ ftrace_special(unsigned long arg1, unsi
   static inline int
   ftrace_printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 0)));
   
  +static inline void tracing_start(void) { }
  +static inline void tracing_stop(void) { }
  +static inline void ftrace_off_permanent(void) { }
   static inline int
   ftrace_printk(const char *fmt, ...)
   {
@@@@ -317,178 -309,178 -222,33 +318,178 @@@@ static inline void ftrace_dump(void) { 
   
   #ifdef CONFIG_FTRACE_MCOUNT_RECORD
   extern void ftrace_init(void);
  -extern void ftrace_init_module(unsigned long *start, unsigned long *end);
  +extern void ftrace_init_module(struct module *mod,
  +                            unsigned long *start, unsigned long *end);
   #else
   static inline void ftrace_init(void) { }
   static inline void
  -ftrace_init_module(unsigned long *start, unsigned long *end) { }
  +ftrace_init_module(struct module *mod,
  +                unsigned long *start, unsigned long *end) { }
  +#endif
  +
  +enum {
  +     POWER_NONE = 0,
  +     POWER_CSTATE = 1,
  +     POWER_PSTATE = 2,
  +};
  +
  +struct power_trace {
  +#ifdef CONFIG_POWER_TRACER
  +     ktime_t                 stamp;
  +     ktime_t                 end;
  +     int                     type;
  +     int                     state;
   #endif
  +};
   
  +#ifdef CONFIG_POWER_TRACER
  +extern void trace_power_start(struct power_trace *it, unsigned int type,
  +                                     unsigned int state);
  +extern void trace_power_mark(struct power_trace *it, unsigned int type,
  +                                     unsigned int state);
  +extern void trace_power_end(struct power_trace *it);
  +#else
  +static inline void trace_power_start(struct power_trace *it, unsigned int type,
  +                                     unsigned int state) { }
  +static inline void trace_power_mark(struct power_trace *it, unsigned int type,
  +                                     unsigned int state) { }
  +static inline void trace_power_end(struct power_trace *it) { }
  +#endif
  +
  +
  +/*
  + * Structure that defines an entry function trace.
  + */
  +struct ftrace_graph_ent {
  +     unsigned long func; /* Current function */
  +     int depth;
  +};
   
  -struct boot_trace {
  -     pid_t                   caller;
  -     char                    func[KSYM_SYMBOL_LEN];
  -     int                     result;
  -     unsigned long long      duration;               /* usecs */
  -     ktime_t                 calltime;
  -     ktime_t                 rettime;
  +/*
  + * Structure that defines a return function trace.
  + */
  +struct ftrace_graph_ret {
  +     unsigned long func; /* Current function */
  +     unsigned long long calltime;
  +     unsigned long long rettime;
  +     /* Number of functions that overran the depth limit for current task */
  +     unsigned long overrun;
  +     int depth;
   };
   
  -#ifdef CONFIG_BOOT_TRACER
  -extern void trace_boot(struct boot_trace *it, initcall_t fn);
  -extern void start_boot_trace(void);
  -extern void stop_boot_trace(void);
  +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  +
  +/*
  + * Sometimes we don't want to trace a function with the function
  + * graph tracer but we want them to keep traced by the usual function
  + * tracer if the function graph tracer is not configured.
  + */
  +#define __notrace_funcgraph          notrace
  +
  +/*
  + * We want to which function is an entrypoint of a hardirq.
  + * That will help us to put a signal on output.
  + */
  +#define __irq_entry           __attribute__((__section__(".irqentry.text")))
  +
  +/* Limits of hardirq entrypoints */
  +extern char __irqentry_text_start[];
  +extern char __irqentry_text_end[];
  +
  +#define FTRACE_RETFUNC_DEPTH 50
  +#define FTRACE_RETSTACK_ALLOC_SIZE 32
  +/* Type of the callback handlers for tracing function graph*/
  +typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); /* return */
  +typedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *); /* entry */
  +
  +extern int register_ftrace_graph(trace_func_graph_ret_t retfunc,
  +                             trace_func_graph_ent_t entryfunc);
  +
  +extern void ftrace_graph_stop(void);
  +
  +/* The current handlers in use */
  +extern trace_func_graph_ret_t ftrace_graph_return;
  +extern trace_func_graph_ent_t ftrace_graph_entry;
  +
  +extern void unregister_ftrace_graph(void);
  +
  +extern void ftrace_graph_init_task(struct task_struct *t);
  +extern void ftrace_graph_exit_task(struct task_struct *t);
  +
  +static inline int task_curr_ret_stack(struct task_struct *t)
  +{
  +     return t->curr_ret_stack;
  +}
  +
  +static inline void pause_graph_tracing(void)
  +{
  +     atomic_inc(&current->tracing_graph_pause);
  +}
  +
  +static inline void unpause_graph_tracing(void)
  +{
  +     atomic_dec(&current->tracing_graph_pause);
  +}
   #else
  -static inline void trace_boot(struct boot_trace *it, initcall_t fn) { }
  -static inline void start_boot_trace(void) { }
  -static inline void stop_boot_trace(void) { }
  +
  +#define __notrace_funcgraph
  +#define __irq_entry
  +
  +static inline void ftrace_graph_init_task(struct task_struct *t) { }
  +static inline void ftrace_graph_exit_task(struct task_struct *t) { }
  +
  +static inline int task_curr_ret_stack(struct task_struct *tsk)
  +{
  +     return -1;
  +}
  +
  +static inline void pause_graph_tracing(void) { }
  +static inline void unpause_graph_tracing(void) { }
   #endif
   
  +#ifdef CONFIG_TRACING
  +#include <linux/sched.h>
  +
  +/* flags for current->trace */
  +enum {
  +     TSK_TRACE_FL_TRACE_BIT  = 0,
  +     TSK_TRACE_FL_GRAPH_BIT  = 1,
  +};
  +enum {
  +     TSK_TRACE_FL_TRACE      = 1 << TSK_TRACE_FL_TRACE_BIT,
  +     TSK_TRACE_FL_GRAPH      = 1 << TSK_TRACE_FL_GRAPH_BIT,
  +};
  +
  +static inline void set_tsk_trace_trace(struct task_struct *tsk)
  +{
  +     set_bit(TSK_TRACE_FL_TRACE_BIT, &tsk->trace);
  +}
  +
  +static inline void clear_tsk_trace_trace(struct task_struct *tsk)
  +{
  +     clear_bit(TSK_TRACE_FL_TRACE_BIT, &tsk->trace);
  +}
  +
  +static inline int test_tsk_trace_trace(struct task_struct *tsk)
  +{
  +     return tsk->trace & TSK_TRACE_FL_TRACE;
  +}
  +
  +static inline void set_tsk_trace_graph(struct task_struct *tsk)
  +{
  +     set_bit(TSK_TRACE_FL_GRAPH_BIT, &tsk->trace);
  +}
  +
  +static inline void clear_tsk_trace_graph(struct task_struct *tsk)
  +{
  +     clear_bit(TSK_TRACE_FL_GRAPH_BIT, &tsk->trace);
  +}
  +
  +static inline int test_tsk_trace_graph(struct task_struct *tsk)
  +{
  +     return tsk->trace & TSK_TRACE_FL_GRAPH;
  +}
   
  +#endif /* CONFIG_TRACING */
   
   #endif /* _LINUX_FTRACE_H */
diff --combined kernel/fork.c
   #include <linux/mount.h>
   #include <linux/audit.h>
   #include <linux/memcontrol.h>
  +#include <linux/ftrace.h>
   #include <linux/profile.h>
   #include <linux/rmap.h>
   #include <linux/acct.h>
@@@@ -81,8 -81,8 -80,6 +81,8 @@@@ DEFINE_PER_CPU(unsigned long, process_c
   
   __cacheline_aligned DEFINE_RWLOCK(tasklist_lock);  /* outer */
   
  +DEFINE_TRACE(sched_process_fork);
  +
   int nr_processes(void)
   {
        int cpu;
@@@@ -140,7 -140,7 -137,6 +140,7 @@@@ void free_task(struct task_struct *tsk
        prop_local_destroy_single(&tsk->dirties);
        free_thread_info(tsk->stack);
        rt_mutex_debug_task_free(tsk);
  +     ftrace_graph_exit_task(tsk);
        free_task_struct(tsk);
   }
   EXPORT_SYMBOL(free_task);
@@@@ -319,17 -319,17 -315,20 +319,20 @@@@ static int dup_mmap(struct mm_struct *m
                file = tmp->vm_file;
                if (file) {
                        struct inode *inode = file->f_path.dentry->d_inode;
++                      struct address_space *mapping = file->f_mapping;
++ 
                        get_file(file);
                        if (tmp->vm_flags & VM_DENYWRITE)
                                atomic_dec(&inode->i_writecount);
-- 
--                      /* insert tmp into the share list, just after mpnt */
--                      spin_lock(&file->f_mapping->i_mmap_lock);
++                      spin_lock(&mapping->i_mmap_lock);
++                      if (tmp->vm_flags & VM_SHARED)
++                              mapping->i_mmap_writable++;
                        tmp->vm_truncate_count = mpnt->vm_truncate_count;
--                      flush_dcache_mmap_lock(file->f_mapping);
++                      flush_dcache_mmap_lock(mapping);
++                      /* insert tmp into the share list, just after mpnt */
                        vma_prio_tree_add(tmp, mpnt);
--                      flush_dcache_mmap_unlock(file->f_mapping);
--                      spin_unlock(&file->f_mapping->i_mmap_lock);
++                      flush_dcache_mmap_unlock(mapping);
++                      spin_unlock(&mapping->i_mmap_lock);
                }
   
                /*
@@@@ -1137,8 -1137,8 -1136,6 +1140,8 @@@@ static struct task_struct *copy_process
                }
        }
   
  +     ftrace_graph_init_task(p);
  +
        p->pid = pid_nr(pid);
        p->tgid = p->pid;
        if (clone_flags & CLONE_THREAD)
        if (current->nsproxy != p->nsproxy) {
                retval = ns_cgroup_clone(p, pid);
                if (retval)
  -                     goto bad_fork_free_pid;
  +                     goto bad_fork_free_graph;
        }
   
        p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
                spin_unlock(&current->sighand->siglock);
                write_unlock_irq(&tasklist_lock);
                retval = -ERESTARTNOINTR;
  -             goto bad_fork_free_pid;
  +             goto bad_fork_free_graph;
        }
   
        if (clone_flags & CLONE_THREAD) {
        cgroup_post_fork(p);
        return p;
   
  +bad_fork_free_graph:
  +     ftrace_graph_exit_task(p);
   bad_fork_free_pid:
        if (pid != &init_struct_pid)
                free_pid(pid);
@@@@ -1406,6 -1406,6 -1401,7 +1409,7 @@@@ long do_fork(unsigned long clone_flags
                        init_completion(&vfork);
                }
   
++              audit_finish_fork(p);
                tracehook_report_clone(trace, regs, clone_flags, nr, p);
   
                /*
diff --combined kernel/sched.c
    */
   #define RUNTIME_INF  ((u64)~0ULL)
   
  +DEFINE_TRACE(sched_wait_task);
  +DEFINE_TRACE(sched_wakeup);
  +DEFINE_TRACE(sched_wakeup_new);
  +DEFINE_TRACE(sched_switch);
  +DEFINE_TRACE(sched_migrate_task);
  +
   #ifdef CONFIG_SMP
   /*
    * Divide a load by a sched group cpu_power : (load / sg->__cpu_power)
@@@@ -1851,8 -1851,8 -1845,6 +1851,8 @@@@ void set_task_cpu(struct task_struct *p
   
        clock_offset = old_rq->clock - new_rq->clock;
   
  +     trace_sched_migrate_task(p, task_cpu(p), new_cpu);
  +
   #ifdef CONFIG_SCHEDSTATS
        if (p->se.wait_start)
                p->se.wait_start -= clock_offset;
@@@@ -2457,7 -2457,7 -2449,7 +2457,7 @@@@ void wake_up_new_task(struct task_struc
                p->sched_class->task_new(rq, p);
                inc_nr_running(rq);
        }
 --     trace_sched_wakeup_new(rq, p);
 ++     trace_sched_wakeup_new(rq, p, 1);
        check_preempt_curr(rq, p, 0);
   #ifdef CONFIG_SMP
        if (p->sched_class->task_wake_up)
@@@@ -2870,6 -2870,6 -2862,7 +2870,6 @@@@ static void sched_migrate_task(struct t
            || unlikely(!cpu_active(dest_cpu)))
                goto out;
   
  -     trace_sched_migrate_task(rq, p, dest_cpu);
        /* force the process onto the specified CPU */
        if (migrate_task(p, dest_cpu, &req)) {
                /* Need to wait for migration thread (might exit: take ref). */
@@@@ -5903,7 -5903,7 -5896,6 +5903,7 @@@@ void __cpuinit init_idle(struct task_st
         * The idle tasks have their own, simple scheduling class:
         */
        idle->sched_class = &idle_sched_class;
  +     ftrace_graph_init_task(idle);
   }
   
   /*
@@@@ -6595,7 -6595,7 -6587,9 +6595,9 @@@@ migration_call(struct notifier_block *n
                        req = list_entry(rq->migration_queue.next,
                                         struct migration_req, list);
                        list_del_init(&req->list);
++                      spin_unlock_irq(&rq->lock);
                        complete(&req->done);
++                      spin_lock_irq(&rq->lock);
                }
                spin_unlock_irq(&rq->lock);
                break;
diff --combined kernel/trace/trace.c
   #include <linux/gfp.h>
   #include <linux/fs.h>
   #include <linux/kprobes.h>
  +#include <linux/seq_file.h>
   #include <linux/writeback.h>
   
   #include <linux/stacktrace.h>
   unsigned long __read_mostly  tracing_max_latency = (cycle_t)ULONG_MAX;
   unsigned long __read_mostly  tracing_thresh;
   
  +/*
  + * We need to change this state when a selftest is running.
  + * A selftest will lurk into the ring-buffer to count the
  + * entries inserted during the selftest although some concurrent
  + * insertions into the ring-buffer such as ftrace_printk could occurred
  + * at the same time, giving false positive or negative results.
  + */
  +static bool __read_mostly tracing_selftest_running;
  +
  +/* For tracers that don't implement custom flags */
  +static struct tracer_opt dummy_tracer_opt[] = {
  +     { }
  +};
  +
  +static struct tracer_flags dummy_tracer_flags = {
  +     .val = 0,
  +     .opts = dummy_tracer_opt
  +};
  +
  +static int dummy_set_flag(u32 old_flags, u32 bit, int set)
  +{
  +     return 0;
  +}
  +
  +/*
  + * 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
  + * this back to zero.
  + */
  +int tracing_disabled = 1;
  +
   static DEFINE_PER_CPU(local_t, ftrace_cpu_disabled);
   
   static inline void ftrace_disable_cpu(void)
@@@@ -95,36 -95,36 -62,7 +95,36 @@@@ static cpumask_t __read_mostly             tracing
   #define for_each_tracing_cpu(cpu)    \
        for_each_cpu_mask(cpu, tracing_buffer_mask)
   
  -static int tracing_disabled = 1;
  +/*
  + * ftrace_dump_on_oops - variable to dump ftrace buffer on oops
  + *
  + * If there is an oops (or kernel panic) and the ftrace_dump_on_oops
  + * is set, then ftrace_dump is called. This will output the contents
  + * of the ftrace buffers to the console.  This is very useful for
  + * capturing traces that lead to crashes and outputing it to a
  + * serial console.
  + *
  + * It is default off, but you can enable it with either specifying
  + * "ftrace_dump_on_oops" in the kernel command line, or setting
  + * /proc/sys/kernel/ftrace_dump_on_oops to true.
  + */
  +int ftrace_dump_on_oops;
  +
  +static int tracing_set_tracer(char *buf);
  +
  +static int __init set_ftrace(char *str)
  +{
  +     tracing_set_tracer(str);
  +     return 1;
  +}
  +__setup("ftrace", set_ftrace);
  +
  +static int __init set_ftrace_dump_on_oops(char *str)
  +{
  +     ftrace_dump_on_oops = 1;
  +     return 1;
  +}
  +__setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
   
   long
   ns2usecs(cycle_t nsec)
@@@@ -174,19 -174,19 -112,6 +174,19 @@@@ static DEFINE_PER_CPU(struct trace_arra
   /* tracer_enabled is used to toggle activation of a tracer */
   static int                   tracer_enabled = 1;
   
  +/**
  + * tracing_is_enabled - return tracer_enabled status
  + *
  + * This function is used by other tracers to know the status
  + * of the tracer_enabled flag.  Tracers may use this function
  + * to know if it should enable their features when starting
  + * up. See irqsoff tracer for an example (start_irqsoff_tracer).
  + */
  +int tracing_is_enabled(void)
  +{
  +     return tracer_enabled;
  +}
  +
   /* function tracing enabled */
   int                          ftrace_function_enabled;
   
@@@@ -228,9 -228,9 -153,8 +228,9 @@@@ static DEFINE_MUTEX(trace_types_lock)
   /* trace_wait is a waitqueue for tasks blocked on trace_poll */
   static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
   
  -/* trace_flags holds iter_ctrl options */
  -unsigned long trace_flags = TRACE_ITER_PRINT_PARENT;
  +/* trace_flags holds trace_options default values */
  +unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
  +     TRACE_ITER_ANNOTATE;
   
   /**
    * trace_wake_up - wake up tasks waiting for trace input
@@@@ -269,6 -269,6 -193,13 +269,6 @@@@ unsigned long nsecs_to_usecs(unsigned l
        return nsecs / 1000;
   }
   
  -/*
  - * TRACE_ITER_SYM_MASK masks the options in trace_flags that
  - * control the output of kernel symbols.
  - */
  -#define TRACE_ITER_SYM_MASK \
  -     (TRACE_ITER_PRINT_PARENT|TRACE_ITER_SYM_OFFSET|TRACE_ITER_SYM_ADDR)
  -
   /* These must match the bit postions in trace_iterator_flags */
   static const char *trace_options[] = {
        "print-parent",
        "stacktrace",
        "sched-tree",
        "ftrace_printk",
  +     "ftrace_preempt",
  +     "branch",
  +     "annotate",
  +     "userstacktrace",
  +     "sym-userobj",
  +     "printk-msg-only",
        NULL
   };
   
@@@@ -434,28 -434,28 -359,6 +434,28 @@@@ trace_seq_putmem_hex(struct trace_seq *
        return trace_seq_putmem(s, hex, j);
   }
   
  +static int
  +trace_seq_path(struct trace_seq *s, struct path *path)
  +{
  +     unsigned char *p;
  +
  +     if (s->len >= (PAGE_SIZE - 1))
  +             return 0;
  +     p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
  +     if (!IS_ERR(p)) {
  +             p = mangle_path(s->buffer + s->len, p, "\n");
  +             if (p) {
  +                     s->len = p - s->buffer;
  +                     return 1;
  +             }
  +     } else {
  +             s->buffer[s->len++] = '?';
  +             return 1;
  +     }
  +
  +     return 0;
  +}
  +
   static void
   trace_seq_reset(struct trace_seq *s)
   {
@@@@ -567,17 -567,17 -470,7 +567,17 @@@@ int register_tracer(struct tracer *type
                return -1;
        }
   
  +     /*
  +      * When this gets called we hold the BKL which means that
  +      * preemption is disabled. Various trace selftests however
  +      * need to disable and enable preemption for successful tests.
  +      * So we drop the BKL here and grab it after the tests again.
  +      */
  +     unlock_kernel();
        mutex_lock(&trace_types_lock);
  +
  +     tracing_selftest_running = true;
  +
        for (t = trace_types; t; t = t->next) {
                if (strcmp(type->name, t->name) == 0) {
                        /* already found */
                }
        }
   
  +     if (!type->set_flag)
  +             type->set_flag = &dummy_set_flag;
  +     if (!type->flags)
  +             type->flags = &dummy_tracer_flags;
  +     else
  +             if (!type->flags->opts)
  +                     type->flags->opts = dummy_tracer_opt;
  +
   #ifdef CONFIG_FTRACE_STARTUP_TEST
        if (type->selftest) {
                struct tracer *saved_tracer = current_trace;
                struct trace_array *tr = &global_trace;
  -             int saved_ctrl = tr->ctrl;
                int i;
  +
                /*
                 * Run a selftest on this tracer.
                 * Here we reset the trace buffer, and set the current
                 * internal tracing to verify that everything is in order.
                 * If we fail, we do not register this tracer.
                 */
  -             for_each_tracing_cpu(i) {
  +             for_each_tracing_cpu(i)
                        tracing_reset(tr, i);
  -             }
  +
                current_trace = type;
  -             tr->ctrl = 0;
                /* 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;
  -             tr->ctrl = saved_ctrl;
                if (ret) {
                        printk(KERN_CONT "FAILED!\n");
                        goto out;
                }
                /* Only reset on passing, to avoid touching corrupted buffers */
  -             for_each_tracing_cpu(i) {
  +             for_each_tracing_cpu(i)
                        tracing_reset(tr, i);
  -             }
  +
                printk(KERN_CONT "PASSED\n");
        }
   #endif
                max_tracer_type_len = len;
   
    out:
  +     tracing_selftest_running = false;
        mutex_unlock(&trace_types_lock);
  +     lock_kernel();
   
        return ret;
   }
@@@@ -696,91 -696,91 -581,6 +696,91 @@@@ static void trace_init_cmdlines(void
        cmdline_idx = 0;
   }
   
  +static int trace_stop_count;
  +static DEFINE_SPINLOCK(tracing_start_lock);
  +
  +/**
  + * ftrace_off_permanent - disable all ftrace code permanently
  + *
  + * This should only be called when a serious anomally has
  + * been detected.  This will turn off the function tracing,
  + * ring buffers, and other tracing utilites. It takes no
  + * locks and can be called from any context.
  + */
  +void ftrace_off_permanent(void)
  +{
  +     tracing_disabled = 1;
  +     ftrace_stop();
  +     tracing_off_permanent();
  +}
  +
  +/**
  + * tracing_start - quick start of the tracer
  + *
  + * If tracing is enabled but was stopped by tracing_stop,
  + * this will start the tracer back up.
  + */
  +void tracing_start(void)
  +{
  +     struct ring_buffer *buffer;
  +     unsigned long flags;
  +
  +     if (tracing_disabled)
  +             return;
  +
  +     spin_lock_irqsave(&tracing_start_lock, flags);
  +     if (--trace_stop_count)
  +             goto out;
  +
  +     if (trace_stop_count < 0) {
  +             /* Someone screwed up their debugging */
  +             WARN_ON_ONCE(1);
  +             trace_stop_count = 0;
  +             goto out;
  +     }
  +
  +
  +     buffer = global_trace.buffer;
  +     if (buffer)
  +             ring_buffer_record_enable(buffer);
  +
  +     buffer = max_tr.buffer;
  +     if (buffer)
  +             ring_buffer_record_enable(buffer);
  +
  +     ftrace_start();
  + out:
  +     spin_unlock_irqrestore(&tracing_start_lock, flags);
  +}
  +
  +/**
  + * tracing_stop - quick stop of the tracer
  + *
  + * Light weight way to stop tracing. Use in conjunction with
  + * tracing_start.
  + */
  +void tracing_stop(void)
  +{
  +     struct ring_buffer *buffer;
  +     unsigned long flags;
  +
  +     ftrace_stop();
  +     spin_lock_irqsave(&tracing_start_lock, flags);
  +     if (trace_stop_count++)
  +             goto out;
  +
  +     buffer = global_trace.buffer;
  +     if (buffer)
  +             ring_buffer_record_disable(buffer);
  +
  +     buffer = max_tr.buffer;
  +     if (buffer)
  +             ring_buffer_record_disable(buffer);
  +
  + out:
  +     spin_unlock_irqrestore(&tracing_start_lock, flags);
  +}
  +
   void trace_stop_cmdline_recording(void);
   
   static void trace_save_cmdline(struct task_struct *tsk)
        spin_unlock(&trace_cmdline_lock);
   }
   
  -static char *trace_find_cmdline(int pid)
  +char *trace_find_cmdline(int pid)
   {
        char *cmdline = "<...>";
        unsigned map;
@@@@ -855,7 -855,7 -655,6 +855,7 @@@@ tracing_generic_entry_update(struct tra
   
        entry->preempt_count            = pc & 0xff;
        entry->pid                      = (tsk) ? tsk->pid : 0;
  +     entry->tgid                     = (tsk) ? tsk->tgid : 0;
        entry->flags =
   #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
                (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
@@@@ -892,56 -892,56 -691,6 +892,56 @@@@ trace_function(struct trace_array *tr, 
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
   }
   
  +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  +static void __trace_graph_entry(struct trace_array *tr,
  +                             struct trace_array_cpu *data,
  +                             struct ftrace_graph_ent *trace,
  +                             unsigned long flags,
  +                             int pc)
  +{
  +     struct ring_buffer_event *event;
  +     struct ftrace_graph_ent_entry *entry;
  +     unsigned long irq_flags;
  +
  +     if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
  +             return;
  +
  +     event = ring_buffer_lock_reserve(global_trace.buffer, sizeof(*entry),
  +                                      &irq_flags);
  +     if (!event)
  +             return;
  +     entry   = ring_buffer_event_data(event);
  +     tracing_generic_entry_update(&entry->ent, flags, pc);
  +     entry->ent.type                 = TRACE_GRAPH_ENT;
  +     entry->graph_ent                        = *trace;
  +     ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
  +}
  +
  +static void __trace_graph_return(struct trace_array *tr,
  +                             struct trace_array_cpu *data,
  +                             struct ftrace_graph_ret *trace,
  +                             unsigned long flags,
  +                             int pc)
  +{
  +     struct ring_buffer_event *event;
  +     struct ftrace_graph_ret_entry *entry;
  +     unsigned long irq_flags;
  +
  +     if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
  +             return;
  +
  +     event = ring_buffer_lock_reserve(global_trace.buffer, sizeof(*entry),
  +                                      &irq_flags);
  +     if (!event)
  +             return;
  +     entry   = ring_buffer_event_data(event);
  +     tracing_generic_entry_update(&entry->ent, flags, pc);
  +     entry->ent.type                 = TRACE_GRAPH_RET;
  +     entry->ret                              = *trace;
  +     ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
  +}
  +#endif
  +
   void
   ftrace(struct trace_array *tr, struct trace_array_cpu *data,
          unsigned long ip, unsigned long parent_ip, unsigned long flags,
@@@@ -993,46 -993,46 -742,6 +993,46 @@@@ void __trace_stack(struct trace_array *
        ftrace_trace_stack(tr, data, flags, skip, preempt_count());
   }
   
  +static void ftrace_trace_userstack(struct trace_array *tr,
  +                struct trace_array_cpu *data,
  +                unsigned long flags, int pc)
  +{
  +#ifdef CONFIG_STACKTRACE
  +     struct ring_buffer_event *event;
  +     struct userstack_entry *entry;
  +     struct stack_trace trace;
  +     unsigned long irq_flags;
  +
  +     if (!(trace_flags & TRACE_ITER_USERSTACKTRACE))
  +             return;
  +
  +     event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
  +                                      &irq_flags);
  +     if (!event)
  +             return;
  +     entry   = ring_buffer_event_data(event);
  +     tracing_generic_entry_update(&entry->ent, flags, pc);
  +     entry->ent.type         = TRACE_USER_STACK;
  +
  +     memset(&entry->caller, 0, sizeof(entry->caller));
  +
  +     trace.nr_entries        = 0;
  +     trace.max_entries       = FTRACE_STACK_ENTRIES;
  +     trace.skip              = 0;
  +     trace.entries           = entry->caller;
  +
  +     save_stack_trace_user(&trace);
  +     ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
  +#endif
  +}
  +
  +void __trace_userstack(struct trace_array *tr,
  +                struct trace_array_cpu *data,
  +                unsigned long flags)
  +{
  +     ftrace_trace_userstack(tr, data, flags, preempt_count());
  +}
  +
   static void
   ftrace_trace_special(void *__tr, void *__data,
                     unsigned long arg1, unsigned long arg2, unsigned long arg3,
        entry->arg3                     = arg3;
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
        ftrace_trace_stack(tr, data, irq_flags, 4, pc);
  +     ftrace_trace_userstack(tr, data, irq_flags, pc);
   
        trace_wake_up();
   }
@@@@ -1095,7 -1095,7 -803,6 +1095,7 @@@@ tracing_sched_switch_trace(struct trace
        entry->next_cpu = task_cpu(next);
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
        ftrace_trace_stack(tr, data, flags, 5, pc);
  +     ftrace_trace_userstack(tr, data, flags, pc);
   }
   
   void
@@@@ -1125,7 -1125,7 -832,6 +1125,7 @@@@ tracing_sched_wakeup_trace(struct trace
        entry->next_cpu                 = task_cpu(wakee);
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
        ftrace_trace_stack(tr, data, flags, 6, pc);
  +     ftrace_trace_userstack(tr, data, flags, pc);
   
        trace_wake_up();
   }
@@@@ -1135,28 -1135,28 -841,26 +1135,28 @@@@ ftrace_special(unsigned long arg1, unsi
   {
        struct trace_array *tr = &global_trace;
        struct trace_array_cpu *data;
  +     unsigned long flags;
        int cpu;
        int pc;
   
  -     if (tracing_disabled || !tr->ctrl)
  +     if (tracing_disabled)
                return;
   
        pc = preempt_count();
  -     preempt_disable_notrace();
  +     local_irq_save(flags);
        cpu = raw_smp_processor_id();
        data = tr->data[cpu];
   
  -     if (likely(!atomic_read(&data->disabled)))
  +     if (likely(atomic_inc_return(&data->disabled) == 1))
                ftrace_trace_special(tr, data, arg1, arg2, arg3, pc);
   
  -     preempt_enable_notrace();
  +     atomic_dec(&data->disabled);
  +     local_irq_restore(flags);
   }
   
   #ifdef CONFIG_FUNCTION_TRACER
   static void
  -function_trace_call(unsigned long ip, unsigned long parent_ip)
  +function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip)
   {
        struct trace_array *tr = &global_trace;
        struct trace_array_cpu *data;
                return;
   
        pc = preempt_count();
  -     resched = need_resched();
  -     preempt_disable_notrace();
  +     resched = ftrace_preempt_disable();
        local_save_flags(flags);
        cpu = raw_smp_processor_id();
        data = tr->data[cpu];
                trace_function(tr, data, ip, parent_ip, flags, pc);
   
        atomic_dec(&data->disabled);
  -     if (resched)
  -             preempt_enable_no_resched_notrace();
  -     else
  -             preempt_enable_notrace();
  +     ftrace_preempt_enable(resched);
  +}
  +
  +static void
  +function_trace_call(unsigned long ip, unsigned long parent_ip)
  +{
  +     struct trace_array *tr = &global_trace;
  +     struct trace_array_cpu *data;
  +     unsigned long flags;
  +     long disabled;
  +     int cpu;
  +     int pc;
  +
  +     if (unlikely(!ftrace_function_enabled))
  +             return;
  +
  +     /*
  +      * Need to use raw, since this must be called before the
  +      * recursive protection is performed.
  +      */
  +     local_irq_save(flags);
  +     cpu = raw_smp_processor_id();
  +     data = tr->data[cpu];
  +     disabled = atomic_inc_return(&data->disabled);
  +
  +     if (likely(disabled == 1)) {
  +             pc = preempt_count();
  +             trace_function(tr, data, ip, parent_ip, flags, pc);
  +     }
  +
  +     atomic_dec(&data->disabled);
  +     local_irq_restore(flags);
  +}
  +
  +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  +int trace_graph_entry(struct ftrace_graph_ent *trace)
  +{
  +     struct trace_array *tr = &global_trace;
  +     struct trace_array_cpu *data;
  +     unsigned long flags;
  +     long disabled;
  +     int cpu;
  +     int pc;
  +
  +     if (!ftrace_trace_task(current))
  +             return 0;
  +
  +     if (!ftrace_graph_addr(trace->func))
  +             return 0;
  +
  +     local_irq_save(flags);
  +     cpu = raw_smp_processor_id();
  +     data = tr->data[cpu];
  +     disabled = atomic_inc_return(&data->disabled);
  +     if (likely(disabled == 1)) {
  +             pc = preempt_count();
  +             __trace_graph_entry(tr, data, trace, flags, pc);
  +     }
  +     /* Only do the atomic if it is not already set */
  +     if (!test_tsk_trace_graph(current))
  +             set_tsk_trace_graph(current);
  +     atomic_dec(&data->disabled);
  +     local_irq_restore(flags);
  +
  +     return 1;
  +}
  +
  +void trace_graph_return(struct ftrace_graph_ret *trace)
  +{
  +     struct trace_array *tr = &global_trace;
  +     struct trace_array_cpu *data;
  +     unsigned long flags;
  +     long disabled;
  +     int cpu;
  +     int pc;
  +
  +     local_irq_save(flags);
  +     cpu = raw_smp_processor_id();
  +     data = tr->data[cpu];
  +     disabled = atomic_inc_return(&data->disabled);
  +     if (likely(disabled == 1)) {
  +             pc = preempt_count();
  +             __trace_graph_return(tr, data, trace, flags, pc);
  +     }
  +     if (!trace->depth)
  +             clear_tsk_trace_graph(current);
  +     atomic_dec(&data->disabled);
  +     local_irq_restore(flags);
   }
  +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
   
   static struct ftrace_ops trace_ops __read_mostly =
   {
   void tracing_start_function_trace(void)
   {
        ftrace_function_enabled = 0;
  +
  +     if (trace_flags & TRACE_ITER_PREEMPTONLY)
  +             trace_ops.func = function_trace_call_preempt_only;
  +     else
  +             trace_ops.func = function_trace_call;
  +
        register_ftrace_function(&trace_ops);
  -     if (tracer_enabled)
  -             ftrace_function_enabled = 1;
  +     ftrace_function_enabled = 1;
   }
   
   void tracing_stop_function_trace(void)
   
   enum trace_file_type {
        TRACE_FILE_LAT_FMT      = 1,
  +     TRACE_FILE_ANNOTATE     = 2,
   };
   
   static void trace_iterator_increment(struct trace_iterator *iter, int cpu)
@@@@ -1433,6 -1433,6 -1047,10 +1433,6 @@@@ static void *s_start(struct seq_file *m
   
        atomic_inc(&trace_record_cmdline_disabled);
   
  -     /* let the tracer grab locks here if needed */
  -     if (current_trace->start)
  -             current_trace->start(iter);
  -
        if (*pos != iter->pos) {
                iter->ent = NULL;
                iter->cpu = 0;
   
   static void s_stop(struct seq_file *m, void *p)
   {
  -     struct trace_iterator *iter = m->private;
  -
        atomic_dec(&trace_record_cmdline_disabled);
  -
  -     /* let the tracer release locks here if needed */
  -     if (current_trace && current_trace == iter->trace && iter->trace->stop)
  -             iter->trace->stop(iter);
  -
        mutex_unlock(&trace_types_lock);
   }
   
@@@@ -1518,7 -1518,7 -1143,7 +1518,7 @@@@ seq_print_sym_offset(struct trace_seq *
   # define IP_FMT "%016lx"
   #endif
   
  -static int
  +int
   seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
   {
        int ret;
        return ret;
   }
   
  +static inline int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
  +                                 unsigned long ip, unsigned long sym_flags)
  +{
  +     struct file *file = NULL;
  +     unsigned long vmstart = 0;
  +     int ret = 1;
  +
  +     if (mm) {
  +             const struct vm_area_struct *vma;
  +
  +             down_read(&mm->mmap_sem);
  +             vma = find_vma(mm, ip);
  +             if (vma) {
  +                     file = vma->vm_file;
  +                     vmstart = vma->vm_start;
  +             }
  +             if (file) {
  +                     ret = trace_seq_path(s, &file->f_path);
  +                     if (ret)
  +                             ret = trace_seq_printf(s, "[+0x%lx]", ip - vmstart);
  +             }
  +             up_read(&mm->mmap_sem);
  +     }
  +     if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
  +             ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
  +     return ret;
  +}
  +
  +static int
  +seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
  +                   unsigned long sym_flags)
  +{
  +     struct mm_struct *mm = NULL;
  +     int ret = 1;
  +     unsigned int i;
  +
  +     if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
  +             struct task_struct *task;
  +             /*
  +              * we do the lookup on the thread group leader,
  +              * since individual threads might have already quit!
  +              */
  +             rcu_read_lock();
  +             task = find_task_by_vpid(entry->ent.tgid);
  +             if (task)
  +                     mm = get_task_mm(task);
  +             rcu_read_unlock();
  +     }
  +
  +     for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
  +             unsigned long ip = entry->caller[i];
  +
  +             if (ip == ULONG_MAX || !ret)
  +                     break;
  +             if (i && ret)
  +                     ret = trace_seq_puts(s, " <- ");
  +             if (!ip) {
  +                     if (ret)
  +                             ret = trace_seq_puts(s, "??");
  +                     continue;
  +             }
  +             if (!ret)
  +                     break;
  +             if (ret)
  +                     ret = seq_print_user_ip(s, mm, ip, sym_flags);
  +     }
  +
  +     if (mm)
  +             mmput(mm);
  +     return ret;
  +}
  +
   static void print_lat_help_header(struct seq_file *m)
   {
        seq_puts(m, "#                  _------=> CPU#            \n");
@@@@ -1748,6 -1748,6 -1301,13 +1748,13 @@@@ lat_print_timestamp(struct trace_seq *s
   
   static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
   
++ static int task_state_char(unsigned long state)
++ {
++      int bit = state ? __ffs(state) + 1 : 0;
++ 
++      return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
++ }
++ 
   /*
    * The message is supposed to contain an ending newline.
    * If the printing stops prematurely, try to add a newline of our own.
@@@@ -1785,23 -1785,23 -1345,6 +1792,23 @@@@ void trace_seq_print_cont(struct trace_
                trace_seq_putc(s, '\n');
   }
   
  +static void test_cpu_buff_start(struct trace_iterator *iter)
  +{
  +     struct trace_seq *s = &iter->seq;
  +
  +     if (!(trace_flags & TRACE_ITER_ANNOTATE))
  +             return;
  +
  +     if (!(iter->iter_flags & TRACE_FILE_ANNOTATE))
  +             return;
  +
  +     if (cpu_isset(iter->cpu, iter->started))
  +             return;
  +
  +     cpu_set(iter->cpu, iter->started);
  +     trace_seq_printf(s, "##### CPU %u buffer started ####\n", iter->cpu);
  +}
  +
   static enum print_line_t
   print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
   {
        char *comm;
        int S, T;
        int i;
 --     unsigned state;
   
        if (entry->type == TRACE_CONT)
                return TRACE_TYPE_HANDLED;
   
  +     test_cpu_buff_start(iter);
  +
        next_entry = find_next_entry(iter, NULL, &next_ts);
        if (!next_entry)
                next_ts = iter->ts;
   
                trace_assign_type(field, entry);
   
--              T = field->next_state < sizeof(state_to_char) ?
--                      state_to_char[field->next_state] : 'X';
-- 
--              state = field->prev_state ?
--                      __ffs(field->prev_state) + 1 : 0;
--              S = state < sizeof(state_to_char) - 1 ? state_to_char[state] : 'X';
++              T = task_state_char(field->next_state);
++              S = task_state_char(field->prev_state);
                comm = trace_find_cmdline(field->next_pid);
                trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
                                 field->prev_pid,
                        trace_seq_print_cont(s, iter);
                break;
        }
  +     case TRACE_BRANCH: {
  +             struct trace_branch *field;
  +
  +             trace_assign_type(field, entry);
  +
  +             trace_seq_printf(s, "[%s] %s:%s:%d\n",
  +                              field->correct ? "  ok  " : " MISS ",
  +                              field->func,
  +                              field->file,
  +                              field->line);
  +             break;
  +     }
  +     case TRACE_USER_STACK: {
  +             struct userstack_entry *field;
  +
  +             trace_assign_type(field, entry);
  +
  +             seq_print_userip_objs(field, s, sym_flags);
  +             trace_seq_putc(s, '\n');
  +             break;
  +     }
        default:
                trace_seq_printf(s, "Unknown type %d\n", entry->type);
        }
@@@@ -1958,8 -1959,8 -1475,6 +1961,8 @@@@ static enum print_line_t print_trace_fm
        if (entry->type == TRACE_CONT)
                return TRACE_TYPE_HANDLED;
   
  +     test_cpu_buff_start(iter);
  +
        comm = trace_find_cmdline(iter->ent->pid);
   
        t = ns2usecs(iter->ts);
   
                trace_assign_type(field, entry);
   
--              S = field->prev_state < sizeof(state_to_char) ?
--                      state_to_char[field->prev_state] : 'X';
--              T = field->next_state < sizeof(state_to_char) ?
--                      state_to_char[field->next_state] : 'X';
++              T = task_state_char(field->next_state);
++              S = task_state_char(field->prev_state);
                ret = trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c\n",
                                       field->prev_pid,
                                       field->prev_prio,
                        trace_seq_print_cont(s, iter);
                break;
        }
  +     case TRACE_GRAPH_RET: {
  +             return print_graph_function(iter);
  +     }
  +     case TRACE_GRAPH_ENT: {
  +             return print_graph_function(iter);
  +     }
  +     case TRACE_BRANCH: {
  +             struct trace_branch *field;
  +
  +             trace_assign_type(field, entry);
  +
  +             trace_seq_printf(s, "[%s] %s:%s:%d\n",
  +                              field->correct ? "  ok  " : " MISS ",
  +                              field->func,
  +                              field->file,
  +                              field->line);
  +             break;
  +     }
  +     case TRACE_USER_STACK: {
  +             struct userstack_entry *field;
  +
  +             trace_assign_type(field, entry);
  +
  +             ret = seq_print_userip_objs(field, s, sym_flags);
  +             if (!ret)
  +                     return TRACE_TYPE_PARTIAL_LINE;
  +             ret = trace_seq_putc(s, '\n');
  +             if (!ret)
  +                     return TRACE_TYPE_PARTIAL_LINE;
  +             break;
  +     }
        }
        return TRACE_TYPE_HANDLED;
   }
@@@@ -2140,12 -2141,12 -1622,9 +2141,9 @@@@ static enum print_line_t print_raw_fmt(
   
                trace_assign_type(field, entry);
   
--              S = field->prev_state < sizeof(state_to_char) ?
--                      state_to_char[field->prev_state] : 'X';
--              T = field->next_state < sizeof(state_to_char) ?
--                      state_to_char[field->next_state] : 'X';
--              if (entry->type == TRACE_WAKE)
--                      S = '+';
++              T = task_state_char(field->next_state);
++              S = entry->type == TRACE_WAKE ? '+' :
++                      task_state_char(field->prev_state);
                ret = trace_seq_printf(s, "%d %d %c %d %d %d %c\n",
                                       field->prev_pid,
                                       field->prev_prio,
                break;
        }
        case TRACE_SPECIAL:
  +     case TRACE_USER_STACK:
        case TRACE_STACK: {
                struct special_entry *field;
   
@@@@ -2232,12 -2233,12 -1710,9 +2230,9 @@@@ static enum print_line_t print_hex_fmt(
   
                trace_assign_type(field, entry);
   
--              S = field->prev_state < sizeof(state_to_char) ?
--                      state_to_char[field->prev_state] : 'X';
--              T = field->next_state < sizeof(state_to_char) ?
--                      state_to_char[field->next_state] : 'X';
--              if (entry->type == TRACE_WAKE)
--                      S = '+';
++              T = task_state_char(field->next_state);
++              S = entry->type == TRACE_WAKE ? '+' :
++                      task_state_char(field->prev_state);
                SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
                SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
                SEQ_PUT_HEX_FIELD_RET(s, S);
                break;
        }
        case TRACE_SPECIAL:
  +     case TRACE_USER_STACK:
        case TRACE_STACK: {
                struct special_entry *field;
   
        return TRACE_TYPE_HANDLED;
   }
   
  +static enum print_line_t print_printk_msg_only(struct trace_iterator *iter)
  +{
  +     struct trace_seq *s = &iter->seq;
  +     struct trace_entry *entry = iter->ent;
  +     struct print_entry *field;
  +     int ret;
  +
  +     trace_assign_type(field, entry);
  +
  +     ret = trace_seq_printf(s, field->buf);
  +     if (!ret)
  +             return TRACE_TYPE_PARTIAL_LINE;
  +
  +     if (entry->flags & TRACE_FLAG_CONT)
  +             trace_seq_print_cont(s, iter);
  +
  +     return TRACE_TYPE_HANDLED;
  +}
  +
   static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
   {
        struct trace_seq *s = &iter->seq;
                break;
        }
        case TRACE_SPECIAL:
  +     case TRACE_USER_STACK:
        case TRACE_STACK: {
                struct special_entry *field;
   
@@@@ -2364,11 -2365,11 -1818,6 +2359,11 @@@@ static enum print_line_t print_trace_li
                        return ret;
        }
   
  +     if (iter->ent->type == TRACE_PRINT &&
  +                     trace_flags & TRACE_ITER_PRINTK &&
  +                     trace_flags & TRACE_ITER_PRINTK_MSGONLY)
  +             return print_printk_msg_only(iter);
  +
        if (trace_flags & TRACE_ITER_BIN)
                return print_bin_fmt(iter);
   
@@@@ -2393,9 -2394,9 -1842,7 +2388,9 @@@@ static int s_show(struct seq_file *m, v
                        seq_printf(m, "# tracer: %s\n", iter->trace->name);
                        seq_puts(m, "#\n");
                }
  -             if (iter->iter_flags & TRACE_FILE_LAT_FMT) {
  +             if (iter->trace && iter->trace->print_header)
  +                     iter->trace->print_header(m);
  +             else if (iter->iter_flags & TRACE_FILE_LAT_FMT) {
                        /* print nothing if the buffers are empty */
                        if (trace_empty(iter))
                                return 0;
@@@@ -2447,15 -2448,15 -1894,6 +2442,15 @@@@ __tracing_open(struct inode *inode, str
        iter->trace = current_trace;
        iter->pos = -1;
   
  +     /* 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))
  +             iter->iter_flags |= TRACE_FILE_ANNOTATE;
  +
  +
        for_each_tracing_cpu(cpu) {
   
                iter->buffer_iter[cpu] =
        m->private = iter;
   
        /* stop the trace while dumping */
  -     if (iter->tr->ctrl) {
  -             tracer_enabled = 0;
  -             ftrace_function_enabled = 0;
  -     }
  -
  -     if (iter->trace && iter->trace->open)
  -                     iter->trace->open(iter);
  +     tracing_stop();
   
        mutex_unlock(&trace_types_lock);
   
@@@@ -2517,7 -2518,7 -1961,14 +2512,7 @@@@ int tracing_release(struct inode *inode
                iter->trace->close(iter);
   
        /* reenable tracing if it was previously enabled */
  -     if (iter->tr->ctrl) {
  -             tracer_enabled = 1;
  -             /*
  -              * It is safe to enable function tracing even if it
  -              * isn't used
  -              */
  -             ftrace_function_enabled = 1;
  -     }
  +     tracing_start();
        mutex_unlock(&trace_types_lock);
   
        seq_release(inode, file);
@@@@ -2695,7 -2696,7 -2146,7 +2690,7 @@@@ tracing_cpumask_write(struct file *filp
        if (err)
                goto err_unlock;
   
  -     raw_local_irq_disable();
  +     local_irq_disable();
        __raw_spin_lock(&ftrace_max_lock);
        for_each_tracing_cpu(cpu) {
                /*
                }
        }
        __raw_spin_unlock(&ftrace_max_lock);
  -     raw_local_irq_enable();
  +     local_irq_enable();
   
        tracing_cpumask = tracing_cpumask_new;
   
@@@@ -2733,16 -2734,16 -2184,13 +2728,16 @@@@ static struct file_operations tracing_c
   };
   
   static ssize_t
  -tracing_iter_ctrl_read(struct file *filp, char __user *ubuf,
  +tracing_trace_options_read(struct file *filp, char __user *ubuf,
                       size_t cnt, loff_t *ppos)
   {
  +     int i;
        char *buf;
        int r = 0;
        int len = 0;
  -     int i;
  +     u32 tracer_flags = current_trace->flags->val;
  +     struct tracer_opt *trace_opts = current_trace->flags->opts;
  +
   
        /* calulate max size */
        for (i = 0; trace_options[i]; i++) {
                len += 3; /* "no" and space */
        }
   
  +     /*
  +      * Increase the size with names of options specific
  +      * of the current tracer.
  +      */
  +     for (i = 0; trace_opts[i].name; i++) {
  +             len += strlen(trace_opts[i].name);
  +             len += 3; /* "no" and space */
  +     }
  +
        /* +2 for \n and \0 */
        buf = kmalloc(len + 2, GFP_KERNEL);
        if (!buf)
                        r += sprintf(buf + r, "no%s ", trace_options[i]);
        }
   
  +     for (i = 0; trace_opts[i].name; i++) {
  +             if (tracer_flags & trace_opts[i].bit)
  +                     r += sprintf(buf + r, "%s ",
  +                             trace_opts[i].name);
  +             else
  +                     r += sprintf(buf + r, "no%s ",
  +                             trace_opts[i].name);
  +     }
  +
        r += sprintf(buf + r, "\n");
        WARN_ON(r >= len + 2);
   
        return r;
   }
   
  +/* Try to assign a tracer specific option */
  +static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
  +{
  +     struct tracer_flags *trace_flags = trace->flags;
  +     struct tracer_opt *opts = NULL;
  +     int ret = 0, i = 0;
  +     int len;
  +
  +     for (i = 0; trace_flags->opts[i].name; i++) {
  +             opts = &trace_flags->opts[i];
  +             len = strlen(opts->name);
  +
  +             if (strncmp(cmp, opts->name, len) == 0) {
  +                     ret = trace->set_flag(trace_flags->val,
  +                             opts->bit, !neg);
  +                     break;
  +             }
  +     }
  +     /* Not found */
  +     if (!trace_flags->opts[i].name)
  +             return -EINVAL;
  +
  +     /* Refused to handle */
  +     if (ret)
  +             return ret;
  +
  +     if (neg)
  +             trace_flags->val &= ~opts->bit;
  +     else
  +             trace_flags->val |= opts->bit;
  +
  +     return 0;
  +}
  +
   static ssize_t
  -tracing_iter_ctrl_write(struct file *filp, const char __user *ubuf,
  +tracing_trace_options_write(struct file *filp, const char __user *ubuf,
                        size_t cnt, loff_t *ppos)
   {
        char buf[64];
        char *cmp = buf;
        int neg = 0;
  +     int ret;
        int i;
   
        if (cnt >= sizeof(buf))
                        break;
                }
        }
  -     /*
  -      * If no option could be set, return an error:
  -      */
  -     if (!trace_options[i])
  -             return -EINVAL;
  +
  +     /* If no option could be set, test the specific tracer options */
  +     if (!trace_options[i]) {
  +             ret = set_tracer_option(current_trace, cmp, neg);
  +             if (ret)
  +                     return ret;
  +     }
   
        filp->f_pos += cnt;
   
   
   static struct file_operations tracing_iter_fops = {
        .open           = tracing_open_generic,
  -     .read           = tracing_iter_ctrl_read,
  -     .write          = tracing_iter_ctrl_write,
  +     .read           = tracing_trace_options_read,
  +     .write          = tracing_trace_options_write,
   };
   
   static const char readme_msg[] =
        "# echo sched_switch > /debug/tracing/current_tracer\n"
        "# cat /debug/tracing/current_tracer\n"
        "sched_switch\n"
  -     "# cat /debug/tracing/iter_ctrl\n"
  +     "# cat /debug/tracing/trace_options\n"
        "noprint-parent nosym-offset nosym-addr noverbose\n"
  -     "# echo print-parent > /debug/tracing/iter_ctrl\n"
  +     "# echo print-parent > /debug/tracing/trace_options\n"
        "# echo 1 > /debug/tracing/tracing_enabled\n"
        "# cat /debug/tracing/trace > /tmp/trace.txt\n"
        "echo 0 > /debug/tracing/tracing_enabled\n"
@@@@ -2913,10 -2914,10 -2306,11 +2908,10 @@@@ static ssize_
   tracing_ctrl_read(struct file *filp, char __user *ubuf,
                  size_t cnt, loff_t *ppos)
   {
        char buf[64];
        int r;
   
  -     r = sprintf(buf, "%ld\n", tr->ctrl);
  +     r = sprintf(buf, "%u\n", tracer_enabled);
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
   }
   
@@@@ -2944,18 -2945,18 -2338,16 +2939,18 @@@@ tracing_ctrl_write(struct file *filp, c
        val = !!val;
   
        mutex_lock(&trace_types_lock);
  -     if (tr->ctrl ^ val) {
  -             if (val)
  +     if (tracer_enabled ^ val) {
  +             if (val) {
                        tracer_enabled = 1;
  -             else
  +                     if (current_trace->start)
  +                             current_trace->start(tr);
  +                     tracing_start();
  +             } else {
                        tracer_enabled = 0;
  -
  -             tr->ctrl = val;
  -
  -             if (current_trace && current_trace->ctrl_update)
  -                     current_trace->ctrl_update(tr);
  +                     tracing_stop();
  +                     if (current_trace->stop)
  +                             current_trace->stop(tr);
  +             }
        }
        mutex_unlock(&trace_types_lock);
   
@@@@ -2981,11 -2982,11 -2373,29 +2976,11 @@@@ tracing_set_trace_read(struct file *fil
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
   }
   
  -static ssize_t
  -tracing_set_trace_write(struct file *filp, const char __user *ubuf,
  -                     size_t cnt, loff_t *ppos)
  +static int tracing_set_tracer(char *buf)
   {
        struct trace_array *tr = &global_trace;
        struct tracer *t;
  -     char buf[max_tracer_type_len+1];
  -     int i;
  -     size_t ret;
  -
  -     ret = cnt;
  -
  -     if (cnt > max_tracer_type_len)
  -             cnt = max_tracer_type_len;
  -
  -     if (copy_from_user(&buf, ubuf, cnt))
  -             return -EFAULT;
  -
  -     buf[cnt] = 0;
  -
  -     /* strip ending whitespace. */
  -     for (i = cnt - 1; i > 0 && isspace(buf[i]); i--)
  -             buf[i] = 0;
  +     int ret = 0;
   
        mutex_lock(&trace_types_lock);
        for (t = trace_types; t; t = t->next) {
        if (t == current_trace)
                goto out;
   
  +     trace_branch_disable();
        if (current_trace && current_trace->reset)
                current_trace->reset(tr);
   
        current_trace = t;
  -     if (t->init)
  -             t->init(tr);
  +     if (t->init) {
  +             ret = t->init(tr);
  +             if (ret)
  +                     goto out;
  +     }
   
  +     trace_branch_enable(tr);
    out:
        mutex_unlock(&trace_types_lock);
   
  -     if (ret > 0)
  -             filp->f_pos += ret;
  +     return ret;
  +}
  +
  +static ssize_t
  +tracing_set_trace_write(struct file *filp, const char __user *ubuf,
  +                     size_t cnt, loff_t *ppos)
  +{
  +     char buf[max_tracer_type_len+1];
  +     int i;
  +     size_t ret;
  +     int err;
  +
  +     ret = cnt;
  +
  +     if (cnt > max_tracer_type_len)
  +             cnt = max_tracer_type_len;
  +
  +     if (copy_from_user(&buf, ubuf, cnt))
  +             return -EFAULT;
  +
  +     buf[cnt] = 0;
  +
  +     /* strip ending whitespace. */
  +     for (i = cnt - 1; i > 0 && isspace(buf[i]); i--)
  +             buf[i] = 0;
  +
  +     err = tracing_set_tracer(buf);
  +     if (err)
  +             return err;
  +
  +     filp->f_pos += ret;
   
        return ret;
   }
@@@@ -3111,10 -3112,10 -2487,6 +3106,10 @@@@ static int tracing_open_pipe(struct ino
                return -ENOMEM;
   
        mutex_lock(&trace_types_lock);
  +
  +     /* trace pipe does not show start of buffer */
  +     cpus_setall(iter->started);
  +
        iter->tr = &global_trace;
        iter->trace = current_trace;
        filp->private_data = iter;
@@@@ -3290,7 -3291,7 -2662,7 +3285,7 @@@@ tracing_entries_read(struct file *filp
        char buf[64];
        int r;
   
  -     r = sprintf(buf, "%lu\n", tr->entries);
  +     r = sprintf(buf, "%lu\n", tr->entries >> 10);
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
   }
   
@@@@ -3301,6 -3302,6 -2673,7 +3296,6 @@@@ tracing_entries_write(struct file *filp
        unsigned long val;
        char buf[64];
        int ret, cpu;
  -     struct trace_array *tr = filp->private_data;
   
        if (cnt >= sizeof(buf))
                return -EINVAL;
   
        mutex_lock(&trace_types_lock);
   
  -     if (tr->ctrl) {
  -             cnt = -EBUSY;
  -             pr_info("ftrace: please disable tracing"
  -                     " before modifying buffer size\n");
  -             goto out;
  -     }
  +     tracing_stop();
   
        /* disable all cpu buffers */
        for_each_tracing_cpu(cpu) {
                        atomic_inc(&max_tr.data[cpu]->disabled);
        }
   
  +     /* value is in KB */
  +     val <<= 10;
  +
        if (val != global_trace.entries) {
                ret = ring_buffer_resize(global_trace.buffer, val);
                if (ret < 0) {
                        atomic_dec(&max_tr.data[cpu]->disabled);
        }
   
  +     tracing_start();
        max_tr.entries = global_trace.entries;
        mutex_unlock(&trace_types_lock);
   
@@@@ -3383,7 -3384,7 -2757,7 +3378,7 @@@@ static int mark_printk(const char *fmt
        int ret;
        va_list args;
        va_start(args, fmt);
  -     ret = trace_vprintk(0, fmt, args);
  +     ret = trace_vprintk(0, -1, fmt, args);
        va_end(args);
        return ret;
   }
@@@@ -3394,8 -3395,8 -2768,9 +3389,8 @@@@ tracing_mark_write(struct file *filp, c
   {
        char *buf;
        char *end;
  -     struct trace_array *tr = &global_trace;
   
  -     if (!tr->ctrl || tracing_disabled)
  +     if (tracing_disabled)
                return -EINVAL;
   
        if (cnt > TRACE_BUF_SIZE)
@@@@ -3461,38 -3462,38 -2836,22 +3456,38 @@@@ static struct file_operations tracing_m
   
   #ifdef CONFIG_DYNAMIC_FTRACE
   
  +int __weak ftrace_arch_read_dyn_info(char *buf, int size)
  +{
  +     return 0;
  +}
  +
   static ssize_t
  -tracing_read_long(struct file *filp, char __user *ubuf,
  +tracing_read_dyn_info(struct file *filp, char __user *ubuf,
                  size_t cnt, loff_t *ppos)
   {
  +     static char ftrace_dyn_info_buffer[1024];
  +     static DEFINE_MUTEX(dyn_info_mutex);
        unsigned long *p = filp->private_data;
  -     char buf[64];
  +     char *buf = ftrace_dyn_info_buffer;
  +     int size = ARRAY_SIZE(ftrace_dyn_info_buffer);
        int r;
   
  -     r = sprintf(buf, "%ld\n", *p);
  +     mutex_lock(&dyn_info_mutex);
  +     r = sprintf(buf, "%ld ", *p);
   
  -     return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
  +     r += ftrace_arch_read_dyn_info(buf+r, (size-1)-r);
  +     buf[r++] = '\n';
  +
  +     r = simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
  +
  +     mutex_unlock(&dyn_info_mutex);
  +
  +     return r;
   }
   
  -static struct file_operations tracing_read_long_fops = {
  +static struct file_operations tracing_dyn_info_fops = {
        .open           = tracing_open_generic,
  -     .read           = tracing_read_long,
  +     .read           = tracing_read_dyn_info,
   };
   #endif
   
@@@@ -3533,10 -3534,10 -2892,10 +3528,10 @@@@ static __init int tracer_init_debugfs(v
        if (!entry)
                pr_warning("Could not create debugfs 'tracing_enabled' entry\n");
   
  -     entry = debugfs_create_file("iter_ctrl", 0644, d_tracer,
  +     entry = debugfs_create_file("trace_options", 0644, d_tracer,
                                    NULL, &tracing_iter_fops);
        if (!entry)
  -             pr_warning("Could not create debugfs 'iter_ctrl' entry\n");
  +             pr_warning("Could not create debugfs 'trace_options' entry\n");
   
        entry = debugfs_create_file("tracing_cpumask", 0644, d_tracer,
                                    NULL, &tracing_cpumask_fops);
                pr_warning("Could not create debugfs "
                           "'trace_pipe' entry\n");
   
  -     entry = debugfs_create_file("trace_entries", 0644, d_tracer,
  +     entry = debugfs_create_file("buffer_size_kb", 0644, d_tracer,
                                    &global_trace, &tracing_entries_fops);
        if (!entry)
                pr_warning("Could not create debugfs "
  -                        "'trace_entries' entry\n");
  +                        "'buffer_size_kb' entry\n");
   
        entry = debugfs_create_file("trace_marker", 0220, d_tracer,
                                    NULL, &tracing_mark_fops);
   #ifdef CONFIG_DYNAMIC_FTRACE
        entry = debugfs_create_file("dyn_ftrace_total_info", 0444, d_tracer,
                                    &ftrace_update_tot_cnt,
  -                                 &tracing_read_long_fops);
  +                                 &tracing_dyn_info_fops);
        if (!entry)
                pr_warning("Could not create debugfs "
                           "'dyn_ftrace_total_info' entry\n");
        return 0;
   }
   
  -int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
  +int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
   {
        static DEFINE_SPINLOCK(trace_buf_lock);
        static char trace_buf[TRACE_BUF_SIZE];
        struct ring_buffer_event *event;
        struct trace_array *tr = &global_trace;
        struct trace_array_cpu *data;
  -     struct print_entry *entry;
  -     unsigned long flags, irq_flags;
        int cpu, len = 0, size, pc;
  +     struct print_entry *entry;
  +     unsigned long irq_flags;
   
  -     if (!tr->ctrl || tracing_disabled)
  +     if (tracing_disabled || tracing_selftest_running)
                return 0;
   
        pc = preempt_count();
        if (unlikely(atomic_read(&data->disabled)))
                goto out;
   
  -     spin_lock_irqsave(&trace_buf_lock, flags);
  +     pause_graph_tracing();
  +     spin_lock_irqsave(&trace_buf_lock, irq_flags);
        len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args);
   
        len = min(len, TRACE_BUF_SIZE-1);
        if (!event)
                goto out_unlock;
        entry = ring_buffer_event_data(event);
  -     tracing_generic_entry_update(&entry->ent, flags, pc);
  +     tracing_generic_entry_update(&entry->ent, irq_flags, pc);
        entry->ent.type                 = TRACE_PRINT;
        entry->ip                       = ip;
  +     entry->depth                    = depth;
   
        memcpy(&entry->buf, trace_buf, len);
        entry->buf[len] = 0;
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
   
    out_unlock:
  -     spin_unlock_irqrestore(&trace_buf_lock, flags);
  -
  +     spin_unlock_irqrestore(&trace_buf_lock, irq_flags);
  +     unpause_graph_tracing();
    out:
        preempt_enable_notrace();
   
@@@@ -3675,7 -3676,7 -3032,7 +3670,7 @@@@ int __ftrace_printk(unsigned long ip, c
                return 0;
   
        va_start(ap, fmt);
  -     ret = trace_vprintk(ip, fmt, ap);
  +     ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
        va_end(ap);
        return ret;
   }
@@@@ -3684,8 -3685,8 -3041,7 +3679,8 @@@@ EXPORT_SYMBOL_GPL(__ftrace_printk)
   static int trace_panic_handler(struct notifier_block *this,
                               unsigned long event, void *unused)
   {
  -     ftrace_dump();
  +     if (ftrace_dump_on_oops)
  +             ftrace_dump();
        return NOTIFY_OK;
   }
   
@@@@ -3701,8 -3702,8 -3057,7 +3696,8 @@@@ static int trace_die_handler(struct not
   {
        switch (val) {
        case DIE_OOPS:
  -             ftrace_dump();
  +             if (ftrace_dump_on_oops)
  +                     ftrace_dump();
                break;
        default:
                break;
@@@@ -3743,6 -3744,6 -3098,7 +3738,6 @@@@ trace_printk_seq(struct trace_seq *s
        trace_seq_reset(s);
   }
   
  -
   void ftrace_dump(void)
   {
        static DEFINE_SPINLOCK(ftrace_dump_lock);
                atomic_inc(&global_trace.data[cpu]->disabled);
        }
   
  +     /* don't look at user memory in panic mode */
  +     trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
  +
        printk(KERN_TRACE "Dumping ftrace buffer:\n");
   
        iter.tr = &global_trace;
@@@@ -3863,6 -3864,6 -3216,7 +3858,6 @@@@ __init static int tracer_alloc_buffers(
   #endif
   
        /* All seems OK, enable tracing */
  -     global_trace.ctrl = tracer_enabled;
        tracing_disabled = 0;
   
        atomic_notifier_chain_register(&panic_notifier_list,