Merge branch 'linus' into tracing/hw-branch-tracing
authorIngo Molnar <mingo@elte.hu>
Tue, 7 Apr 2009 11:34:26 +0000 (13:34 +0200)
committerIngo Molnar <mingo@elte.hu>
Tue, 7 Apr 2009 11:34:42 +0000 (13:34 +0200)
Merge reason: update to latest tracing and ptrace APIs

Signed-off-by: Ingo Molnar <mingo@elte.hu>
1  2 
arch/x86/Kconfig.debug
arch/x86/kernel/Makefile
kernel/trace/trace.h
kernel/trace/trace_selftest.c

diff --combined arch/x86/Kconfig.debug
index dfd74abc03f820a4d23e857d01a497de5fcff1de,d8359e73317f8dfb8b929f15f555f5593469e7fd..22b752e094874209f63a97dd75670bcbb009e1d4
@@@ -72,14 -72,6 +72,6 @@@ config DEBUG_STACK_USAG
  
          This option will slow down process creation somewhat.
  
- config DEBUG_PAGEALLOC
-       bool "Debug page memory allocations"
-       depends on DEBUG_KERNEL
-       ---help---
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a large slowdown, but helps to find certain types
-         of memory corruptions.
  config DEBUG_PER_CPU_MAPS
        bool "Debug access to per_cpu maps"
        depends on DEBUG_KERNEL
@@@ -175,15 -167,6 +167,15 @@@ config IOMMU_LEA
          Add a simple leak tracer to the IOMMU code. This is useful when you
          are debugging a buggy device driver that leaks IOMMU mappings.
  
 +config X86_DS_SELFTEST
 +    bool "DS selftest"
 +    default y
 +    depends on DEBUG_KERNEL
 +    depends on X86_DS
 +      ---help---
 +        Perform Debug Store selftests at boot time.
 +        If in doubt, say "N".
 +
  config HAVE_MMIOTRACE_SUPPORT
        def_bool y
  
diff --combined arch/x86/kernel/Makefile
index a0c9e138b0083b60f361e032c117addf412eeca0,145cce75cda70dcc5f90560902eff37cc6ddd3fc..77df4d654ff94636d4a68917e7961c7966e2a444
@@@ -44,7 -44,6 +44,7 @@@ obj-y                         += process.
  obj-y                         += i387.o xsave.o
  obj-y                         += ptrace.o
  obj-$(CONFIG_X86_DS)          += ds.o
 +obj-$(CONFIG_X86_DS_SELFTEST)         += ds_selftest.o
  obj-$(CONFIG_X86_32)          += tls.o
  obj-$(CONFIG_IA32_EMULATION)  += tls.o
  obj-y                         += step.o
@@@ -67,11 -66,11 +67,11 @@@ obj-$(CONFIG_X86_MPPARSE)  += mpparse.
  obj-y                         += apic/
  obj-$(CONFIG_X86_REBOOTFIXUPS)        += reboot_fixups_32.o
  obj-$(CONFIG_DYNAMIC_FTRACE)  += ftrace.o
- obj-$(CONFIG_FUNCTION_GRAPH_TRACER)   += ftrace.o
+ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
+ obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
  obj-$(CONFIG_KEXEC)           += machine_kexec_$(BITS).o
  obj-$(CONFIG_KEXEC)           += relocate_kernel_$(BITS).o crash.o
  obj-$(CONFIG_CRASH_DUMP)      += crash_dump_$(BITS).o
- obj-$(CONFIG_X86_VSMP)                += vsmp_64.o
  obj-$(CONFIG_KPROBES)         += kprobes.o
  obj-$(CONFIG_MODULES)         += module_$(BITS).o
  obj-$(CONFIG_EFI)             += efi.o efi_$(BITS).o efi_stub_$(BITS).o
@@@ -107,7 -106,7 +107,7 @@@ obj-$(CONFIG_MICROCODE)                    += microcode.
  
  obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
  
