Merge branches 'tracing/ftrace', 'tracing/function-graph-tracer' and 'tracing/urgent...
Ingo Molnar [Fri, 5 Dec 2008 13:45:22 +0000 (14:45 +0100)]
1  2  3 
block/blk-core.c
block/elevator.c
kernel/trace/trace.c
kernel/trace/trace.h

diff --combined block/blk-core.c
   #include <linux/task_io_accounting_ops.h>
   #include <linux/blktrace_api.h>
   #include <linux/fault-inject.h>
  +#include <trace/block.h>
   
   #include "blk.h"
   
  +DEFINE_TRACE(block_plug);
  +DEFINE_TRACE(block_unplug_io);
  +DEFINE_TRACE(block_unplug_timer);
  +DEFINE_TRACE(block_getrq);
  +DEFINE_TRACE(block_sleeprq);
  +DEFINE_TRACE(block_rq_requeue);
  +DEFINE_TRACE(block_bio_backmerge);
  +DEFINE_TRACE(block_bio_frontmerge);
  +DEFINE_TRACE(block_bio_queue);
  +DEFINE_TRACE(block_rq_complete);
  +DEFINE_TRACE(block_remap);   /* Also used in drivers/md/dm.c */
  +EXPORT_TRACEPOINT_SYMBOL_GPL(block_remap);
  +
   static int __make_request(struct request_queue *q, struct bio *bio);
   
   /*
@@@@ -219,7 -219,7 -205,7 +219,7 @@@@ void blk_plug_device(struct request_que
   
        if (!queue_flag_test_and_set(QUEUE_FLAG_PLUGGED, q)) {
                mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);
  -             blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG);
  +             trace_block_plug(q);
        }
   }
   EXPORT_SYMBOL(blk_plug_device);
@@@@ -306,7 -306,7 -292,9 +306,7 @@@@ void blk_unplug_work(struct work_struc
        struct request_queue *q =
                container_of(work, struct request_queue, unplug_work);
   
  -     blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL,
  -                             q->rq.count[READ] + q->rq.count[WRITE]);
  -
  +     trace_block_unplug_io(q);
        q->unplug_fn(q);
   }
   
@@@@ -314,7 -314,7 -302,9 +314,7 @@@@ void blk_unplug_timeout(unsigned long d
   {
        struct request_queue *q = (struct request_queue *)data;
   
  -     blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_TIMER, NULL,
  -                             q->rq.count[READ] + q->rq.count[WRITE]);
  -
  +     trace_block_unplug_timer(q);
        kblockd_schedule_work(q, &q->unplug_work);
   }
   
@@@@ -324,7 -324,7 -314,9 +324,7 @@@@ void blk_unplug(struct request_queue *q
         * devices don't necessarily have an ->unplug_fn defined
         */
        if (q->unplug_fn) {
  -             blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL,
  -                                     q->rq.count[READ] + q->rq.count[WRITE]);
  -
  +             trace_block_unplug_io(q);
                q->unplug_fn(q);
        }
   }
@@@@ -600,7 -600,7 -592,7 +600,7 @@@@ blk_init_queue_node(request_fn_proc *rf
                                   1 << QUEUE_FLAG_STACKABLE);
        q->queue_lock           = lock;
   
--      blk_queue_segment_boundary(q, 0xffffffff);
++      blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
   
        blk_queue_make_request(q, __make_request);
        blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
@@@@ -830,7 -830,7 -822,7 +830,7 @@@@ rq_starved
        if (ioc_batching(q, ioc))
                ioc->nr_batch_requests--;
   
  -     blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
  +     trace_block_getrq(q, bio, rw);
   out:
        return rq;
   }
@@@@ -856,7 -856,7 -848,7 +856,7 @@@@ static struct request *get_request_wait
                prepare_to_wait_exclusive(&rl->wait[rw], &wait,
                                TASK_UNINTERRUPTIBLE);
   
  -             blk_add_trace_generic(q, bio, rw, BLK_TA_SLEEPRQ);
  +             trace_block_sleeprq(q, bio, rw);
   
                __generic_unplug_device(q);
                spin_unlock_irq(q->queue_lock);
