Merge tag 'trace-v5.6-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 26 Feb 2020 18:34:42 +0000 (10:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 26 Feb 2020 18:34:42 +0000 (10:34 -0800)
Pull tracing and bootconfig updates:
 "Fixes and changes to bootconfig before it goes live in a release.

  Change in API of bootconfig (before it comes live in a release):
  - Have a magic value "BOOTCONFIG" in initrd to know a bootconfig
    exists
  - Set CONFIG_BOOT_CONFIG to 'n' by default
  - Show error if "bootconfig" on cmdline but not compiled in
  - Prevent redefining the same value
  - Have a way to append values
  - Added a SELECT BLK_DEV_INITRD to fix a build failure

  Synthetic event fixes:
  - Switch to raw_smp_processor_id() for recording CPU value in preempt
    section. (No care for what the value actually is)
  - Fix samples always recording u64 values
  - Fix endianess
  - Check number of values matches number of fields
  - Fix a printing bug

  Fix of trace_printk() breaking postponed start up tests

  Make a function static that is only used in a single file"

* tag 'trace-v5.6-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  bootconfig: Fix CONFIG_BOOTTIME_TRACING dependency issue
  bootconfig: Add append value operator support
  bootconfig: Prohibit re-defining value on same key
  bootconfig: Print array as multiple commands for legacy command line
  bootconfig: Reject subkey and value on same parent key
  tools/bootconfig: Remove unneeded error message silencer
  bootconfig: Add bootconfig magic word for indicating bootconfig explicitly
  bootconfig: Set CONFIG_BOOT_CONFIG=n by default
  tracing: Clear trace_state when starting trace
  bootconfig: Mark boot_config_checksum() static
  tracing: Disable trace_printk() on post poned tests
  tracing: Have synthetic event test use raw_smp_processor_id()
  tracing: Fix number printing bug in print_synth_event()
  tracing: Check that number of vals matches number of synth event fields
  tracing: Make synth_event trace functions endian-correct
  tracing: Make sure synth_event_trace() example always uses u64

1  2 
init/Kconfig
init/main.c
kernel/trace/trace.c
kernel/trace/trace_events_hist.c

diff --combined init/Kconfig
@@@ -54,12 -54,11 +54,12 @@@ config CC_DISABLE_WARN_MAYBE_UNINITIALI
  
  config CONSTRUCTORS
        bool
 +      depends on !UML
  
  config IRQ_WORK
        bool
  
 -config BUILDTIME_EXTABLE_SORT
 +config BUILDTIME_TABLE_SORT
        bool
  
  config THREAD_INFO_IN_TASK
@@@ -1081,14 -1080,6 +1081,14 @@@ config UTS_N
          In this namespace tasks see different info provided with the
          uname() system call
  
 +config TIME_NS
 +      bool "TIME namespace"
 +      depends on GENERIC_VDSO_TIME_NS
 +      default y
 +      help
 +        In this namespace boottime and monotonic clocks can be set.
 +        The time will keep going with the same pace.
 +
  config IPC_NS
        bool "IPC namespace"
        depends on (SYSVIPC || POSIX_MQUEUE)
@@@ -1226,13 -1217,12 +1226,12 @@@ endi
  
  config BOOT_CONFIG
        bool "Boot config support"
-       depends on BLK_DEV_INITRD
-       default y
+       select BLK_DEV_INITRD
        help
          Extra boot config allows system admin to pass a config file as
          complemental extension of kernel cmdline when booting.
          The boot config file must be attached at the end of initramfs
-         with checksum and size.
+         with checksum, size and magic word.
          See <file:Documentation/admin-guide/bootconfig.rst> for details.
  
          If unsure, say Y.
@@@ -1626,9 -1616,6 +1625,9 @@@ config BPF_SYSCAL
          Enable the bpf() system call that allows to manipulate eBPF
          programs and maps via file descriptors.
  
 +config ARCH_WANT_DEFAULT_BPF_JIT
 +      bool
 +
  config BPF_JIT_ALWAYS_ON
        bool "Permanently enable BPF JIT and remove BPF interpreter"
        depends on BPF_SYSCALL && HAVE_EBPF_JIT && BPF_JIT
          Enables BPF JIT and removes BPF interpreter to avoid
          speculative execution of BPF instructions by the interpreter
  
 +config BPF_JIT_DEFAULT_ON
 +      def_bool ARCH_WANT_DEFAULT_BPF_JIT || BPF_JIT_ALWAYS_ON
 +      depends on HAVE_EBPF_JIT && BPF_JIT
 +
  config USERFAULTFD
        bool "Enable userfaultfd() system call"
        depends on MMU