- obj-$(CONFIG_SWIOTLB)                 += pci-swiotlb_64.o # NB rename without _64
+ obj-$(CONFIG_SWIOTLB)                 += pci-swiotlb.o
  
  ###
  # 64 bit specific files
@@@ -121,4 -120,5 +121,5 @@@ ifeq ($(CONFIG_X86_64),y
        obj-$(CONFIG_AMD_IOMMU)         += amd_iommu_init.o amd_iommu.o
  
        obj-$(CONFIG_PCI_MMCONFIG)      += mmconf-fam10h_64.o
+       obj-y                           += vsmp_64.o
  endif
diff --combined kernel/trace/trace.h
index e7fbc826f1e93391faa03cee96d84c68094b4e7a,cbc168f1e43db4e78e41a990cd5b0265cf9a96d4..9e15802cca9f5c81fb4723ac1e4b24e9a63e2a31
@@@ -123,7 -123,6 +123,6 @@@ struct userstack_entry 
  struct bprint_entry {
        struct trace_entry      ent;
        unsigned long           ip;
-       int                     depth;
        const char              *fmt;
        u32                     buf[];
  };
  struct print_entry {
        struct trace_entry      ent;
        unsigned long           ip;
-       int                     depth;
        char                    buf[];
  };
  
@@@ -184,6 -182,12 +182,12 @@@ struct trace_power 
        struct power_trace      state_data;
  };
  
+ enum kmemtrace_type_id {
+       KMEMTRACE_TYPE_KMALLOC = 0,     /* kmalloc() or kfree(). */
+       KMEMTRACE_TYPE_CACHE,           /* kmem_cache_*(). */
+       KMEMTRACE_TYPE_PAGES,           /* __get_free_pages() and friends. */
+ };
  struct kmemtrace_alloc_entry {
        struct trace_entry      ent;
        enum kmemtrace_type_id type_id;
@@@ -202,6 -206,19 +206,19 @@@ struct kmemtrace_free_entry 
        const void *ptr;
  };
  
+ struct syscall_trace_enter {
+       struct trace_entry      ent;
+       int                     nr;
+       unsigned long           args[];
+ };
+ struct syscall_trace_exit {
+       struct trace_entry      ent;
+       int                     nr;
+       unsigned long           ret;
+ };
  /*
   * trace_flag_type is an enumeration that holds different
   * states when a trace occurs. These are:
@@@ -315,6 -332,10 +332,10 @@@ extern void __ftrace_bad_type(void)
                          TRACE_KMEM_ALLOC);    \
                IF_ASSIGN(var, ent, struct kmemtrace_free_entry,        \
                          TRACE_KMEM_FREE);     \
+               IF_ASSIGN(var, ent, struct syscall_trace_enter,         \
+                         TRACE_SYSCALL_ENTER);                         \
+               IF_ASSIGN(var, ent, struct syscall_trace_exit,          \
+                         TRACE_SYSCALL_EXIT);                          \
                __ftrace_bad_type();                                    \
        } while (0)
  
@@@ -468,6 -489,8 +489,8 @@@ trace_current_buffer_lock_reserve(unsig
                                  unsigned long flags, int pc);
  void trace_current_buffer_unlock_commit(struct ring_buffer_event *event,
                                        unsigned long flags, int pc);
+ void trace_nowake_buffer_unlock_commit(struct ring_buffer_event *event,
+                                       unsigned long flags, int pc);
  
  struct trace_entry *tracing_get_trace_entry(struct trace_array *tr,
                                                struct trace_array_cpu *data);
@@@ -547,7 -570,7 +570,7 @@@ struct tracer_switch_ops 
  };
  #endif /* CONFIG_CONTEXT_SWITCH_TRACER */
  
- extern char *trace_find_cmdline(int pid);
+ extern void trace_find_cmdline(int pid, char comm[]);
  
  #ifdef CONFIG_DYNAMIC_FTRACE
  extern unsigned long ftrace_update_tot_cnt;