@@@@ -936,7 -936,7 -928,7 +936,7 @@@@ void blk_requeue_request(struct request
   {
        blk_delete_timer(rq);
        blk_clear_rq_complete(rq);
  -     blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
  +     trace_block_rq_requeue(q, rq);
   
        if (blk_rq_tagged(rq))
                blk_queue_end_tag(q, rq);
@@@@ -1175,7 -1175,7 -1167,7 +1175,7 @@@@ static int __make_request(struct reques
                if (!ll_back_merge_fn(q, req, bio))
                        break;
   
  -             blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
  +             trace_block_bio_backmerge(q, bio);
   
                req->biotail->bi_next = bio;
                req->biotail = bio;
                if (!ll_front_merge_fn(q, req, bio))
                        break;
   
  -             blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
  +             trace_block_bio_frontmerge(q, bio);
   
                bio->bi_next = req->bio;
                req->bio = bio;
@@@@ -1277,7 -1277,7 -1269,7 +1277,7 @@@@ static inline void blk_partition_remap(
                bio->bi_sector += p->start_sect;
                bio->bi_bdev = bdev->bd_contains;
   
  -             blk_add_trace_remap(bdev_get_queue(bio->bi_bdev), bio,
  +             trace_block_remap(bdev_get_queue(bio->bi_bdev), bio,
                                    bdev->bd_dev, bio->bi_sector,
                                    bio->bi_sector - p->start_sect);
        }
                        goto end_io;
   
                if (old_sector != -1)
  -                     blk_add_trace_remap(q, bio, old_dev, bio->bi_sector,
  +                     trace_block_remap(q, bio, old_dev, bio->bi_sector,
                                            old_sector);
   
  -             blk_add_trace_bio(q, bio, BLK_TA_QUEUE);
  +             trace_block_bio_queue(q, bio);
   
                old_sector = bio->bi_sector;
                old_dev = bio->bi_bdev->bd_dev;
@@@@ -1645,6 -1645,6 -1637,28 +1645,28 @@@@ int blk_insert_cloned_request(struct re
   EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
   
   /**
++  * blkdev_dequeue_request - dequeue request and start timeout timer
++  * @req: request to dequeue
++  *
++  * Dequeue @req and start timeout timer on it.  This hands off the
++  * request to the driver.
++  *
++  * Block internal functions which don't want to start timer should
++  * call elv_dequeue_request().
++  */
++ void blkdev_dequeue_request(struct request *req)
++ {
++      elv_dequeue_request(req->q, req);
++ 
++      /*
++       * We are now handing the request to the hardware, add the
++       * timeout handler.
++       */
++      blk_add_timer(req);
++ }
++ EXPORT_SYMBOL(blkdev_dequeue_request);
++ 
++ /**
    * __end_that_request_first - end I/O on a request
    * @req:      the request being processed
    * @error:    %0 for success, < %0 for error
@@@@ -1664,7 -1664,7 -1678,7 +1686,7 @@@@ static int __end_that_request_first(str
        int total_bytes, bio_nbytes, next_idx = 0;
        struct bio *bio;
   
  -     blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
  +     trace_block_rq_complete(req->q, req);
   
        /*
         * for a REQ_TYPE_BLOCK_PC request, we want to carry any eventual
@@@@ -1782,7 -1782,7 -1796,7 +1804,7 @@@@ static void end_that_request_last(struc
                blk_queue_end_tag(req->q, req);
   
        if (blk_queued_rq(req))
--              blkdev_dequeue_request(req);
++              elv_dequeue_request(req->q, req);
   
        if (unlikely(laptop_mode) && blk_fs_request(req))
                laptop_io_completion();
diff --combined block/elevator.c
   #include <linux/compiler.h>
   #include <linux/delay.h>
   #include <linux/blktrace_api.h>
  +#include <trace/block.h>
   #include <linux/hash.h>
   #include <linux/uaccess.h>
   
   static DEFINE_SPINLOCK(elv_list_lock);
   static LIST_HEAD(elv_list);
   
  +DEFINE_TRACE(block_rq_abort);
  +
   /*
    * Merge hash stuff.
    */
@@@@ -55,9 -55,9 -52,6 +55,9 @@@@ static const int elv_hash_shift = 6
   #define rq_hash_key(rq)              ((rq)->sector + (rq)->nr_sectors)
   #define ELV_ON_HASH(rq)              (!hlist_unhashed(&(rq)->hash))
   
  +DEFINE_TRACE(block_rq_insert);
  +DEFINE_TRACE(block_rq_issue);
  +
   /*
    * Query io scheduler to see if the current process issuing bio may be
    * merged with rq.
@@@@ -592,7 -592,7 -586,7 +592,7 @@@@ void elv_insert(struct request_queue *q
        unsigned ordseq;
        int unplug_it = 1;
   
  -     blk_add_trace_rq(q, rq, BLK_TA_INSERT);
  +     trace_block_rq_insert(q, rq);
   
        rq->q = q;
   
@@@@ -778,7 -778,7 -772,7 +778,7 @@@@ struct request *elv_next_request(struc
                         * not be passed by new incoming requests
                         */
                        rq->cmd_flags |= REQ_STARTED;
  -                     blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
  +                     trace_block_rq_issue(q, rq);
                }
   
                if (!q->boundary_rq || q->boundary_rq == rq) {
@@@@ -850,14 -850,14 -844,7 +850,7 @@@@ void elv_dequeue_request(struct request
         */
        if (blk_account_rq(rq))
                q->in_flight++;
-- 
--      /*
--       * We are now handing the request to the hardware, add the
--       * timeout handler.
--       */
--      blk_add_timer(rq);
   }
-- EXPORT_SYMBOL(elv_dequeue_request);
   
   int elv_queue_empty(struct request_queue *q)
   {
@@@@ -927,7 -927,7 -914,7 +920,7 @@@@ void elv_abort_queue(struct request_que
        while (!list_empty(&q->queue_head)) {
                rq = list_entry_rq(q->queue_head.next);
                rq->cmd_flags |= REQ_QUIET;
  -             blk_add_trace_rq(q, rq, BLK_TA_ABORT);
  +             trace_block_rq_abort(q, rq);
                __blk_end_request(rq, -EIO, blk_rq_bytes(rq));
        }
   }
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;
   
  +/* 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)
@@@@ -86,36 -86,36 -62,7 +86,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)
@@@@ -165,19 -165,19 -112,6 +165,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;
   
@@@@ -219,9 -219,9 -153,8 +219,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
@@@@ -260,6 -260,6 -193,13 +260,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",
        NULL
   };
   
@@@@ -424,28 -424,28 -359,6 +424,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)
   {
@@@@ -557,15 -557,15 -470,7 +557,15 @@@@ 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);
  +
        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.
                 * 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
   
    out:
        mutex_unlock(&trace_types_lock);
  +     lock_kernel();
   
        return ret;
   }
@@@@ -682,91 -682,91 -581,6 +682,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;
@@@@ -841,7 -841,7 -655,6 +841,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) |
@@@@ -878,56 -878,56 -691,6 +878,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,
@@@@ -979,46 -979,46 -742,6 +979,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();
   }
@@@@ -1081,7 -1081,7 -803,6 +1081,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
@@@@ -1111,7 -1111,7 -832,6 +1111,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();
   }
@@@@ -1121,28 -1121,28 -841,26 +1121,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 =
   {
        .func = function_trace_call,
   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)
@@@@ -1419,6 -1408,6 -1047,10 +1419,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);
   }
   
@@@@ -1504,7 -1493,7 -1143,7 +1504,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");
@@@@ -1771,23 -1760,23 -1338,6 +1771,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)
   {
        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_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);
        }
@@@@ -1945,8 -1934,8 -1472,6 +1945,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_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;
   }
@@@@ -2146,7 -2135,7 -1640,6 +2146,7 @@@@ static enum print_line_t print_raw_fmt(
                break;
        }
        case TRACE_SPECIAL:
  +     case TRACE_USER_STACK:
        case TRACE_STACK: {
                struct special_entry *field;
   
@@@@ -2235,7 -2224,7 -1728,6 +2235,7 @@@@ static enum print_line_t print_hex_fmt(
                break;
        }
        case TRACE_SPECIAL:
  +     case TRACE_USER_STACK:
        case TRACE_STACK: {
                struct special_entry *field;
   
@@@@ -2290,7 -2279,7 -1782,6 +2290,7 @@@@ static enum print_line_t print_bin_fmt(
                break;
        }
        case TRACE_SPECIAL:
  +     case TRACE_USER_STACK:
        case TRACE_STACK: {
                struct special_entry *field;
   
@@@@ -2356,9 -2345,9 -1847,7 +2356,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;
@@@@ -2410,15 -2399,15 -1899,6 +2410,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);
   
@@@@ -2480,7 -2469,7 -1966,14 +2480,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);
@@@@ -2658,7 -2647,7 -2151,7 +2658,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;
   
@@@@ -2696,16 -2685,16 -2189,13 +2696,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"
@@@@ -2876,10 -2865,10 -2311,11 +2876,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);
   }
   
@@@@ -2907,18 -2896,18 -2343,16 +2907,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);
   
@@@@ -2944,11 -2933,11 -2378,29 +2944,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;
   }
@@@@ -3074,10 -3063,10 -2492,6 +3074,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;
@@@@ -3253,7 -3242,7 -2667,7 +3253,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);
   }
   
@@@@ -3264,6 -3253,6 -2678,7 +3264,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);
   
@@@@ -3346,7 -3335,7 -2762,7 +3346,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;
   }
@@@@ -3357,8 -3346,8 -2773,9 +3357,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)
@@@@ -3424,38 -3413,38 -2841,22 +3424,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
   
@@@@ -3496,10 -3485,10 -2897,10 +3496,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);
+ +     /*
+ +      * Raw Spinlock because a normal spinlock would be traced here
+ +      * and append an irrelevant couple spin_lock_irqsave/
+ +      * spin_unlock_irqrestore traced by ftrace around this
+ +      * TRACE_PRINTK trace.
+ +      */
+ +     static raw_spinlock_t trace_buf_lock =
+ +                             (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
        static char trace_buf[TRACE_BUF_SIZE];
   
        struct ring_buffer_event *event;
        unsigned long flags, irq_flags;
        int cpu, len = 0, size, pc;
   
  -     if (!tr->ctrl || tracing_disabled)
  +     if (tracing_disabled)
                return 0;
   
        pc = preempt_count();
        if (unlikely(atomic_read(&data->disabled)))
                goto out;
   
- -     spin_lock_irqsave(&trace_buf_lock, flags);
+ +     local_irq_save(flags);
+ +     __raw_spin_lock(&trace_buf_lock);
        len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args);
   
        len = min(len, TRACE_BUF_SIZE-1);
        tracing_generic_entry_update(&entry->ent, 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);
+ +     __raw_spin_unlock(&trace_buf_lock);
+ +     local_irq_restore(flags);
   
    out:
        preempt_enable_notrace();
@@@@ -3636,7 -3635,13 -3037,7 +3646,13 @@@@ int __ftrace_printk(unsigned long ip, c
                return 0;
   
        va_start(ap, fmt);
- -     ret = trace_vprintk(ip, fmt, ap);
+ +
+ +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ +     ret = trace_vprintk(ip, current->curr_ret_stack, fmt, ap);
+ +#else
+ +     ret = trace_vprintk(ip, -1, fmt, ap);
+ +#endif
+ +
        va_end(ap);
        return ret;
   }
@@@@ -3645,8 -3650,8 -3046,7 +3661,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;
   }
   
@@@@ -3662,8 -3667,8 -3062,7 +3678,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;
@@@@ -3704,6 -3709,6 -3103,7 +3720,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;
@@@@ -3824,6 -3829,6 -3221,7 +3840,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,
diff --combined kernel/trace/trace.h
@@@@ -8,7 -8,7 -8,6 +8,7 @@@@
   #include <linux/ring_buffer.h>
   #include <linux/mmiotrace.h>
   #include <linux/ftrace.h>
  +#include <trace/boot.h>
   
   enum trace_type {
        __TRACE_FIRST_TYPE = 0,
        TRACE_SPECIAL,
        TRACE_MMIO_RW,
        TRACE_MMIO_MAP,
  -     TRACE_BOOT,
  +     TRACE_BRANCH,
  +     TRACE_BOOT_CALL,
  +     TRACE_BOOT_RET,
  +     TRACE_GRAPH_RET,
  +     TRACE_GRAPH_ENT,
  +     TRACE_USER_STACK,
  +     TRACE_BTS,
  +     TRACE_POWER,
   
        __TRACE_LAST_TYPE
   };
@@@@ -46,7 -46,7 -38,6 +46,7 @@@@ struct trace_entry 
        unsigned char           flags;
        unsigned char           preempt_count;
        int                     pid;
  +     int                     tgid;
   };
   
   /*
@@@@ -57,18 -57,18 -48,6 +57,18 @@@@ struct ftrace_entry 
        unsigned long           ip;
        unsigned long           parent_ip;
   };
  +
  +/* Function call entry */
  +struct ftrace_graph_ent_entry {
  +     struct trace_entry                      ent;
  +     struct ftrace_graph_ent         graph_ent;
  +};
  +
  +/* Function return entry */
  +struct ftrace_graph_ret_entry {
  +     struct trace_entry                      ent;
  +     struct ftrace_graph_ret         ret;
  +};
   extern struct tracer boot_tracer;
   
   /*
@@@@ -106,17 -106,18 -85,12 +106,18 @@@@ struct stack_entry 
        unsigned long           caller[FTRACE_STACK_ENTRIES];
   };
   
  +struct userstack_entry {
  +     struct trace_entry      ent;
  +     unsigned long           caller[FTRACE_STACK_ENTRIES];
  +};
  +
   /*
    * ftrace_printk entry:
    */
   struct print_entry {
        struct trace_entry      ent;
        unsigned long           ip;
+ +     int                     depth;
        char                    buf[];
   };
   
@@@@ -138,35 -139,35 -112,9 +139,35 @@@@ struct trace_mmiotrace_map 
        struct mmiotrace_map    map;
   };
   
  -struct trace_boot {
  +struct trace_boot_call {
        struct trace_entry      ent;
  -     struct boot_trace       initcall;
  +     struct boot_trace_call boot_call;
  +};
  +
  +struct trace_boot_ret {
  +     struct trace_entry      ent;
  +     struct boot_trace_ret boot_ret;
  +};
  +
  +#define TRACE_FUNC_SIZE 30
  +#define TRACE_FILE_SIZE 20
  +struct trace_branch {
  +     struct trace_entry      ent;
  +     unsigned                line;
  +     char                    func[TRACE_FUNC_SIZE+1];
  +     char                    file[TRACE_FILE_SIZE+1];
  +     char                    correct;
  +};
  +
  +struct bts_entry {
  +     struct trace_entry      ent;
  +     unsigned long           from;
  +     unsigned long           to;
  +};
  +
  +struct trace_power {
  +     struct trace_entry      ent;
  +     struct power_trace      state_data;
   };
   
   /*
@@@@ -224,6 -225,6 -172,7 +225,6 @@@@ struct trace_iterator
   struct trace_array {
        struct ring_buffer      *buffer;
        unsigned long           entries;
  -     long                    ctrl;
        int                     cpu;
        cycle_t                 time_start;
        struct task_struct      *waiter;
@@@@ -263,22 -264,22 -212,13 +264,22 @@@@ extern void __ftrace_bad_type(void)
                IF_ASSIGN(var, ent, struct ctx_switch_entry, 0);        \
                IF_ASSIGN(var, ent, struct trace_field_cont, TRACE_CONT); \
                IF_ASSIGN(var, ent, struct stack_entry, TRACE_STACK);   \
  +             IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
                IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT);   \
                IF_ASSIGN(var, ent, struct special_entry, 0);           \
                IF_ASSIGN(var, ent, struct trace_mmiotrace_rw,          \
                          TRACE_MMIO_RW);                               \
                IF_ASSIGN(var, ent, struct trace_mmiotrace_map,         \
                          TRACE_MMIO_MAP);                              \
  -             IF_ASSIGN(var, ent, struct trace_boot, TRACE_BOOT);     \
  +             IF_ASSIGN(var, ent, struct trace_boot_call, TRACE_BOOT_CALL);\
  +             IF_ASSIGN(var, ent, struct trace_boot_ret, TRACE_BOOT_RET);\
  +             IF_ASSIGN(var, ent, struct trace_branch, TRACE_BRANCH); \
  +             IF_ASSIGN(var, ent, struct ftrace_graph_ent_entry,      \
  +                       TRACE_GRAPH_ENT);             \
  +             IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry,      \
  +                       TRACE_GRAPH_RET);             \
  +             IF_ASSIGN(var, ent, struct bts_entry, TRACE_BTS);\
  +             IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \
                __ftrace_bad_type();                                    \
        } while (0)
   
@@@@ -289,56 -290,56 -229,29 +290,56 @@@@ enum print_line_t 
        TRACE_TYPE_UNHANDLED    = 2     /* Relay to other output functions */
   };
   
  +
  +/*
  + * An option specific to a tracer. This is a boolean value.
  + * The bit is the bit index that sets its value on the
  + * flags value in struct tracer_flags.
  + */
  +struct tracer_opt {
  +     const char      *name; /* Will appear on the trace_options file */
  +     u32             bit; /* Mask assigned in val field in tracer_flags */
  +};
  +
  +/*
  + * The set of specific options for a tracer. Your tracer
  + * have to set the initial value of the flags val.
  + */
  +struct tracer_flags {
  +     u32                     val;
  +     struct tracer_opt       *opts;
  +};
  +
  +/* Makes more easy to define a tracer opt */
  +#define TRACER_OPT(s, b)     .name = #s, .bit = b
  +
   /*
    * A specific tracer, represented by methods that operate on a trace array:
    */
   struct tracer {
        const char              *name;
  -     void                    (*init)(struct trace_array *tr);
  +     /* Your tracer should raise a warning if init fails */
  +     int                     (*init)(struct trace_array *tr);
        void                    (*reset)(struct trace_array *tr);
  +     void                    (*start)(struct trace_array *tr);
  +     void                    (*stop)(struct trace_array *tr);
        void                    (*open)(struct trace_iterator *iter);
        void                    (*pipe_open)(struct trace_iterator *iter);
        void                    (*close)(struct trace_iterator *iter);
        ssize_t                 (*read)(struct trace_iterator *iter,
                                        struct file *filp, char __user *ubuf,
                                        size_t cnt, loff_t *ppos);
  -     void                    (*ctrl_update)(struct trace_array *tr);
   #ifdef CONFIG_FTRACE_STARTUP_TEST
        int                     (*selftest)(struct tracer *trace,
                                            struct trace_array *tr);
   #endif
  +     void                    (*print_header)(struct seq_file *m);
        enum print_line_t       (*print_line)(struct trace_iterator *iter);
  +     /* If you handled the flag setting, return 0 */
  +     int                     (*set_flag)(u32 old_flags, u32 bit, int set);
        struct tracer           *next;
        int                     print_max;
  +     struct tracer_flags     *flags;
   };
   
   struct trace_seq {
@@@@ -366,11 -367,11 -279,8 +367,11 @@@@ struct trace_iterator 
        unsigned long           iter_flags;
        loff_t                  pos;
        long                    idx;
  +
  +     cpumask_t               started;
   };
   
  +int tracing_is_enabled(void);
   void trace_wake_up(void);
   void tracing_reset(struct trace_array *tr, int cpu);
   int tracing_open_generic(struct inode *inode, struct file *filp);
@@@@ -411,17 -412,17 -321,8 +412,17 @@@@ void trace_function(struct trace_array 
                    unsigned long parent_ip,
                    unsigned long flags, int pc);
   
  +void trace_graph_return(struct ftrace_graph_ret *trace);
  +int trace_graph_entry(struct ftrace_graph_ent *trace);
  +void trace_bts(struct trace_array *tr,
  +            unsigned long from,
  +            unsigned long to);
  +
   void tracing_start_cmdline_record(void);
   void tracing_stop_cmdline_record(void);
  +void tracing_sched_switch_assign_trace(struct trace_array *tr);
  +void tracing_stop_sched_switch_record(void);
  +void tracing_start_sched_switch_record(void);
   int register_tracer(struct tracer *type);
   void unregister_tracer(struct tracer *type);
   
@@@@ -457,7 -458,7 -358,6 +458,7 @@@@ struct tracer_switch_ops 
        struct tracer_switch_ops        *next;
   };
   
  +char *trace_find_cmdline(int pid);
   #endif /* CONFIG_CONTEXT_SWITCH_TRACER */
   
   #ifdef CONFIG_DYNAMIC_FTRACE
@@@@ -483,78 -484,37 -383,19 +484,79 @@@@ extern int trace_selftest_startup_sched
                                               struct trace_array *tr);
   extern int trace_selftest_startup_sysprof(struct tracer *trace,
                                               struct trace_array *tr);
  +extern int trace_selftest_startup_branch(struct tracer *trace,
  +                                      struct trace_array *tr);
   #endif /* CONFIG_FTRACE_STARTUP_TEST */
   
   extern void *head_page(struct trace_array_cpu *data);
   extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...);
   extern void trace_seq_print_cont(struct trace_seq *s,
                                 struct trace_iterator *iter);
  +
  +extern int
  +seq_print_ip_sym(struct trace_seq *s, unsigned long ip,
  +             unsigned long sym_flags);
   extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
                                 size_t cnt);
   extern long ns2usecs(cycle_t nsec);