diff --combined init/main.c
@@@ -64,7 -64,7 +64,7 @@@
  #include <linux/lockdep.h>
  #include <linux/kmemleak.h>
  #include <linux/pid_namespace.h>
 -#include <linux/device.h>
 +#include <linux/device/driver.h>
  #include <linux/kthread.h>
  #include <linux/sched.h>
  #include <linux/sched/init.h>
@@@ -268,7 -268,6 +268,6 @@@ static int __init xbc_snprint_cmdline(c
  {
        struct xbc_node *knode, *vnode;
        char *end = buf + size;
-       char c = '\"';
        const char *val;
        int ret;
  
                        return ret;
  
                vnode = xbc_node_get_child(knode);
-               ret = snprintf(buf, rest(buf, end), "%s%c", xbc_namebuf,
-                               vnode ? '=' : ' ');
-               if (ret < 0)
-                       return ret;
-               buf += ret;
-               if (!vnode)
+               if (!vnode) {
+                       ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
+                       if (ret < 0)
+                               return ret;
+                       buf += ret;
                        continue;
-               c = '\"';
+               }
                xbc_array_for_each_value(vnode, val) {
-                       ret = snprintf(buf, rest(buf, end), "%c%s", c, val);
+                       ret = snprintf(buf, rest(buf, end), "%s=\"%s\" ",
+                                      xbc_namebuf, val);
                        if (ret < 0)
                                return ret;
                        buf += ret;
-                       c = ',';
                }
-               if (rest(buf, end) > 2)
-                       strcpy(buf, "\" ");
-               buf += 2;
        }
  
        return buf - (end - size);
@@@ -335,7 -329,7 +329,7 @@@ static char * __init xbc_make_cmdline(c
        return new_cmdline;
  }
  
- u32 boot_config_checksum(unsigned char *p, u32 size)
static u32 boot_config_checksum(unsigned char *p, u32 size)
  {
        u32 ret = 0;
  
@@@ -374,7 -368,11 +368,11 @@@ static void __init setup_boot_config(co
        if (!initrd_end)
                goto not_found;
  
-       hdr = (u32 *)(initrd_end - 8);
+       data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;
+       if (memcmp(data, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN))
+               goto not_found;
+       hdr = (u32 *)(data - 8);
        size = hdr[0];
        csum = hdr[1];
  
@@@ -418,10 -416,19 +416,18 @@@ not_found
  }
  #else
  #define setup_boot_config(cmdline)    do { } while (0)
+ static int __init warn_bootconfig(char *str)
+ {
+       pr_warn("WARNING: 'bootconfig' found on the kernel command line but CONFIG_BOOTCONFIG is not set.\n");
+       return 0;
+ }
+ early_param("bootconfig", warn_bootconfig);
  #endif
  
  /* Change NUL term back to "=", to make "param" the whole string. */
 -static int __init repair_env_string(char *param, char *val,
 -                                  const char *unused, void *arg)
 +static void __init repair_env_string(char *param, char *val)
  {
        if (val) {
                /* param=val or param="val"? */
                else if (val == param+strlen(param)+2) {
                        val[-2] = '=';
                        memmove(val-1, val, strlen(val)+1);
 -                      val--;
                } else
                        BUG();
        }
 -      return 0;
  }
  
  /* Anything after -- gets handed straight to init. */
@@@ -444,7 -453,7 +450,7 @@@ static int __init set_init_arg(char *pa
        if (panic_later)
                return 0;
  
 -      repair_env_string(param, val, unused, NULL);
 +      repair_env_string(param, val);
  
        for (i = 0; argv_init[i]; i++) {
                if (i == MAX_INIT_ARGS) {
  static int __init unknown_bootoption(char *param, char *val,
                                     const char *unused, void *arg)
  {
 -      repair_env_string(param, val, unused, NULL);
 +      size_t len = strlen(param);
 +
 +      repair_env_string(param, val);
  
        /* Handle obsolete-style parameters */
        if (obsolete_checksetup(param))
                return 0;
  
        /* Unused module parameter. */
 -      if (strchr(param, '.') && (!val || strchr(param, '.') < val))
 +      if (strnchr(param, len, '.'))
                return 0;
  
        if (panic_later)
                                panic_later = "env";
                                panic_param = param;
                        }
 -                      if (!strncmp(param, envp_init[i], val - param))
 +                      if (!strncmp(param, envp_init[i], len+1))
                                break;
                }
                envp_init[i] = param;
@@@ -756,7 -763,6 +762,7 @@@ static void __init mm_init(void
         * bigger than MAX_ORDER unless SPARSEMEM.
         */
        page_ext_init_flatmem();
 +      init_debug_pagealloc();
        report_meminit();
        mem_init();
        kmem_cache_init();
@@@ -1198,12 -1204,6 +1204,12 @@@ static const char *initcall_level_names
        "late",
  };
  
 +static int __init ignore_unknown_bootoption(char *param, char *val,
 +                             const char *unused, void *arg)
 +{
 +      return 0;
 +}
 +
  static void __init do_initcall_level(int level, char *command_line)
  {
        initcall_entry_t *fn;
                   command_line, __start___param,
                   __stop___param - __start___param,
                   level, level,
 -                 NULL, &repair_env_string);
 +                 NULL, ignore_unknown_bootoption);
  
        trace_initcall_level(initcall_level_names[level]);
        for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
@@@ -1266,16 -1266,8 +1272,16 @@@ static void __init do_pre_smp_initcalls
  
  static int run_init_process(const char *init_filename)
  {
 +      const char *const *p;
 +
        argv_init[0] = init_filename;
        pr_info("Run %s as init process\n", init_filename);
 +      pr_debug("  with arguments:\n");
 +      for (p = argv_init; *p; p++)
 +              pr_debug("    %s\n", *p);
 +      pr_debug("  with environment:\n");
 +      for (p = envp_init; *p; p++)
 +              pr_debug("    %s\n", *p);
        return do_execve(getname_kernel(init_filename),
                (const char __user *const __user *)argv_init,
                (const char __user *const __user *)envp_init);
@@@ -1322,11 -1314,6 +1328,11 @@@ static void mark_readonly(void
        } else
                pr_info("Kernel memory protection disabled.\n");
  }
 +#elif defined(CONFIG_ARCH_HAS_STRICT_KERNEL_RWX)
 +static inline void mark_readonly(void)
 +{
 +      pr_warn("Kernel memory protection not selected by kernel config.\n");
 +}
  #else
  static inline void mark_readonly(void)
  {
diff --combined kernel/trace/trace.c
@@@ -1837,6 -1837,7 +1837,7 @@@ static __init int init_trace_selftests(
  
        pr_info("Running postponed tracer tests:\n");
  
+       tracing_selftest_running = true;
        list_for_each_entry_safe(p, n, &postponed_selftests, list) {
                /* This loop can take minutes when sanitizers are enabled, so
                 * lets make sure we allow RCU processing.
                list_del(&p->list);
                kfree(p);
        }
+       tracing_selftest_running = false;
  
   out:
        mutex_unlock(&trace_types_lock);
@@@ -8568,7 -8570,7 +8570,7 @@@ static struct trace_array *trace_array_
  
        ret = event_trace_add_tracer(tr->dir, tr);
        if (ret) {
 -              tracefs_remove_recursive(tr->dir);
 +              tracefs_remove(tr->dir);
                goto out_free_tr;
        }
  
@@@ -8679,7 -8681,7 +8681,7 @@@ static int __remove_instance(struct tra
        event_trace_del_tracer(tr);
        ftrace_clear_pids(tr);
        ftrace_destroy_function_files(tr);
 -      tracefs_remove_recursive(tr->dir);
 +      tracefs_remove(tr->dir);
        free_trace_buffers(tr);
  
        for (i = 0; i < tr->nr_topts; i++) {
@@@ -9483,11 -9485,6 +9485,11 @@@ __init static int tracing_set_default_c
  {
        /* sched_clock_stable() is determined in late_initcall */
        if (!trace_boot_clock && !sched_clock_stable()) {
 +              if (security_locked_down(LOCKDOWN_TRACEFS)) {
 +                      pr_warn("Can not set tracing clock due to lockdown\n");
 +                      return -EPERM;
 +              }
 +
                printk(KERN_WARNING
                       "Unstable clock detected, switching default tracing clock to \"global\"\n"
                       "If you want to keep using the local clock, then add:\n"
@@@ -121,7 -121,6 +121,7 @@@ struct hist_field 
        struct ftrace_event_field       *field;
        unsigned long                   flags;
        hist_field_fn_t                 fn;
 +      unsigned int                    ref;
        unsigned int                    size;
        unsigned int                    offset;
        unsigned int                    is_signed;
@@@ -821,6 -820,29 +821,29 @@@ static const char *synth_field_fmt(cha
        return fmt;
  }
  
+ static void print_synth_event_num_val(struct trace_seq *s,
+                                     char *print_fmt, char *name,
+                                     int size, u64 val, char *space)
+ {
+       switch (size) {
+       case 1:
+               trace_seq_printf(s, print_fmt, name, (u8)val, space);
+               break;
+       case 2:
+               trace_seq_printf(s, print_fmt, name, (u16)val, space);
+               break;
+       case 4:
+               trace_seq_printf(s, print_fmt, name, (u32)val, space);
+               break;
+       default:
+               trace_seq_printf(s, print_fmt, name, val, space);
+               break;
+       }
+ }
  static enum print_line_t print_synth_event(struct trace_iterator *iter,
                                           int flags,
                                           struct trace_event *event)
                } else {
                        struct trace_print_flags __flags[] = {
                            __def_gfpflag_names, {-1, NULL} };
+                       char *space = (i == se->n_fields - 1 ? "" : " ");
  
-                       trace_seq_printf(s, print_fmt, se->fields[i]->name,
-                                        entry->fields[n_u64],
-                                        i == se->n_fields - 1 ? "" : " ");
+                       print_synth_event_num_val(s, print_fmt,
+                                                 se->fields[i]->name,
+                                                 se->fields[i]->size,
+                                                 entry->fields[n_u64],
+                                                 space);
  
                        if (strcmp(se->fields[i]->type, "gfp_t") == 0) {
                                trace_seq_puts(s, " (");
@@@ -1167,12 -1192,6 +1193,12 @@@ static struct synth_event *find_synth_e
        return NULL;
  }
  
 +static struct trace_event_fields synth_event_fields_array[] = {
 +      { .type = TRACE_FUNCTION_TYPE,
 +        .define_fields = synth_event_define_fields },
 +      {}
 +};
 +
  static int register_synth_event(struct synth_event *event)
  {
        struct trace_event_call *call = &event->call;
  
        INIT_LIST_HEAD(&call->class->fields);
        call->event.funcs = &synth_event_funcs;
 -      call->class->define_fields = synth_event_define_fields;
 +      call->class->fields_array = synth_event_fields_array;
  
        ret = register_trace_event(&call->event);
        if (!ret) {
@@@ -1805,6 -1824,8 +1831,8 @@@ __synth_event_trace_start(struct trace_
        int entry_size, fields_size = 0;
        int ret = 0;
  
+       memset(trace_state, '\0', sizeof(*trace_state));
        /*
         * Normal event tracing doesn't get called at all unless the
         * ENABLED bit is set (which attaches the probe thus allowing
@@@ -1885,6 -1906,11 +1913,11 @@@ int synth_event_trace(struct trace_even
                return ret;
        }
  
+       if (n_vals != state.event->n_fields) {
+               ret = -EINVAL;
+               goto out;
+       }
        va_start(args, n_vals);
        for (i = 0, n_u64 = 0; i < state.event->n_fields; i++) {
                u64 val;
                        strscpy(str_field, str_val, STR_VAR_LEN_MAX);
                        n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
                } else {
-                       state.entry->fields[n_u64] = val;
+                       struct synth_field *field = state.event->fields[i];
+                       switch (field->size) {
+                       case 1:
+                               *(u8 *)&state.entry->fields[n_u64] = (u8)val;
+                               break;
+                       case 2:
+                               *(u16 *)&state.entry->fields[n_u64] = (u16)val;
+                               break;
+                       case 4:
+                               *(u32 *)&state.entry->fields[n_u64] = (u32)val;
+                               break;
+                       default:
+                               state.entry->fields[n_u64] = val;
+                               break;
+                       }
                        n_u64++;
                }
        }
        va_end(args);
+ out:
        __synth_event_trace_end(&state);
  
        return ret;
@@@ -1942,6 -1986,11 +1993,11 @@@ int synth_event_trace_array(struct trac
                return ret;
        }
  
+       if (n_vals != state.event->n_fields) {
+               ret = -EINVAL;
+               goto out;
+       }
        for (i = 0, n_u64 = 0; i < state.event->n_fields; i++) {
                if (state.event->fields[i]->is_string) {
                        char *str_val = (char *)(long)vals[i];
                        strscpy(str_field, str_val, STR_VAR_LEN_MAX);
                        n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
                } else {
-                       state.entry->fields[n_u64] = vals[i];
+                       struct synth_field *field = state.event->fields[i];
+                       u64 val = vals[i];
+                       switch (field->size) {
+                       case 1:
+                               *(u8 *)&state.entry->fields[n_u64] = (u8)val;
+                               break;
+                       case 2:
+                               *(u16 *)&state.entry->fields[n_u64] = (u16)val;
+                               break;
+                       case 4:
+                               *(u32 *)&state.entry->fields[n_u64] = (u32)val;
+                               break;
+                       default:
+                               state.entry->fields[n_u64] = val;
+                               break;
+                       }
                        n_u64++;
                }
        }
+ out:
        __synth_event_trace_end(&state);
  
        return ret;
@@@ -1997,8 -2065,6 +2072,6 @@@ int synth_event_trace_start(struct trac
        if (!trace_state)
                return -EINVAL;
  
-       memset(trace_state, '\0', sizeof(*trace_state));
        ret = __synth_event_trace_start(file, trace_state);
        if (ret == -ENOENT)
                ret = 0; /* just disabled, not really an error */
@@@ -2069,8 -2135,25 +2142,25 @@@ static int __synth_event_add_val(const 
  
                str_field = (char *)&entry->fields[field->offset];
                strscpy(str_field, str_val, STR_VAR_LEN_MAX);
-       } else
-               entry->fields[field->offset] = val;
+       } else {
+               switch (field->size) {
+               case 1:
+                       *(u8 *)&trace_state->entry->fields[field->offset] = (u8)val;
+                       break;
+               case 2:
+                       *(u16 *)&trace_state->entry->fields[field->offset] = (u16)val;
+                       break;
+               case 4:
+                       *(u32 *)&trace_state->entry->fields[field->offset] = (u32)val;
+                       break;
+               default:
+                       trace_state->entry->fields[field->offset] = val;
+                       break;
+               }
+       }
   out:
        return ret;
  }
@@@ -3216,16 -3299,8 +3306,16 @@@ static int contains_operator(char *str
        return field_op;
  }
  
 +static void get_hist_field(struct hist_field *hist_field)
 +{
 +      hist_field->ref++;
 +}
 +
  static void __destroy_hist_field(struct hist_field *hist_field)
  {
 +      if (--hist_field->ref > 1)
 +              return;
 +
        kfree(hist_field->var.name);
        kfree(hist_field->name);
        kfree(hist_field->type);
@@@ -3267,8 -3342,6 +3357,8 @@@ static struct hist_field *create_hist_f
        if (!hist_field)
                return NULL;
  
 +      hist_field->ref = 1;
 +
        hist_field->hist_data = hist_data;
  
        if (flags & HIST_FIELD_FL_EXPR || flags & HIST_FIELD_FL_ALIAS)
@@@ -3480,17 -3553,6 +3570,17 @@@ static struct hist_field *create_var_re
  {
        unsigned long flags = HIST_FIELD_FL_VAR_REF;
        struct hist_field *ref_field;
 +      int i;
 +
 +      /* Check if the variable already exists */
 +      for (i = 0; i < hist_data->n_var_refs; i++) {
 +              ref_field = hist_data->var_refs[i];
 +              if (ref_field->var.idx == var_field->var.idx &&
 +                  ref_field->var.hist_data == var_field->hist_data) {
 +                      get_hist_field(ref_field);
 +                      return ref_field;
 +              }
 +      }
  
        ref_field = create_hist_field(var_field->hist_data, NULL, flags, NULL);
        if (ref_field) {