Merge tag 'trace-3.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Dec 2014 20:53:59 +0000 (12:53 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Dec 2014 20:53:59 +0000 (12:53 -0800)
Pull tracing updates from Steven Rostedt:
 "As the merge window is still open, and this code was not as complex as
  I thought it might be.  I'm pushing this in now.

  This will allow Thomas to debug his irq work for 3.20.

  This adds two new features:

  1) Allow traceopoints to be enabled right after mm_init().

     By passing in the trace_event= kernel command line parameter,
     tracepoints can be enabled at boot up.  For debugging things like
     the initialization of interrupts, it is needed to have tracepoints
     enabled very early.  People have asked about this before and this
     has been on my todo list.  As it can be helpful for Thomas to debug
     his upcoming 3.20 IRQ work, I'm pushing this now.  This way he can
     add tracepoints into the IRQ set up and have users enable them when
     things go wrong.

  2) Have the tracepoints printed via printk() (the console) when they
     are triggered.

     If the irq code locks up or reboots the box, having the tracepoint
     output go into the kernel ring buffer is useless for debugging.
     But being able to add the tp_printk kernel command line option
     along with the trace_event= option will have these tracepoints
     printed as they occur, and that can be really useful for debugging
     early lock up or reboot problems.

  This code is not that intrusive and it passed all my tests.  Thomas
  tried them out too and it works for his needs.

Link: http://lkml.kernel.org/r/20141214201609.126831471@goodmis.org"
* tag 'trace-3.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  tracing: Add tp_printk cmdline to have tracepoints go to printk()
  tracing: Move enabling tracepoints to just after rcu_init()

1  2 
Documentation/kernel-parameters.txt
init/main.c
kernel/sysctl.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/trace/trace_syscalls.c