@@@ -576,16 -599,14 +599,16 @@@ extern int trace_selftest_startup_syspr
                                               struct trace_array *tr);
  extern int trace_selftest_startup_branch(struct tracer *trace,
                                         struct trace_array *tr);
 +extern int trace_selftest_startup_hw_branches(struct tracer *trace,
 +                                            struct trace_array *tr);
  #endif /* CONFIG_FTRACE_STARTUP_TEST */
  
  extern void *head_page(struct trace_array_cpu *data);
  extern long ns2usecs(cycle_t nsec);
  extern int
- trace_vbprintk(unsigned long ip, int depth, const char *fmt, va_list args);
+ trace_vbprintk(unsigned long ip, const char *fmt, va_list args);
  extern int
- trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args);
+ trace_vprintk(unsigned long ip, const char *fmt, va_list args);
  
  extern unsigned long trace_flags;
  
@@@ -669,6 -690,8 +692,8 @@@ enum trace_iterator_flags 
        TRACE_ITER_PRINTK_MSGONLY       = 0x10000,
        TRACE_ITER_CONTEXT_INFO         = 0x20000, /* Print pid/cpu/time */
        TRACE_ITER_LATENCY_FMT          = 0x40000,
+       TRACE_ITER_GLOBAL_CLK           = 0x80000,
+       TRACE_ITER_SLEEP_TIME           = 0x100000,
  };
  
  /*
@@@ -761,22 -784,89 +786,89 @@@ enum 
        TRACE_EVENT_TYPE_RAW            = 2,
  };
  
+ struct ftrace_event_field {
+       struct list_head        link;
+       char                    *name;
+       char                    *type;
+       int                     offset;
+       int                     size;
+ };
  struct ftrace_event_call {
-       char            *name;
-       char            *system;
-       struct dentry   *dir;
-       int             enabled;
-       int             (*regfunc)(void);
-       void            (*unregfunc)(void);
-       int             id;
-       int             (*raw_init)(void);
-       int             (*show_format)(struct trace_seq *s);
+       char                    *name;
+       char                    *system;
+       struct dentry           *dir;
+       int                     enabled;
+       int                     (*regfunc)(void);
+       void                    (*unregfunc)(void);
+       int                     id;
+       int                     (*raw_init)(void);
+       int                     (*show_format)(struct trace_seq *s);
+       int                     (*define_fields)(void);
+       struct list_head        fields;
+       struct filter_pred      **preds;
+ #ifdef CONFIG_EVENT_PROFILE
+       atomic_t        profile_count;
+       int             (*profile_enable)(struct ftrace_event_call *);
+       void            (*profile_disable)(struct ftrace_event_call *);
+ #endif
  };
  
+ struct event_subsystem {
+       struct list_head        list;
+       const char              *name;
+       struct dentry           *entry;
+       struct filter_pred      **preds;
+ };
+ #define events_for_each(event)                                                \
+       for (event = __start_ftrace_events;                             \
+            (unsigned long)event < (unsigned long)__stop_ftrace_events; \
+            event++)
+ #define MAX_FILTER_PRED 8
+ struct filter_pred;
+ typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event);
+ struct filter_pred {
+       filter_pred_fn_t fn;
+       u64 val;
+       char *str_val;
+       int str_len;
+       char *field_name;
+       int offset;
+       int not;
+       int or;
+       int compound;
+       int clear;
+ };
+ int trace_define_field(struct ftrace_event_call *call, char *type,
+                      char *name, int offset, int size);
+ extern void filter_free_pred(struct filter_pred *pred);
+ extern void filter_print_preds(struct filter_pred **preds,
+                              struct trace_seq *s);
+ extern int filter_parse(char **pbuf, struct filter_pred *pred);
+ extern int filter_add_pred(struct ftrace_event_call *call,
+                          struct filter_pred *pred);
+ extern void filter_free_preds(struct ftrace_event_call *call);
+ extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
+ extern void filter_free_subsystem_preds(struct event_subsystem *system);
+ extern int filter_add_subsystem_pred(struct event_subsystem *system,
+                                    struct filter_pred *pred);
  void event_trace_printk(unsigned long ip, const char *fmt, ...);
  extern struct ftrace_event_call __start_ftrace_events[];
  extern struct ftrace_event_call __stop_ftrace_events[];
  
+ #define for_each_event(event)                                         \
+       for (event = __start_ftrace_events;                             \
+            (unsigned long)event < (unsigned long)__stop_ftrace_events; \
+            event++)
  extern const char *__start___trace_bprintk_fmt[];
  extern const char *__stop___trace_bprintk_fmt[];
  
index b91091267067651c7e54d8136726b2b27c1dd675,08f4eb2763d141bbae33c518a4de1e15d1c3614a..499d01c44cd17b9a95e843b5b062b900185c4886
@@@ -16,7 -16,6 +16,7 @@@ static inline int trace_valid_entry(str
        case TRACE_BRANCH:
        case TRACE_GRAPH_ENT:
        case TRACE_GRAPH_RET:
 +      case TRACE_HW_BRANCHES:
                return 1;
        }
        return 0;
@@@ -189,7 -188,6 +189,7 @@@ int trace_selftest_startup_dynamic_trac
  #else
  # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })
  #endif /* CONFIG_DYNAMIC_FTRACE */
 +
  /*
   * Simple verification test of ftrace function tracer.
   * Enable ftrace, sleep 1/10 second, and then read the trace
@@@ -250,6 -248,28 +250,28 @@@ trace_selftest_startup_function(struct 
  
  
  #ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ /* Maximum number of functions to trace before diagnosing a hang */
