]> Pileus Git - ~andy/linux/blobdiff - kernel/trace/trace.h
tracing: Use direct field, type and system names
[~andy/linux] / kernel / trace / trace.h
index c75d7988902caa5b7ce38d3cdad888d9ade9f105..e420f2a230de323dae5732401a68699bb13129f0 100644 (file)
 #include <linux/trace_seq.h>
 #include <linux/ftrace_event.h>
 
+#ifdef CONFIG_FTRACE_SYSCALLS
+#include <asm/unistd.h>                /* For NR_SYSCALLS           */
+#include <asm/syscall.h>       /* some archs define it here */
+#endif
+
 enum trace_type {
        __TRACE_FIRST_TYPE = 0,
 
@@ -127,12 +132,21 @@ enum trace_flag_type {
 
 #define TRACE_BUF_SIZE         1024
 
+struct trace_array;
+
+struct trace_cpu {
+       struct trace_array      *tr;
+       struct dentry           *dir;
+       int                     cpu;
+};
+
 /*
  * The CPU trace array - it consists of thousands of trace entries
  * plus some other descriptor data: (for example which task started
  * the trace, etc.)
  */
 struct trace_array_cpu {
+       struct trace_cpu        trace_cpu;
        atomic_t                disabled;
        void                    *buffer_page;   /* ring buffer spare */
 
@@ -151,6 +165,8 @@ struct trace_array_cpu {
        char                    comm[TASK_COMM_LEN];
 };
 
+struct tracer;
+
 /*
  * The trace array - an array of per-CPU trace arrays. This is the
  * highest level data structure that individual tracers deal with.
@@ -158,13 +174,53 @@ struct trace_array_cpu {
  */
 struct trace_array {
        struct ring_buffer      *buffer;
+       struct list_head        list;
+       char                    *name;
        int                     cpu;
        int                     buffer_disabled;
+       struct trace_cpu        trace_cpu;      /* place holder */
+#ifdef CONFIG_FTRACE_SYSCALLS
+       int                     sys_refcount_enter;
+       int                     sys_refcount_exit;
+       DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
+       DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
+#endif
+       int                     stop_count;
+       int                     clock_id;
+       struct tracer           *current_trace;
+       unsigned int            flags;
        cycle_t                 time_start;
+       raw_spinlock_t          start_lock;
+       struct dentry           *dir;
+       struct dentry           *options;
+       struct dentry           *percpu_dir;
+       struct dentry           *event_dir;
+       struct list_head        systems;
+       struct list_head        events;
        struct task_struct      *waiter;
-       struct trace_array_cpu  *data[NR_CPUS];
+       struct trace_array_cpu  *data;
 };
 
+enum {
+       TRACE_ARRAY_FL_GLOBAL   = (1 << 0)
+};
+
+extern struct list_head ftrace_trace_arrays;
+
+/*
+ * The global tracer (top) should be the first trace array added,
+ * but we check the flag anyway.
+ */
+static inline struct trace_array *top_trace_array(void)
+{
+       struct trace_array *tr;
+
+       tr = list_entry(ftrace_trace_arrays.prev,
+                       typeof(*tr), list);
+       WARN_ON(!(tr->flags & TRACE_ARRAY_FL_GLOBAL));
+       return tr;
+}
+
 #define FTRACE_CMP_TYPE(var, type) \
        __builtin_types_compatible_p(typeof(var), type *)
 
@@ -283,24 +339,70 @@ struct tracer {
        enum print_line_t       (*print_line)(struct trace_iterator *iter);
        /* If you handled the flag setting, return 0 */
        int                     (*set_flag)(u32 old_flags, u32 bit, int set);
+       /* Return 0 if OK with change, else return non-zero */
+       int                     (*flag_changed)(struct tracer *tracer,
+                                               u32 mask, int set);
        struct tracer           *next;
        struct tracer_flags     *flags;
        bool                    print_max;
        bool                    use_max_tr;
+       bool                    allocated_snapshot;
+       bool                    enabled;
 };
 
 
 /* Only current can touch trace_recursion */
-#define trace_recursion_inc() do { (current)->trace_recursion++; } while (0)
-#define trace_recursion_dec() do { (current)->trace_recursion--; } while (0)
-
-/* Ring buffer has the 10 LSB bits to count */
-#define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff)
 
-/* for function tracing recursion */
-#define TRACE_INTERNAL_BIT             (1<<11)
-#define TRACE_GLOBAL_BIT               (1<<12)
-#define TRACE_CONTROL_BIT              (1<<13)
+/*
+ * For function tracing recursion:
+ *  The order of these bits are important.
+ *
+ *  When function tracing occurs, the following steps are made:
+ *   If arch does not support a ftrace feature:
+ *    call internal function (uses INTERNAL bits) which calls...
+ *   If callback is registered to the "global" list, the list
+ *    function is called and recursion checks the GLOBAL bits.
+ *    then this function calls...
+ *   The function callback, which can use the FTRACE bits to
+ *    check for recursion.
+ *
+ * Now if the arch does not suppport a feature, and it calls
+ * the global list function which calls the ftrace callback
+ * all three of these steps will do a recursion protection.
+ * There's no reason to do one if the previous caller already
+ * did. The recursion that we are protecting against will
+ * go through the same steps again.
+ *
+ * To prevent the multiple recursion checks, if a recursion
+ * bit is set that is higher than the MAX bit of the current
+ * check, then we know that the check was made by the previous
+ * caller, and we can skip the current check.
+ */
+enum {
+       TRACE_BUFFER_BIT,
+       TRACE_BUFFER_NMI_BIT,
+       TRACE_BUFFER_IRQ_BIT,
+       TRACE_BUFFER_SIRQ_BIT,
+
+       /* Start of function recursion bits */
+       TRACE_FTRACE_BIT,
+       TRACE_FTRACE_NMI_BIT,
+       TRACE_FTRACE_IRQ_BIT,
+       TRACE_FTRACE_SIRQ_BIT,
+
+       /* GLOBAL_BITs must be greater than FTRACE_BITs */
+       TRACE_GLOBAL_BIT,
+       TRACE_GLOBAL_NMI_BIT,
+       TRACE_GLOBAL_IRQ_BIT,
+       TRACE_GLOBAL_SIRQ_BIT,
+
+       /* INTERNAL_BITs must be greater than GLOBAL_BITs */
+       TRACE_INTERNAL_BIT,
+       TRACE_INTERNAL_NMI_BIT,
+       TRACE_INTERNAL_IRQ_BIT,
+       TRACE_INTERNAL_SIRQ_BIT,
+
+       TRACE_CONTROL_BIT,
 
 /*
  * Abuse of the trace_recursion.
@@ -309,13 +411,77 @@ struct tracer {
  * was called in irq context but we have irq tracing off. Since this
  * can only be modified by current, we can reuse trace_recursion.
  */
-#define TRACE_IRQ_BIT                  (1<<13)
+       TRACE_IRQ_BIT,
+};
 
-#define trace_recursion_set(bit)       do { (current)->trace_recursion |= (bit); } while (0)
-#define trace_recursion_clear(bit)     do { (current)->trace_recursion &= ~(bit); } while (0)
-#define trace_recursion_test(bit)      ((current)->trace_recursion & (bit))
+#define trace_recursion_set(bit)       do { (current)->trace_recursion |= (1<<(bit)); } while (0)
+#define trace_recursion_clear(bit)     do { (current)->trace_recursion &= ~(1<<(bit)); } while (0)
+#define trace_recursion_test(bit)      ((current)->trace_recursion & (1<<(bit)))
 
-#define TRACE_PIPE_ALL_CPU     -1
+#define TRACE_CONTEXT_BITS     4
+
+#define TRACE_FTRACE_START     TRACE_FTRACE_BIT
+#define TRACE_FTRACE_MAX       ((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1)
+
+#define TRACE_GLOBAL_START     TRACE_GLOBAL_BIT
+#define TRACE_GLOBAL_MAX       ((1 << (TRACE_GLOBAL_START + TRACE_CONTEXT_BITS)) - 1)
+
+#define TRACE_LIST_START       TRACE_INTERNAL_BIT
+#define TRACE_LIST_MAX         ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1)
+
+#define TRACE_CONTEXT_MASK     TRACE_LIST_MAX
+
+static __always_inline int trace_get_context_bit(void)
+{
+       int bit;
+
+       if (in_interrupt()) {
+               if (in_nmi())
+                       bit = 0;
+
+               else if (in_irq())
+                       bit = 1;
+               else
+                       bit = 2;
+       } else
+               bit = 3;
+
+       return bit;
+}
+
+static __always_inline int trace_test_and_set_recursion(int start, int max)
+{
+       unsigned int val = current->trace_recursion;
+       int bit;
+
+       /* A previous recursion check was made */
+       if ((val & TRACE_CONTEXT_MASK) > max)
+               return 0;
+
+       bit = trace_get_context_bit() + start;
+       if (unlikely(val & (1 << bit)))
+               return -1;
+
+       val |= 1 << bit;
+       current->trace_recursion = val;
+       barrier();
+
+       return bit;
+}
+
+static __always_inline void trace_clear_recursion(int bit)
+{
+       unsigned int val = current->trace_recursion;
+
+       if (!bit)
+               return;
+
+       bit = 1 << bit;
+       val &= ~bit;
+
+       barrier();
+       current->trace_recursion = val;
+}
 
 static inline struct ring_buffer_iter *
 trace_buffer_iter(struct trace_iterator *iter, int cpu)
@@ -338,6 +504,7 @@ struct dentry *trace_create_file(const char *name,
                                 void *data,
                                 const struct file_operations *fops);
 
+struct dentry *tracing_init_dentry_tr(struct trace_array *tr);
 struct dentry *tracing_init_dentry(void);
 
 struct ring_buffer_event;
@@ -720,8 +887,8 @@ enum {
 
 struct ftrace_event_field {
        struct list_head        link;
-       char                    *name;
-       char                    *type;
+       const char              *name;
+       const char              *type;
        int                     filter_type;
        int                     offset;
        int                     size;
@@ -739,12 +906,19 @@ struct event_filter {
 struct event_subsystem {
        struct list_head        list;
        const char              *name;
-       struct dentry           *entry;
        struct event_filter     *filter;
-       int                     nr_events;
        int                     ref_count;
 };
 
+struct ftrace_subsystem_dir {
+       struct list_head                list;
+       struct event_subsystem          *subsystem;
+       struct trace_array              *tr;
+       struct dentry                   *entry;
+       int                             ref_count;
+       int                             nr_events;
+};
+
 #define FILTER_PRED_INVALID    ((unsigned short)-1)
 #define FILTER_PRED_IS_RIGHT   (1 << 15)
 #define FILTER_PRED_FOLD       (1 << 15)
@@ -802,7 +976,7 @@ extern void print_event_filter(struct ftrace_event_call *call,
                               struct trace_seq *s);
 extern int apply_event_filter(struct ftrace_event_call *call,
                              char *filter_string);
-extern int apply_subsystem_event_filter(struct event_subsystem *system,
+extern int apply_subsystem_event_filter(struct ftrace_subsystem_dir *dir,
                                        char *filter_string);
 extern void print_subsystem_event_filter(struct event_subsystem *system,
                                         struct trace_seq *s);
@@ -826,6 +1000,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
 }
 
 extern void trace_event_enable_cmd_record(bool enable);
+extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
+extern int event_trace_del_tracer(struct trace_array *tr);
 
 extern struct mutex event_mutex;
 extern struct list_head ftrace_events;
@@ -835,6 +1011,8 @@ extern const char *__stop___trace_bprintk_fmt[];
 
 void trace_printk_init_buffers(void);
 void trace_printk_start_comm(void);
+int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
+int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled);
 
 #undef FTRACE_ENTRY
 #define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter)    \