@@@ -829,15 -829,6 +829,15 @@@ bytes respectively. Such letter suffixe
                        CONFIG_DEBUG_PAGEALLOC, hence this option will not help
                        tracking down these problems.
  
 +      debug_pagealloc=
 +                      [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this
 +                      parameter enables the feature at boot time. In
 +                      default, it is disabled. We can avoid allocating huge
 +                      chunk of memory for debug pagealloc if we don't enable
 +                      it at boot time and the system will work mostly same
 +                      with the kernel built without CONFIG_DEBUG_PAGEALLOC.
 +                      on: enable the feature
 +
        debugpat        [X86] Enable PAT debugging
  
        decnet.addr=    [HW,NET]
                        Format: {"off" | "on" | "skip[mbr]"}
  
        efi=            [EFI]
 -                      Format: { "old_map" }
 +                      Format: { "old_map", "nochunk", "noruntime" }
                        old_map [X86-64]: switch to the old ioremap-based EFI
                        runtime services mapping. 32-bit still uses this one by
                        default.
 +                      nochunk: disable reading files in "chunks" in the EFI
 +                      boot stub, as chunking can cause problems with some
 +                      firmware implementations.
 +                      noruntime : disable EFI runtime services support
  
        efi_no_storage_paranoia [EFI; X86]
                        Using this parameter you can use more than 50% of
                        multiple times interleaved with hugepages= to reserve
                        huge pages of different sizes. Valid pages sizes on
                        x86-64 are 2M (when the CPU supports "pse") and 1G
 -                      (when the CPU supports the "pdpe1gb" cpuinfo flag)
 -                      Note that 1GB pages can only be allocated at boot time
 -                      using hugepages= and not freed afterwards.
 +                      (when the CPU supports the "pdpe1gb" cpuinfo flag).
  
        hvc_iucv=       [S390] Number of z/VM IUCV hypervisor console (HVC)
                               terminal devices. Valid values: 0..8
        i8042.noloop    [HW] Disable the AUX Loopback command while probing
                             for the AUX port
        i8042.nomux     [HW] Don't check presence of an active multiplexing
 -                           controller. Default: true.
 +                           controller
        i8042.nopnp     [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
                             controllers
        i8042.notimeout [HW] Ignore timeout condition signalled by controller
                        .cdrom .chs .ignore_cable are additional options
                        See Documentation/ide/ide.txt.
  
 +      ide-generic.probe-mask= [HW] (E)IDE subsystem
 +                      Format: <int>
 +                      Probe mask for legacy ISA IDE ports.  Depending on
 +                      platform up to 6 ports are supported, enabled by
 +                      setting corresponding bits in the mask to 1.  The
 +                      default value is 0x0, which has a special meaning.
 +                      On systems that have PCI, it triggers scanning the
 +                      PCI bus for the first and the second port, which
 +                      are then probed.  On systems without PCI the value
 +                      of 0x0 enables probing the two first ports as if it
 +                      was 0x3.
 +
        ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
                        Claim all unknown PCI IDE storage controllers.
  
                        Formats: { "ima" | "ima-ng" }
                        Default: "ima-ng"
  
 +      ima_template_fmt=
 +                      [IMA] Define a custom template format.
 +                      Format: { "field1|...|fieldN" }
 +
        ima.ahash_minsize= [IMA] Minimum file size for asynchronous hash usage
                        Format: <min_file_size>
                        Set the minimal file size for using asynchronous hash.
                       disable
                         Do not enable intel_pstate as the default
                         scaling driver for the supported processors
 +                     no_hwp
 +                       Do not enable hardware P state control (HWP)
 +                       if available.
  
        intremap=       [X86-64, Intel-IOMMU]
                        on      enable Interrupt Remapping (default)
        kmemleak=       [KNL] Boot-time kmemleak enable/disable
                        Valid arguments: on, off
                        Default: on
 +                      Built with CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y,
 +                      the default is off.
  
        kmemcheck=      [X86] Boot-time kmemcheck enable/disable/one-shot mode
                        Valid arguments: 0, 1, 2
  
        nodsp           [SH] Disable hardware DSP at boot time.
  
 -      noefi           [X86] Disable EFI runtime services support.
 +      noefi           Disable EFI runtime services support.
  
        noexec          [IA-64]
  
        OSS             [HW,OSS]
                        See Documentation/sound/oss/oss-parameters.txt
  
 +      page_owner=     [KNL] Boot-time page_owner enabling option.
 +                      Storage of the information about who allocated
 +                      each page is disabled in default. With this switch,
 +                      we can turn it on.
 +                      on: enable the feature
 +
        panic=          [KNL] Kernel behaviour on panic: delay <timeout>
                        timeout > 0: seconds before rebooting
                        timeout = 0: wait forever
                        timeout < 0: reboot immediately
                        Format: <timeout>
  
 +      panic_on_warn   panic() instead of WARN().  Useful to cause kdump
 +                      on a WARN().
 +
        crash_kexec_post_notifiers
                        Run kdump after running panic-notifiers and dumping
                        kmsg. This only for the users who doubt kdump always
                        quiescent states.  Units are jiffies, minimum
                        value is one, and maximum value is HZ.
  
 +      rcutree.kthread_prio=    [KNL,BOOT]
 +                      Set the SCHED_FIFO priority of the RCU
 +                      per-CPU kthreads (rcuc/N). This value is also
 +                      used for the priority of the RCU boost threads
 +                      (rcub/N). Valid values are 1-99 and the default
 +                      is 1 (the least-favored priority).
 +
        rcutree.rcu_nocb_leader_stride= [KNL]
                        Set the number of NOCB kthread groups, which
                        defaults to the square root of the number of
                        messages.  Disable with a value less than or equal
                        to zero.
  
 +      rcupdate.rcu_self_test= [KNL]
 +                      Run the RCU early boot self tests
 +
 +      rcupdate.rcu_self_test_bh= [KNL]
 +                      Run the RCU bh early boot self tests
 +
 +      rcupdate.rcu_self_test_sched= [KNL]
 +                      Run the RCU sched early boot self tests
 +
        rdinit=         [KNL]
                        Format: <full_path>
                        Run specified binary instead of /init from the ramdisk,
                        neutralize any effect of /proc/sys/kernel/sysrq.
                        Useful for debugging.
  
 +      tcpmhash_entries= [KNL,NET]
 +                      Set the number of tcp_metrics_hash slots.
 +                      Default value is 8192 or 16384 depending on total
 +                      ram pages. This is used to specify the TCP metrics
 +                      cache size. See Documentation/networking/ip-sysctl.txt
 +                      "tcp_no_metrics_save" section for more details.
 +
        tdfx=           [HW,DRM]
  
        test_suspend=   [SUSPEND][,N]
                        e.g. base its process migration decisions on it.
                        Default is on.
  
 +      topology_updates= [KNL, PPC, NUMA]
 +                      Format: {off}
 +                      Specify if the kernel should ignore (off)
 +                      topology updates sent by the hypervisor to this
 +                      LPAR.
 +
        tp720=          [HW,PS2]
  
        tpm_suspend_pcr=[HW,TPM]
                        See also Documentation/trace/ftrace.txt "trace options"
                        section.
  
+       tp_printk[FTRACE]
+                       Have the tracepoints sent to printk as well as the
+                       tracing ring buffer. This is useful for early boot up
+                       where the system hangs or reboots and does not give the
+                       option for reading the tracing buffer or performing a
+                       ftrace_dump_on_oops.
+                       To turn off having tracepoints sent to printk,
+                        echo 0 > /proc/sys/kernel/tracepoint_printk
+                       Note, echoing 1 into this file without the
+                       tracepoint_printk kernel cmdline option has no effect.
+                       ** CAUTION **
+                       Having tracepoints sent to printk() and activating high
+                       frequency tracepoints such as irq or sched, can cause
+                       the system to live lock.
        traceoff_on_warning
                        [FTRACE] enable this option to disable tracing when a
                        warning is hit. This turns off "tracing_on". Tracing can
  
        usb-storage.delay_use=
                        [UMS] The delay in seconds before a new device is
 -                      scanned for Logical Units (default 5).
 +                      scanned for Logical Units (default 1).
  
        usb-storage.quirks=
                        [UMS] A list of quirks entries to supplement or
diff --combined init/main.c
@@@ -51,7 -51,7 +51,7 @@@
  #include <linux/mempolicy.h>
  #include <linux/key.h>
  #include <linux/buffer_head.h>
 -#include <linux/page_cgroup.h>
 +#include <linux/page_ext.h>
  #include <linux/debug_locks.h>
  #include <linux/debugobjects.h>
  #include <linux/lockdep.h>
@@@ -78,7 -78,6 +78,7 @@@
  #include <linux/context_tracking.h>
  #include <linux/random.h>
  #include <linux/list.h>
 +#include <linux/integrity.h>
  
  #include <asm/io.h>
  #include <asm/bugs.h>
@@@ -487,10 -486,10 +487,10 @@@ void __init __weak thread_info_cache_in
  static void __init mm_init(void)
  {
        /*
 -       * page_cgroup requires contiguous pages,
 +       * page_ext requires contiguous pages,
         * bigger than MAX_ORDER unless SPARSEMEM.
         */
 -      page_cgroup_init_flatmem();
 +      page_ext_init_flatmem();
        mem_init();
        kmem_cache_init();
        percpu_init_late();
@@@ -545,7 -544,7 +545,7 @@@ asmlinkage __visible void __init start_
                                  static_command_line, __start___param,
                                  __stop___param - __start___param,
                                  -1, -1, &unknown_bootoption);
 -      if (after_dashes)
 +      if (!IS_ERR_OR_NULL(after_dashes))
                parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
                           set_init_arg);
  
                local_irq_disable();
        idr_init_cache();
        rcu_init();
+       /* trace_printk() and trace points may be used after this */
+       trace_init();
        context_tracking_init();
        radix_tree_init();
        /* init some links before init_ISA_irqs() */
                initrd_start = 0;
        }
  #endif
 -      page_cgroup_init();
 +      page_ext_init();
        debug_objects_mem_init();
        kmemleak_init();
        setup_per_cpu_pageset();
