Merge tag 'trace-v6.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[linux-2.6-microblaze.git] / kernel / trace / trace.c
index c9e40f6..937e967 100644 (file)
@@ -49,6 +49,8 @@
 #include <linux/irq_work.h>
 #include <linux/workqueue.h>
 
+#include <asm/setup.h> /* COMMAND_LINE_SIZE */
+
 #include "trace.h"
 #include "trace_output.h"
 
@@ -186,6 +188,12 @@ static char *default_bootup_tracer;
 static bool allocate_snapshot;
 static bool snapshot_at_boot;
 
+static char boot_instance_info[COMMAND_LINE_SIZE] __initdata;
+static int boot_instance_index;
+
+static char boot_snapshot_info[COMMAND_LINE_SIZE] __initdata;
+static int boot_snapshot_index;
+
 static int __init set_cmdline_ftrace(char *str)
 {
        strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
@@ -222,9 +230,22 @@ __setup("traceoff_on_warning", stop_trace_on_warning);
 
 static int __init boot_alloc_snapshot(char *str)
 {
-       allocate_snapshot = true;
-       /* We also need the main ring buffer expanded */
-       ring_buffer_expanded = true;
+       char *slot = boot_snapshot_info + boot_snapshot_index;
+       int left = sizeof(boot_snapshot_info) - boot_snapshot_index;
+       int ret;
+
+       if (str[0] == '=') {
+               str++;
+               if (strlen(str) >= left)
+                       return -1;
+
+               ret = snprintf(slot, left, "%s\t", str);
+               boot_snapshot_index += ret;
+       } else {
+               allocate_snapshot = true;
+               /* We also need the main ring buffer expanded */
+               ring_buffer_expanded = true;
+       }
        return 1;
 }
 __setup("alloc_snapshot", boot_alloc_snapshot);
@@ -239,6 +260,23 @@ static int __init boot_snapshot(char *str)
 __setup("ftrace_boot_snapshot", boot_snapshot);
 
 
+static int __init boot_instance(char *str)
+{
+       char *slot = boot_instance_info + boot_instance_index;
+       int left = sizeof(boot_instance_info) - boot_instance_index;
+       int ret;
+
+       if (strlen(str) >= left)
+               return -1;
+
+       ret = snprintf(slot, left, "%s\t", str);
+       boot_instance_index += ret;
+
+       return 1;
+}
+__setup("trace_instance=", boot_instance);
+
+
 static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata;
 
 static int __init set_trace_boot_options(char *str)
@@ -1001,13 +1039,8 @@ __buffer_unlock_commit(struct trace_buffer *buffer, struct ring_buffer_event *ev
                ring_buffer_unlock_commit(buffer);
 }
 
-/**
- * __trace_puts - write a constant string into the trace buffer.
- * @ip:           The address of the caller
- * @str:   The constant string to write
- * @size:  The size of the string.
- */
-int __trace_puts(unsigned long ip, const char *str, int size)
+int __trace_array_puts(struct trace_array *tr, unsigned long ip,
+                      const char *str, int size)
 {
        struct ring_buffer_event *event;
        struct trace_buffer *buffer;
@@ -1015,7 +1048,7 @@ int __trace_puts(unsigned long ip, const char *str, int size)
        unsigned int trace_ctx;
        int alloc;
 
-       if (!(global_trace.trace_flags & TRACE_ITER_PRINTK))
+       if (!(tr->trace_flags & TRACE_ITER_PRINTK))
                return 0;
 
        if (unlikely(tracing_selftest_running || tracing_disabled))
@@ -1024,7 +1057,7 @@ int __trace_puts(unsigned long ip, const char *str, int size)
        alloc = sizeof(*entry) + size + 2; /* possible \n added */
 
        trace_ctx = tracing_gen_ctx();
-       buffer = global_trace.array_buffer.buffer;
+       buffer = tr->array_buffer.buffer;
        ring_buffer_nest_start(buffer);
        event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc,
                                            trace_ctx);
@@ -1046,11 +1079,23 @@ int __trace_puts(unsigned long ip, const char *str, int size)
                entry->buf[size] = '\0';
 
        __buffer_unlock_commit(buffer, event);
-       ftrace_trace_stack(&global_trace, buffer, trace_ctx, 4, NULL);
+       ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL);
  out:
        ring_buffer_nest_end(buffer);
        return size;
 }
