]> Pileus Git - ~andy/linux/blobdiff - kernel/trace/trace.c
Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
[~andy/linux] / kernel / trace / trace.c
index 9d20cd9743efc0bf02cff0cf0f5536c19d0252cc..24c1f23825579df4f2bf46e2dca98e6af8fb4abd 100644 (file)
@@ -455,6 +455,9 @@ int __trace_puts(unsigned long ip, const char *str, int size)
        unsigned long irq_flags;
        int alloc;
 
+       if (unlikely(tracing_selftest_running || tracing_disabled))
+               return 0;
+
        alloc = sizeof(*entry) + size + 2; /* possible \n added */
 
        local_save_flags(irq_flags);
@@ -495,6 +498,9 @@ int __trace_bputs(unsigned long ip, const char *str)
        unsigned long irq_flags;
        int size = sizeof(struct bputs_entry);
 
+       if (unlikely(tracing_selftest_running || tracing_disabled))
+               return 0;
+
        local_save_flags(irq_flags);
        buffer = global_trace.trace_buffer.buffer;
        event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size,
@@ -594,6 +600,28 @@ void free_snapshot(struct trace_array *tr)
        tr->allocated_snapshot = false;
 }
 
+/**
+ * tracing_alloc_snapshot - allocate snapshot buffer.
+ *
+ * This only allocates the snapshot buffer if it isn't already
+ * allocated - it doesn't also take a snapshot.
+ *
+ * This is meant to be used in cases where the snapshot buffer needs
+ * to be set up for events that can't sleep but need to be able to
+ * trigger a snapshot.
+ */
+int tracing_alloc_snapshot(void)
+{
+       struct trace_array *tr = &global_trace;
+       int ret;
+
+       ret = alloc_snapshot(tr);
+       WARN_ON(ret < 0);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(tracing_alloc_snapshot);
+
 /**
  * trace_snapshot_alloc - allocate and take a snapshot of the current buffer.
  *
@@ -607,11 +635,10 @@ void free_snapshot(struct trace_array *tr)
  */
 void tracing_snapshot_alloc(void)
 {
-       struct trace_array *tr = &global_trace;
        int ret;
 
-       ret = alloc_snapshot(tr);
-       if (WARN_ON(ret < 0))
+       ret = tracing_alloc_snapshot();
+       if (ret < 0)
                return;
 
        tracing_snapshot();
@@ -623,6 +650,12 @@ void tracing_snapshot(void)
        WARN_ONCE(1, "Snapshot feature not enabled, but internal snapshot used");
 }
 EXPORT_SYMBOL_GPL(tracing_snapshot);
+int tracing_alloc_snapshot(void)
+{
+       WARN_ONCE(1, "Snapshot feature not enabled, but snapshot allocation used");
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(tracing_alloc_snapshot);
 void tracing_snapshot_alloc(void)
 {
        /* Give warning */
@@ -1567,15 +1600,31 @@ void trace_buffer_unlock_commit(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
 
+static struct ring_buffer *temp_buffer;
+
 struct ring_buffer_event *
 trace_event_buffer_lock_reserve(struct ring_buffer **current_rb,
                          struct ftrace_event_file *ftrace_file,
                          int type, unsigned long len,
                          unsigned long flags, int pc)
 {
+       struct ring_buffer_event *entry;
+
        *current_rb = ftrace_file->tr->trace_buffer.buffer;
-       return trace_buffer_lock_reserve(*current_rb,
+       entry = trace_buffer_lock_reserve(*current_rb,
                                         type, len, flags, pc);
+       /*
+        * If tracing is off, but we have triggers enabled
+        * we still need to look at the event data. Use the temp_buffer
+        * to store the trace event for the tigger to use. It's recusive
+        * safe and will not be recorded anywhere.
+        */
+       if (!entry && ftrace_file->flags & FTRACE_EVENT_FL_TRIGGER_COND) {
+               *current_rb = temp_buffer;
+               entry = trace_buffer_lock_reserve(*current_rb,
+                                                 type, len, flags, pc);
+       }
+       return entry;
 }
 EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve);
 
@@ -3156,19 +3205,23 @@ tracing_write_stub(struct file *filp, const char __user *ubuf,
        return count;
 }
 
-static loff_t tracing_seek(struct file *file, loff_t offset, int origin)
+loff_t tracing_lseek(struct file *file, loff_t offset, int whence)
 {
+       int ret;
+
        if (file->f_mode & FMODE_READ)
-               return seq_lseek(file, offset, origin);
+               ret = seq_lseek(file, offset, whence);
        else
-               return 0;
+               file->f_pos = ret = 0;
+
+       return ret;
 }
 
 static const struct file_operations tracing_fops = {
        .open           = tracing_open,
        .read           = seq_read,
        .write          = tracing_write_stub,
-       .llseek         = tracing_seek,
+       .llseek         = tracing_lseek,
        .release        = tracing_release,
 };
 
@@ -3488,60 +3541,103 @@ static const char readme_msg[] =
        "  instances\t\t- Make sub-buffers with: mkdir instances/foo\n"
        "\t\t\t  Remove sub-buffer with rmdir\n"
        "  trace_options\t\t- Set format or modify how tracing happens\n"
-       "\t\t\t  Disable an option by adding a suffix 'no' to the option name\n"
+       "\t\t\t  Disable an option by adding a suffix 'no' to the\n"
+       "\t\t\t  option name\n"
 #ifdef CONFIG_DYNAMIC_FTRACE
        "\n  available_filter_functions - list of functions that can be filtered on\n"
-       "  set_ftrace_filter\t- echo function name in here to only trace these functions\n"
-       "            accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
-       "            modules: Can select a group via module\n"
-       "             Format: :mod:<module-name>\n"
-       "             example: echo :mod:ext3 > set_ftrace_filter\n"
-       "            triggers: a command to perform when function is hit\n"
-       "              Format: <function>:<trigger>[:count]\n"
-       "             trigger: traceon, traceoff\n"
-       "                      enable_event:<system>:<event>\n"
-       "                      disable_event:<system>:<event>\n"
+       "  set_ftrace_filter\t- echo function name in here to only trace these\n"
+       "\t\t\t  functions\n"
+       "\t     accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
+       "\t     modules: Can select a group via module\n"
+       "\t      Format: :mod:<module-name>\n"
+       "\t     example: echo :mod:ext3 > set_ftrace_filter\n"
+       "\t    triggers: a command to perform when function is hit\n"
+       "\t      Format: <function>:<trigger>[:count]\n"
+       "\t     trigger: traceon, traceoff\n"
+       "\t\t      enable_event:<system>:<event>\n"
+       "\t\t      disable_event:<system>:<event>\n"
 #ifdef CONFIG_STACKTRACE
-       "                      stacktrace\n"
+       "\t\t      stacktrace\n"
 #endif
 #ifdef CONFIG_TRACER_SNAPSHOT
-       "                      snapshot\n"
+       "\t\t      snapshot\n"
 #endif
-       "             example: echo do_fault:traceoff > set_ftrace_filter\n"
-       "                      echo do_trap:traceoff:3 > set_ftrace_filter\n"
-       "             The first one will disable tracing every time do_fault is hit\n"
-       "             The second will disable tracing at most 3 times when do_trap is hit\n"
-       "               The first time do trap is hit and it disables tracing, the counter\n"
-       "               will decrement to 2. If tracing is already disabled, the counter\n"
-       "               will not decrement. It only decrements when the trigger did work\n"
-       "             To remove trigger without count:\n"
-       "               echo '!<function>:<trigger> > set_ftrace_filter\n"
-       "             To remove trigger with a count:\n"
-       "               echo '!<function>:<trigger>:0 > set_ftrace_filter\n"
+       "\t     example: echo do_fault:traceoff > set_ftrace_filter\n"
+       "\t              echo do_trap:traceoff:3 > set_ftrace_filter\n"
+       "\t     The first one will disable tracing every time do_fault is hit\n"
+       "\t     The second will disable tracing at most 3 times when do_trap is hit\n"
+       "\t       The first time do trap is hit and it disables tracing, the\n"
+       "\t       counter will decrement to 2. If tracing is already disabled,\n"
+       "\t       the counter will not decrement. It only decrements when the\n"
+       "\t       trigger did work\n"
+       "\t     To remove trigger without count:\n"
+       "\t       echo '!<function>:<trigger> > set_ftrace_filter\n"
+       "\t     To remove trigger with a count:\n"
+       "\t       echo '!<function>:<trigger>:0 > set_ftrace_filter\n"
        "  set_ftrace_notrace\t- echo function name in here to never trace.\n"
-       "            accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
-       "            modules: Can select a group via module command :mod:\n"
-       "            Does not accept triggers\n"
+       "\t    accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
+       "\t    modules: Can select a group via module command :mod:\n"
+       "\t    Does not accept triggers\n"
 #endif /* CONFIG_DYNAMIC_FTRACE */
 #ifdef CONFIG_FUNCTION_TRACER
-       "  set_ftrace_pid\t- Write pid(s) to only function trace those pids (function)\n"
+       "  set_ftrace_pid\t- Write pid(s) to only function trace those pids\n"
+       "\t\t    (function)\n"
 #endif
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        "  set_graph_function\t- Trace the nested calls of a function (function_graph)\n"
        "  max_graph_depth\t- Trace a limited depth of nested calls (0 is unlimited)\n"
 #endif
 #ifdef CONFIG_TRACER_SNAPSHOT
-       "\n  snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n"
-       "\t\t\t  Read the contents for more information\n"
+       "\n  snapshot\t\t- Like 'trace' but shows the content of the static\n"
+       "\t\t\t  snapshot buffer. Read the contents for more\n"
+       "\t\t\t  information\n"
 #endif
 #ifdef CONFIG_STACK_TRACER
        "  stack_trace\t\t- Shows the max stack trace when active\n"
        "  stack_max_size\t- Shows current max stack size that was traced\n"
-       "\t\t\t  Write into this file to reset the max size (trigger a new trace)\n"
+       "\t\t\t  Write into this file to reset the max size (trigger a\n"
+       "\t\t\t  new trace)\n"
 #ifdef CONFIG_DYNAMIC_FTRACE
-       "  stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n"
+       "  stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace\n"
+       "\t\t\t  traces\n"
 #endif
 #endif /* CONFIG_STACK_TRACER */
+       "  events/\t\t- Directory containing all trace event subsystems:\n"
+       "      enable\t\t- Write 0/1 to enable/disable tracing of all events\n"
+       "  events/<system>/\t- Directory containing all trace events for <system>:\n"
+       "      enable\t\t- Write 0/1 to enable/disable tracing of all <system>\n"
+       "\t\t\t  events\n"
+       "      filter\t\t- If set, only events passing filter are traced\n"
+       "  events/<system>/<event>/\t- Directory containing control files for\n"
+       "\t\t\t  <event>:\n"
+       "      enable\t\t- Write 0/1 to enable/disable tracing of <event>\n"
+       "      filter\t\t- If set, only events passing filter are traced\n"
+       "      trigger\t\t- If set, a command to perform when event is hit\n"
+       "\t    Format: <trigger>[:count][if <filter>]\n"
+       "\t   trigger: traceon, traceoff\n"
+       "\t            enable_event:<system>:<event>\n"
+       "\t            disable_event:<system>:<event>\n"
+#ifdef CONFIG_STACKTRACE
+       "\t\t    stacktrace\n"
+#endif
+#ifdef CONFIG_TRACER_SNAPSHOT
+       "\t\t    snapshot\n"
+#endif
+       "\t   example: echo traceoff > events/block/block_unplug/trigger\n"
+       "\t            echo traceoff:3 > events/block/block_unplug/trigger\n"
+       "\t            echo 'enable_event:kmem:kmalloc:3 if nr_rq > 1' > \\\n"
+       "\t                  events/block/block_unplug/trigger\n"
+       "\t   The first disables tracing every time block_unplug is hit.\n"
+       "\t   The second disables tracing the first 3 times block_unplug is hit.\n"
+       "\t   The third enables the kmalloc event the first 3 times block_unplug\n"
+       "\t     is hit and has value of greater than 1 for the 'nr_rq' event field.\n"
+       "\t   Like function triggers, the counter is only decremented if it\n"
+       "\t    enabled or disabled tracing.\n"
+       "\t   To remove a trigger without a count:\n"
+       "\t     echo '!<trigger> > <system>/<event>/trigger\n"
+       "\t   To remove a trigger with a count:\n"
+       "\t     echo '!<trigger>:0 > <system>/<event>/trigger\n"
+       "\t   Filters can be ignored when removing a trigger.\n"
 ;
 
 static ssize_t
@@ -4212,12 +4308,6 @@ out:
        return sret;
 }
 
-static void tracing_pipe_buf_release(struct pipe_inode_info *pipe,
-                                    struct pipe_buffer *buf)
-{
-       __free_page(buf->page);
-}
-
 static void tracing_spd_release_pipe(struct splice_pipe_desc *spd,
                                     unsigned int idx)
 {
@@ -4229,7 +4319,7 @@ static const struct pipe_buf_operations tracing_pipe_buf_ops = {
        .map                    = generic_pipe_buf_map,
        .unmap                  = generic_pipe_buf_unmap,
        .confirm                = generic_pipe_buf_confirm,
-       .release                = tracing_pipe_buf_release,
+       .release                = generic_pipe_buf_release,
        .steal                  = generic_pipe_buf_steal,
        .get                    = generic_pipe_buf_get,
 };
@@ -4913,7 +5003,7 @@ static const struct file_operations snapshot_fops = {
        .open           = tracing_snapshot_open,
        .read           = seq_read,
        .write          = tracing_snapshot_write,
-       .llseek         = tracing_seek,
+       .llseek         = tracing_lseek,
        .release        = tracing_snapshot_release,
 };
 
@@ -5883,6 +5973,8 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size
 
        rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
 
+       buf->tr = tr;
+
        buf->buffer = ring_buffer_alloc(size, rb_flags);
        if (!buf->buffer)
                return -ENOMEM;
@@ -6418,11 +6510,16 @@ __init static int tracer_alloc_buffers(void)
 
        raw_spin_lock_init(&global_trace.start_lock);
 
+       /* Used for event triggers */
+       temp_buffer = ring_buffer_alloc(PAGE_SIZE, RB_FL_OVERWRITE);
+       if (!temp_buffer)
+               goto out_free_cpumask;
+
        /* TODO: make the number of buffers hot pluggable with CPUS */
        if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) {
                printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
                WARN_ON(1);
-               goto out_free_cpumask;
+               goto out_free_temp_buffer;
        }
 
        if (global_trace.buffer_disabled)
@@ -6464,6 +6561,8 @@ __init static int tracer_alloc_buffers(void)
 
        return 0;
 
+out_free_temp_buffer:
+       ring_buffer_free(temp_buffer);
 out_free_cpumask:
        free_percpu(global_trace.trace_buffer.data);
 #ifdef CONFIG_TRACER_MAX_TRACE