@@@ -960,13 -963,8 +964,13 @@@ static int __ref kernel_init(void *unus
                ret = run_init_process(execute_command);
                if (!ret)
                        return 0;
 +#ifndef CONFIG_INIT_FALLBACK
 +              panic("Requested init %s failed (error %d).",
 +                    execute_command, ret);
 +#else
                pr_err("Failed to execute %s (error %d).  Attempting defaults...\n",
 -                      execute_command, ret);
 +                     execute_command, ret);
 +#endif
        }
        if (!try_to_run_init_process("/sbin/init") ||
            !try_to_run_init_process("/etc/init") ||
@@@ -1032,11 -1030,8 +1036,11 @@@ static noinline void __init kernel_init
         * Ok, we have completed the initial bootup, and
         * we're essentially up and running. Get rid of the
         * initmem segments and start the user-mode stuff..
 +       *
 +       * rootfs is available now, try loading the public keys
 +       * and default modules
         */
  
 -      /* rootfs is available now, try loading default modules */
 +      integrity_load_keys();
        load_default_modules();
  }
diff --combined kernel/sysctl.c
@@@ -387,8 -387,7 +387,8 @@@ static struct ctl_table kern_table[] = 
                .data           = &sysctl_numa_balancing_scan_size,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
 -              .proc_handler   = proc_dointvec,
 +              .proc_handler   = proc_dointvec_minmax,
 +              .extra1         = &one,
        },
        {
                .procname       = "numa_balancing",
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+       {
+               .procname       = "tracepoint_printk",
+               .data           = &tracepoint_printk,
+               .maxlen         = sizeof(tracepoint_printk),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
  #endif
  #ifdef CONFIG_KEXEC
        {
                .proc_handler   = proc_dointvec,
        },
  #endif
 +      {
 +              .procname       = "panic_on_warn",
 +              .data           = &panic_on_warn,
 +              .maxlen         = sizeof(int),
 +              .mode           = 0644,
 +              .proc_handler   = proc_dointvec_minmax,
 +              .extra1         = &zero,
 +              .extra2         = &one,
 +      },
        { }
  };
  
diff --combined kernel/trace/trace.c
@@@ -63,6 -63,10 +63,10 @@@ static bool __read_mostly tracing_selft
   */
  bool __read_mostly tracing_selftest_disabled;
  
+ /* Pipe tracepoints to printk */
+ struct trace_iterator *tracepoint_print_iter;
+ int tracepoint_printk;
  /* For tracers that don't implement custom flags */
  static struct tracer_opt dummy_tracer_opt[] = {
        { }
@@@ -193,6 -197,13 +197,13 @@@ static int __init set_trace_boot_clock(
  }
  __setup("trace_clock=", set_trace_boot_clock);
  
+ static int __init set_tracepoint_printk(char *str)
+ {
+       if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0))
+               tracepoint_printk = 1;
+       return 1;
+ }
+ __setup("tp_printk", set_tracepoint_printk);
  
  unsigned long long ns2usecs(cycle_t nsec)
  {
@@@ -939,20 -950,19 +950,20 @@@ out
        return ret;
  }
  
 +/* TODO add a seq_buf_to_buffer() */
  static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)
  {
        int len;
  
 -      if (s->len <= s->readpos)
 +      if (trace_seq_used(s) <= s->seq.readpos)
                return -EBUSY;
  
 -      len = s->len - s->readpos;
 +      len = trace_seq_used(s) - s->seq.readpos;
        if (cnt > len)
                cnt = len;
 -      memcpy(buf, s->buffer + s->readpos, cnt);
 +      memcpy(buf, s->buffer + s->seq.readpos, cnt);
  
 -      s->readpos += cnt;
 +      s->seq.readpos += cnt;
        return cnt;
  }
  