+EXPORT_SYMBOL_GPL(__trace_array_puts);
+
+/**
+ * __trace_puts - write a constant string into the trace buffer.
+ * @ip:           The address of the caller
+ * @str:   The constant string to write
+ * @size:  The size of the string.
+ */
+int __trace_puts(unsigned long ip, const char *str, int size)
+{
+       return __trace_array_puts(&global_trace, ip, str, size);
+}
 EXPORT_SYMBOL_GPL(__trace_puts);
 
 /**
@@ -1142,7 +1187,7 @@ void tracing_snapshot_instance(struct trace_array *tr)
  *
  * Note, make sure to allocate the snapshot with either
  * a tracing_snapshot_alloc(), or by doing it manually
- * with: echo 1 > /sys/kernel/debug/tracing/snapshot
+ * with: echo 1 > /sys/kernel/tracing/snapshot
  *
  * If the snapshot buffer is not allocated, it will stop tracing.
  * Basically making a permanent snapshot.
@@ -3128,6 +3173,9 @@ void __trace_stack(struct trace_array *tr, unsigned int trace_ctx,
                return;
        }
 
+       if (WARN_ON_ONCE(IS_ENABLED(CONFIG_GENERIC_ENTRY)))
+               return;
+
        /*
         * When an NMI triggers, RCU is enabled via ct_nmi_enter(),
         * but if the above rcu_is_watching() failed, then the NMI
@@ -5119,6 +5167,8 @@ loff_t tracing_lseek(struct file *file, loff_t offset, int whence)
 static const struct file_operations tracing_fops = {
        .open           = tracing_open,
        .read           = seq_read,
+       .read_iter      = seq_read_iter,
+       .splice_read    = generic_file_splice_read,
        .write          = tracing_write_stub,
        .llseek         = tracing_lseek,
        .release        = tracing_release,
@@ -5598,7 +5648,7 @@ static const char readme_msg[] =
 #ifdef CONFIG_HIST_TRIGGERS
        "\t           s:[synthetic/]<event> <field> [<field>]\n"
 #endif
-       "\t           e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>]\n"
+       "\t           e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>] [if <filter>]\n"
        "\t           -:[<group>/][<event>]\n"
 #ifdef CONFIG_KPROBE_EVENTS
        "\t    place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
@@ -5615,7 +5665,7 @@ static const char readme_msg[] =
        "\t           $stack<index>, $stack, $retval, $comm,\n"
 #endif
        "\t           +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
-       "\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
+       "\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol,\n"
        "\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
        "\t           symstr, <type>\\[<array-size>\\]\n"
 #ifdef CONFIG_HIST_TRIGGERS
@@ -5757,7 +5807,7 @@ static const char readme_msg[] =
 #ifdef CONFIG_SYNTH_EVENTS
        "  events/synthetic_events\t- Create/append/remove/show synthetic events\n"
        "\t  Write into this file to define/undefine new synthetic events.\n"
-       "\t     example: echo 'myevent u64 lat; char name[]' >> synthetic_events\n"
+       "\t     example: echo 'myevent u64 lat; char name[]; long[] stack' >> synthetic_events\n"
 #endif
 #endif
 ;
@@ -9222,10 +9272,6 @@ static int allocate_trace_buffers(struct trace_array *tr, int size)
        }
        tr->allocated_snapshot = allocate_snapshot;
 
-       /*
-        * Only the top level trace array gets its snapshot allocated
-        * from the kernel command line.
-        */
        allocate_snapshot = false;
 #endif
 
@@ -10141,6 +10187,79 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_TRACER_MAX_TRACE
+__init static bool tr_needs_alloc_snapshot(const char *name)
+{
+       char *test;
+       int len = strlen(name);
+       bool ret;
+
+       if (!boot_snapshot_index)
+               return false;
+
+       if (strncmp(name, boot_snapshot_info, len) == 0 &&
+           boot_snapshot_info[len] == '\t')
+               return true;
+
+       test = kmalloc(strlen(name) + 3, GFP_KERNEL);
+       if (!test)
+               return false;
+
+       sprintf(test, "\t%s\t", name);
+       ret = strstr(boot_snapshot_info, test) == NULL;
+       kfree(test);
+       return ret;
+}
+
+__init static void do_allocate_snapshot(const char *name)
+{
+       if (!tr_needs_alloc_snapshot(name))
+               return;
+
+       /*
+        * When allocate_snapshot is set, the next call to
+        * allocate_trace_buffers() (called by trace_array_get_by_name())
+        * will allocate the snapshot buffer. That will alse clear
+        * this flag.
+        */
+       allocate_snapshot = true;
+}
+#else
+static inline void do_allocate_snapshot(const char *name) { }
+#endif
+
+__init static void enable_instances(void)
+{
+       struct trace_array *tr;
+       char *curr_str;
+       char *str;
+       char *tok;
+
+       /* A tab is always appended */
+       boot_instance_info[boot_instance_index - 1] = '\0';
+       str = boot_instance_info;
+
+       while ((curr_str = strsep(&str, "\t"))) {
+
+               tok = strsep(&curr_str, ",");
+
+               if (IS_ENABLED(CONFIG_TRACER_MAX_TRACE))
+                       do_allocate_snapshot(tok);
+
+               tr = trace_array_get_by_name(tok);
+               if (!tr) {
+                       pr_warn("Failed to create instance buffer %s\n", curr_str);
+                       continue;
+               }
+               /* Allow user space to delete it */
+               trace_array_put(tr);
+
+               while ((tok = strsep(&curr_str, ","))) {
+                       early_enable_events(tr, tok, true);
+               }
+       }
+}
+
 __init static int tracer_alloc_buffers(void)
 {
        int ring_buf_size;
@@ -10274,10 +10393,19 @@ out:
 
 void __init ftrace_boot_snapshot(void)
 {
+       struct trace_array *tr;
+
        if (snapshot_at_boot) {
                tracing_snapshot();
                internal_trace_puts("** Boot snapshot taken **\n");
        }
+
+       list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+               if (tr == &global_trace)
+                       continue;
+               trace_array_puts(tr, "** Boot snapshot taken **\n");
+               tracing_snapshot_instance(tr);
+       }
 }
 
 void __init early_trace_init(void)
@@ -10299,6 +10427,9 @@ void __init early_trace_init(void)
 void __init trace_init(void)
 {
        trace_event_init();
+
+       if (boot_instance_index)
+               enable_instances();
 }
 
 __init static void clear_boot_tracer(void)