+ #define GRAPH_MAX_FUNC_TEST   100000000
+ static void __ftrace_dump(bool disable_tracing);
+ static unsigned int graph_hang_thresh;
+ /* Wrap the real function entry probe to avoid possible hanging */
+ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace)
+ {
+       /* This is harmlessly racy, we want to approximately detect a hang */
+       if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) {
+               ftrace_graph_stop();
+               printk(KERN_WARNING "BUG: Function graph tracer hang!\n");
+               if (ftrace_dump_on_oops)
+                       __ftrace_dump(false);
+               return 0;
+       }
+       return trace_graph_entry(trace);
+ }
  /*
   * Pretty much the same than for the function tracer from which the selftest
   * has been borrowed.
@@@ -261,15 -281,29 +283,29 @@@ trace_selftest_startup_function_graph(s
        int ret;
        unsigned long count;
  
-       ret = tracer_init(trace, tr);
+       /*
+        * Simulate the init() callback but we attach a watchdog callback
+        * to detect and recover from possible hangs
+        */
+       tracing_reset_online_cpus(tr);
+       ret = register_ftrace_graph(&trace_graph_return,
+                                   &trace_graph_entry_watchdog);
        if (ret) {
                warn_failed_init_tracer(trace, ret);
                goto out;
        }
+       tracing_start_cmdline_record();
  
        /* Sleep for a 1/10 of a second */
        msleep(100);
  
+       /* Have we just recovered from a hang? */
+       if (graph_hang_thresh > GRAPH_MAX_FUNC_TEST) {
+               tracing_selftest_disabled = true;
+               ret = -1;
+               goto out;
+       }
        tracing_stop();
  
        /* check the trace buffer */