@@@ -1078,14 -1088,13 +1089,14 @@@ update_max_tr_single(struct trace_arra
  }
  #endif /* CONFIG_TRACER_MAX_TRACE */
  
 -static int wait_on_pipe(struct trace_iterator *iter)
 +static int wait_on_pipe(struct trace_iterator *iter, bool full)
  {
        /* Iterators are static, they should be filled or empty */
        if (trace_buffer_iter(iter, iter->cpu_file))
                return 0;
  
 -      return ring_buffer_wait(iter->trace_buffer->buffer, iter->cpu_file);
 +      return ring_buffer_wait(iter->trace_buffer->buffer, iter->cpu_file,
 +                              full);
  }
  
  #ifdef CONFIG_FTRACE_STARTUP_TEST
@@@ -2031,7 -2040,7 +2042,7 @@@ void trace_printk_init_buffers(void
        pr_warning("** trace_printk() being used. Allocating extra memory.  **\n");
        pr_warning("**                                                      **\n");
        pr_warning("** This means that this is a DEBUG kernel and it is     **\n");
 -      pr_warning("** unsafe for produciton use.                           **\n");
 +      pr_warning("** unsafe for production use.                           **\n");
        pr_warning("**                                                      **\n");
        pr_warning("** If you see this message and you are not debugging    **\n");
        pr_warning("** the kernel, report this immediately to your vendor!  **\n");
@@@ -4314,8 -4323,6 +4325,8 @@@ static int tracing_open_pipe(struct ino
                goto out;
        }
  
 +      trace_seq_init(&iter->seq);
 +
        /*
         * We make a copy of the current tracer to avoid concurrent
         * changes on it while we are reading.
@@@ -4437,12 -4444,15 +4448,12 @@@ static int tracing_wait_pipe(struct fil
  
                mutex_unlock(&iter->mutex);
  
 -              ret = wait_on_pipe(iter);
 +              ret = wait_on_pipe(iter, false);
  
                mutex_lock(&iter->mutex);
  
                if (ret)
                        return ret;
 -
 -              if (signal_pending(current))
 -                      return -EINTR;
        }
  
        return 1;
@@@ -4509,18 -4519,18 +4520,18 @@@ waitagain
        trace_access_lock(iter->cpu_file);
        while (trace_find_next_entry_inc(iter) != NULL) {
                enum print_line_t ret;
 -              int len = iter->seq.len;
 +              int save_len = iter->seq.seq.len;
  
                ret = print_trace_line(iter);
                if (ret == TRACE_TYPE_PARTIAL_LINE) {
                        /* don't print partial lines */
 -                      iter->seq.len = len;
 +                      iter->seq.seq.len = save_len;
                        break;
                }
                if (ret != TRACE_TYPE_NO_CONSUME)
                        trace_consume(iter);
  
 -              if (iter->seq.len >= cnt)
 +              if (trace_seq_used(&iter->seq) >= cnt)
                        break;
  
                /*
  
        /* Now copy what we have to the user */
        sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
 -      if (iter->seq.readpos >= iter->seq.len)
 +      if (iter->seq.seq.readpos >= trace_seq_used(&iter->seq))
                trace_seq_init(&iter->seq);
  
        /*
@@@ -4570,33 -4580,20 +4581,33 @@@ static size_
  tracing_fill_pipe_page(size_t rem, struct trace_iterator *iter)
  {
        size_t count;
 +      int save_len;
        int ret;
  
        /* Seq buffer is page-sized, exactly what we need. */
        for (;;) {
 -              count = iter->seq.len;
 +              save_len = iter->seq.seq.len;
                ret = print_trace_line(iter);
 -              count = iter->seq.len - count;
 -              if (rem < count) {
 -                      rem = 0;
 -                      iter->seq.len -= count;
 +
 +              if (trace_seq_has_overflowed(&iter->seq)) {
 +                      iter->seq.seq.len = save_len;
                        break;
                }
 +
 +              /*
 +               * This should not be hit, because it should only
 +               * be set if the iter->seq overflowed. But check it
 +               * anyway to be safe.
 +               */
                if (ret == TRACE_TYPE_PARTIAL_LINE) {
 -                      iter->seq.len -= count;
 +                      iter->seq.seq.len = save_len;
 +                      break;
 +              }
 +
 +              count = trace_seq_used(&iter->seq) - save_len;
 +              if (rem < count) {
 +                      rem = 0;
 +                      iter->seq.seq.len = save_len;
                        break;
                }
  
@@@ -4677,13 -4674,13 +4688,13 @@@ static ssize_t tracing_splice_read_pipe
                /* Copy the data into the page, so we can start over. */
                ret = trace_seq_to_buffer(&iter->seq,
                                          page_address(spd.pages[i]),
 -                                        iter->seq.len);
 +                                        trace_seq_used(&iter->seq));
                if (ret < 0) {
                        __free_page(spd.pages[i]);
                        break;
                }
                spd.partial[i].offset = 0;
 -              spd.partial[i].len = iter->seq.len;
 +              spd.partial[i].len = trace_seq_used(&iter->seq);
  
                trace_seq_init(&iter->seq);
        }