- -extern int trace_vprintk(unsigned long ip, const char *fmt, va_list args);
+ +extern int
+ +trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args);
   
   extern unsigned long trace_flags;
   
  +/* Standard output formatting function used for function return traces */
  +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  +extern enum print_line_t print_graph_function(struct trace_iterator *iter);
 ++
 ++#ifdef CONFIG_DYNAMIC_FTRACE
 ++/* TODO: make this variable */
 ++#define FTRACE_GRAPH_MAX_FUNCS               32
 ++extern int ftrace_graph_count;
 ++extern unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS];
 ++
 ++static inline int ftrace_graph_addr(unsigned long addr)
 ++{
 ++     int i;
 ++
 ++     if (!ftrace_graph_count || test_tsk_trace_graph(current))
 ++             return 1;
 ++
 ++     for (i = 0; i < ftrace_graph_count; i++) {
 ++             if (addr == ftrace_graph_funcs[i])
 ++                     return 1;
 ++     }
 ++
 ++     return 0;
 ++}
  +#else
 ++static inline int ftrace_trace_addr(unsigned long addr)
 ++{
 ++     return 1;
 ++}
 ++static inline int ftrace_graph_addr(unsigned long addr)
 ++{
 ++     return 1;
 ++}
 ++#endif /* CONFIG_DYNAMIC_FTRACE */
 ++
 ++#else /* CONFIG_FUNCTION_GRAPH_TRACER */
  +static inline enum print_line_t
  +print_graph_function(struct trace_iterator *iter)
  +{
  +     return TRACE_TYPE_UNHANDLED;
  +}
 - #endif
 ++#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 ++
 ++extern struct pid *ftrace_pid_trace;
 ++
 ++static inline int ftrace_trace_task(struct task_struct *task)
 ++{
 ++     if (ftrace_pid_trace)
 ++             return 1;
 ++
 ++     return test_tsk_trace_trace(task);
 ++}
  +
   /*
    * trace_iterator_flags is an enumeration that defines bit
    * positions into trace_flags that controls the output.
@@@@ -574,92 -534,92 -415,8 +576,92 @@@@ enum trace_iterator_flags 
        TRACE_ITER_STACKTRACE           = 0x100,
        TRACE_ITER_SCHED_TREE           = 0x200,
        TRACE_ITER_PRINTK               = 0x400,
  +     TRACE_ITER_PREEMPTONLY          = 0x800,
  +     TRACE_ITER_BRANCH               = 0x1000,
  +     TRACE_ITER_ANNOTATE             = 0x2000,
  +     TRACE_ITER_USERSTACKTRACE       = 0x4000,
  +     TRACE_ITER_SYM_USEROBJ          = 0x8000
   };
   
  +/*
  + * 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)
  +
   extern struct tracer nop_trace;
   
  +/**
  + * ftrace_preempt_disable - disable preemption scheduler safe
  + *
  + * When tracing can happen inside the scheduler, there exists
  + * cases that the tracing might happen before the need_resched
  + * flag is checked. If this happens and the tracer calls
  + * preempt_enable (after a disable), a schedule might take place
  + * causing an infinite recursion.
  + *
  + * To prevent this, we read the need_recshed flag before
  + * disabling preemption. When we want to enable preemption we
  + * check the flag, if it is set, then we call preempt_enable_no_resched.
  + * Otherwise, we call preempt_enable.
  + *
  + * The rational for doing the above is that if need resched is set
  + * and we have yet to reschedule, we are either in an atomic location
  + * (where we do not need to check for scheduling) or we are inside
  + * the scheduler and do not want to resched.
  + */
  +static inline int ftrace_preempt_disable(void)
  +{
  +     int resched;
  +
  +     resched = need_resched();
  +     preempt_disable_notrace();
  +
  +     return resched;
  +}
  +
  +/**
  + * ftrace_preempt_enable - enable preemption scheduler safe
  + * @resched: the return value from ftrace_preempt_disable
  + *
  + * This is a scheduler safe way to enable preemption and not miss
  + * any preemption checks. The disabled saved the state of preemption.
  + * If resched is set, then we were either inside an atomic or
  + * are inside the scheduler (we would have already scheduled
  + * otherwise). In this case, we do not want to call normal
  + * preempt_enable, but preempt_enable_no_resched instead.
  + */
  +static inline void ftrace_preempt_enable(int resched)
  +{
  +     if (resched)
  +             preempt_enable_no_resched_notrace();
  +     else
  +             preempt_enable_notrace();
  +}
  +
  +#ifdef CONFIG_BRANCH_TRACER
  +extern int enable_branch_tracing(struct trace_array *tr);
  +extern void disable_branch_tracing(void);
  +static inline int trace_branch_enable(struct trace_array *tr)
  +{
  +     if (trace_flags & TRACE_ITER_BRANCH)
  +             return enable_branch_tracing(tr);
  +     return 0;
  +}
  +static inline void trace_branch_disable(void)
  +{
  +     /* due to races, always disable */
  +     disable_branch_tracing();
  +}
  +#else
  +static inline int trace_branch_enable(struct trace_array *tr)
  +{
  +     return 0;
  +}
  +static inline void trace_branch_disable(void)
  +{
  +}
  +#endif /* CONFIG_BRANCH_TRACER */
  +
   #endif /* _LINUX_KERNEL_TRACE_H */