@@@ -317,6 -351,14 +353,14 @@@ trace_selftest_startup_irqsoff(struct t
        local_irq_disable();
        udelay(100);
        local_irq_enable();
+       /*
+        * Stop the tracer to avoid a warning subsequent
+        * to buffer flipping failure because tracing_stop()
+        * disables the tr and max buffers, making flipping impossible
+        * in case of parallels max irqs off latencies.
+        */
+       trace->stop(tr);
        /* stop the tracing. */
        tracing_stop();
        /* check both trace buffers */
@@@ -371,6 -413,14 +415,14 @@@ trace_selftest_startup_preemptoff(struc
        preempt_disable();
        udelay(100);
        preempt_enable();
+       /*
+        * Stop the tracer to avoid a warning subsequent
+        * to buffer flipping failure because tracing_stop()
+        * disables the tr and max buffers, making flipping impossible
+        * in case of parallels max preempt off latencies.
+        */
+       trace->stop(tr);
        /* stop the tracing. */
        tracing_stop();
        /* check both trace buffers */
@@@ -416,7 -466,7 +468,7 @@@ trace_selftest_startup_preemptirqsoff(s
        ret = tracer_init(trace, tr);
        if (ret) {
                warn_failed_init_tracer(trace, ret);
-               goto out;
+               goto out_no_start;
        }
  
        /* reset the max latency */
        /* reverse the order of preempt vs irqs */
        local_irq_enable();
  
+       /*
+        * Stop the tracer to avoid a warning subsequent
+        * to buffer flipping failure because tracing_stop()
+        * disables the tr and max buffers, making flipping impossible
+        * in case of parallels max irqs/preempt off latencies.
+        */
+       trace->stop(tr);
        /* stop the tracing. */
        tracing_stop();
        /* check both trace buffers */
        ret = trace_test_buffer(tr, NULL);
-       if (ret) {
-               tracing_start();
+       if (ret)
                goto out;
-       }
  
        ret = trace_test_buffer(&max_tr, &count);
-       if (ret) {
-               tracing_start();
+       if (ret)
                goto out;
-       }
  
        if (!ret && !count) {
                printk(KERN_CONT ".. no entries found ..");
                ret = -1;
-               tracing_start();
                goto out;
        }
  
        /* do the test by disabling interrupts first this time */
        tracing_max_latency = 0;
        tracing_start();
+       trace->start(tr);
        preempt_disable();
        local_irq_disable();
        udelay(100);
        /* reverse the order of preempt vs irqs */
        local_irq_enable();
  
+       trace->stop(tr);
        /* stop the tracing. */
        tracing_stop();
        /* check both trace buffers */
                goto out;
        }
  
-  out:
-       trace->reset(tr);
+ out:
        tracing_start();
+ out_no_start:
+       trace->reset(tr);
        tracing_max_latency = save_max;
  
        return ret;
@@@ -693,55 -749,3 +751,55 @@@ trace_selftest_startup_branch(struct tr
        return ret;
  }
  #endif /* CONFIG_BRANCH_TRACER */
 +
 +#ifdef CONFIG_HW_BRANCH_TRACER
 +int
 +trace_selftest_startup_hw_branches(struct tracer *trace,
 +                                 struct trace_array *tr)
 +{
 +      struct trace_iterator iter;
 +      struct tracer tracer;
 +      unsigned long count;
 +      int ret;
 +
 +      if (!trace->open) {
 +              printk(KERN_CONT "missing open function...");
 +              return -1;
 +      }
 +
 +      ret = tracer_init(trace, tr);
 +      if (ret) {
 +              warn_failed_init_tracer(trace, ret);
 +              return ret;
 +      }
 +
 +      /*
 +       * The hw-branch tracer needs to collect the trace from the various
 +       * cpu trace buffers - before tracing is stopped.
 +       */
 +      memset(&iter, 0, sizeof(iter));
 +      memcpy(&tracer, trace, sizeof(tracer));
 +
 +      iter.trace = &tracer;
 +      iter.tr = tr;
 +      iter.pos = -1;
 +      mutex_init(&iter.mutex);
 +
 +      trace->open(&iter);
 +
 +      mutex_destroy(&iter.mutex);
 +
 +      tracing_stop();
 +
 +      ret = trace_test_buffer(tr, &count);
 +      trace->reset(tr);
 +      tracing_start();
 +
 +      if (!ret && !count) {
 +              printk(KERN_CONT "no entries found..");
 +              ret = -1;
 +      }
 +
 +      return ret;
 +}
 +#endif /* CONFIG_HW_BRANCH_TRACER */