@@@ -5385,12 -5382,16 +5396,12 @@@ tracing_buffers_read(struct file *filp
                                goto out_unlock;
                        }
                        mutex_unlock(&trace_types_lock);
 -                      ret = wait_on_pipe(iter);
 +                      ret = wait_on_pipe(iter, false);
                        mutex_lock(&trace_types_lock);
                        if (ret) {
                                size = ret;
                                goto out_unlock;
                        }
 -                      if (signal_pending(current)) {
 -                              size = -EINTR;
 -                              goto out_unlock;
 -                      }
                        goto again;
                }
                size = 0;
@@@ -5509,7 -5510,7 +5520,7 @@@ tracing_buffers_splice_read(struct fil
        };
        struct buffer_ref *ref;
        int entries, size, i;
 -      ssize_t ret;
 +      ssize_t ret = 0;
  
        mutex_lock(&trace_types_lock);
  
                int r;
  
                ref = kzalloc(sizeof(*ref), GFP_KERNEL);
 -              if (!ref)
 +              if (!ref) {
 +                      ret = -ENOMEM;
                        break;
 +              }
  
                ref->ref = 1;
                ref->buffer = iter->trace_buffer->buffer;
                ref->page = ring_buffer_alloc_read_page(ref->buffer, iter->cpu_file);
                if (!ref->page) {
 +                      ret = -ENOMEM;
                        kfree(ref);
                        break;
                }
  
        /* did we read anything? */
        if (!spd.nr_pages) {
 +              if (ret)
 +                      goto out;
 +
                if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK)) {
                        ret = -EAGAIN;
                        goto out;
                }
                mutex_unlock(&trace_types_lock);
 -              ret = wait_on_pipe(iter);
 +              ret = wait_on_pipe(iter, true);
                mutex_lock(&trace_types_lock);
                if (ret)
                        goto out;
 -              if (signal_pending(current)) {
 -                      ret = -EINTR;
 -                      goto out;
 -              }
 +
                goto again;
        }
  
@@@ -5683,8 -5681,7 +5694,8 @@@ tracing_stats_read(struct file *filp, c
        cnt = ring_buffer_read_events_cpu(trace_buf->buffer, cpu);
        trace_seq_printf(s, "read events: %ld\n", cnt);
  
 -      count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
 +      count = simple_read_from_buffer(ubuf, count, ppos,
 +                                      s->buffer, trace_seq_used(s));
  
        kfree(s);
  
@@@ -6433,7 -6430,7 +6444,7 @@@ static int instance_mkdir (struct inod
        int ret;
  
        /* Paranoid: Make sure the parent is the "instances" directory */
 -      parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
 +      parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
        if (WARN_ON_ONCE(parent != trace_instance_dir))
                return -ENOENT;
  
@@@ -6460,7 -6457,7 +6471,7 @@@ static int instance_rmdir(struct inode 
        int ret;
  
        /* Paranoid: Make sure the parent is the "instances" directory */
 -      parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
 +      parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
        if (WARN_ON_ONCE(parent != trace_instance_dir))
                return -ENOENT;
  
  trace_printk_seq(struct trace_seq *s)
  {
        /* Probably should print a warning here. */
 -      if (s->len >= TRACE_MAX_PRINT)
 -              s->len = TRACE_MAX_PRINT;
 +      if (s->seq.len >= TRACE_MAX_PRINT)
 +              s->seq.len = TRACE_MAX_PRINT;
 +
 +      /*
 +       * More paranoid code. Although the buffer size is set to
 +       * PAGE_SIZE, and TRACE_MAX_PRINT is 1000, this is just
 +       * an extra layer of protection.
 +       */
 +      if (WARN_ON_ONCE(s->seq.len >= s->seq.size))
 +              s->seq.len = s->seq.size - 1;
  
        /* should be zero ended, but we are paranoid. */
 -      s->buffer[s->len] = 0;
 +      s->buffer[s->seq.len] = 0;
  
        printk(KERN_TRACE "%s", s->buffer);
  
        return ret;
  }
  
+ void __init trace_init(void)
+ {
+       if (tracepoint_printk) {
+               tracepoint_print_iter =
+                       kmalloc(sizeof(*tracepoint_print_iter), GFP_KERNEL);
+               if (WARN_ON(!tracepoint_print_iter))
+                       tracepoint_printk = 0;
+       }
+       tracer_alloc_buffers();
+       init_ftrace_syscalls();
+       trace_event_init();     
+ }
  __init static int clear_boot_tracer(void)
  {
        /*
        return 0;
  }
  
- early_initcall(tracer_alloc_buffers);
  fs_initcall(tracer_init_debugfs);
  late_initcall(clear_boot_tracer);
@@@ -212,8 -212,40 +212,40 @@@ void *ftrace_event_buffer_reserve(struc
  }
  EXPORT_SYMBOL_GPL(ftrace_event_buffer_reserve);
  
+ static DEFINE_SPINLOCK(tracepoint_iter_lock);
+ static void output_printk(struct ftrace_event_buffer *fbuffer)
+ {
+       struct ftrace_event_call *event_call;
+       struct trace_event *event;
+       unsigned long flags;
+       struct trace_iterator *iter = tracepoint_print_iter;
+       if (!iter)
+               return;
+       event_call = fbuffer->ftrace_file->event_call;
+       if (!event_call || !event_call->event.funcs ||
+           !event_call->event.funcs->trace)
+               return;
+       event = &fbuffer->ftrace_file->event_call->event;
+       spin_lock_irqsave(&tracepoint_iter_lock, flags);
+       trace_seq_init(&iter->seq);
+       iter->ent = fbuffer->entry;
+       event_call->event.funcs->trace(iter, 0, event);
+       trace_seq_putc(&iter->seq, 0);
+       printk("%s", iter->seq.buffer);
+       spin_unlock_irqrestore(&tracepoint_iter_lock, flags);
+ }
  void ftrace_event_buffer_commit(struct ftrace_event_buffer *fbuffer)
  {
+       if (tracepoint_printk)
+               output_printk(fbuffer);
        event_trigger_unlock_commit(fbuffer->ftrace_file, fbuffer->buffer,
                                    fbuffer->event, fbuffer->entry,
                                    fbuffer->flags, fbuffer->pc);
@@@ -461,7 -493,7 +493,7 @@@ static void remove_event_file_dir(struc
  
        if (dir) {
                spin_lock(&dir->d_lock);        /* probably unneeded */
 -              list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
 +              list_for_each_entry(child, &dir->d_subdirs, d_child) {
                        if (child->d_inode)     /* probably unneeded */
                                child->d_inode->i_private = NULL;
                }
@@@ -1044,8 -1076,7 +1076,8 @@@ event_filter_read(struct file *filp, ch
        mutex_unlock(&event_mutex);
  
        if (file)
 -              r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
 +              r = simple_read_from_buffer(ubuf, cnt, ppos,
 +                                          s->buffer, trace_seq_used(s));
  
        kfree(s);
  
@@@ -1211,8 -1242,7 +1243,8 @@@ subsystem_filter_read(struct file *filp
        trace_seq_init(s);
  
        print_subsystem_event_filter(system, s);
 -      r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
 +      r = simple_read_from_buffer(ubuf, cnt, ppos,
 +                                  s->buffer, trace_seq_used(s));
  
        kfree(s);
  
@@@ -1267,8 -1297,7 +1299,8 @@@ show_header(struct file *filp, char __u
        trace_seq_init(s);
  
        func(s);
 -      r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
 +      r = simple_read_from_buffer(ubuf, cnt, ppos,
 +                                  s->buffer, trace_seq_used(s));
  
        kfree(s);
  
@@@ -2480,8 -2509,14 +2512,14 @@@ static __init int event_trace_init(void
  #endif
        return 0;
  }
- early_initcall(event_trace_memsetup);
- core_initcall(event_trace_enable);
+ void __init trace_event_init(void)
+ {
+       event_trace_memsetup();
+       init_ftrace_syscalls();
+       event_trace_enable();
+ }
  fs_initcall(event_trace_init);
  
  #ifdef CONFIG_FTRACE_STARTUP_TEST
@@@ -304,7 -304,7 +304,7 @@@ static void ftrace_syscall_enter(void *
        int size;
  
        syscall_nr = trace_get_syscall_nr(current, regs);
 -      if (syscall_nr < 0)
 +      if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
                return;
  
        /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE) */
@@@ -351,7 -351,7 +351,7 @@@ static void ftrace_syscall_exit(void *d
        int syscall_nr;
  
        syscall_nr = trace_get_syscall_nr(current, regs);
 -      if (syscall_nr < 0)
 +      if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
                return;
  
        /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE()) */
@@@ -514,7 -514,7 +514,7 @@@ unsigned long __init __weak arch_syscal
        return (unsigned long)sys_call_table[nr];
  }
  
static int __init init_ftrace_syscalls(void)
void __init init_ftrace_syscalls(void)
  {
        struct syscall_metadata *meta;
        unsigned long addr;
                                    GFP_KERNEL);
        if (!syscalls_metadata) {
                WARN_ON(1);
-               return -ENOMEM;
+               return;
        }
  
        for (i = 0; i < NR_syscalls; i++) {
                meta->syscall_nr = i;
                syscalls_metadata[i] = meta;
        }
-       return 0;
  }
- early_initcall(init_ftrace_syscalls);
  
  #ifdef CONFIG_PERF_EVENTS
  
@@@ -558,7 -555,7 +555,7 @@@ static void perf_syscall_enter(void *ig
        int size;
  
        syscall_nr = trace_get_syscall_nr(current, regs);
 -      if (syscall_nr < 0)
 +      if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
                return;
        if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
                return;
@@@ -632,7 -629,7 +629,7 @@@ static void perf_syscall_exit(void *ign
        int size;
  
        syscall_nr = trace_get_syscall_nr(current, regs);
 -      if (syscall_nr < 0)
 +      if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
                return;
        if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
                return;