Merge commit 'v2.6.32-rc6' into perf/core
[safe/jmp/linux-2.6] / include / trace / ftrace.h
index a822087..c9bbcab 100644 (file)
 #undef __field
 #define __field(type, item)                                    \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t"      \
-                              "offset:%u;\tsize:%u;\n",                \
+                              "offset:%u;\tsize:%u;\tsigned:%u;\n",    \
                               (unsigned int)offsetof(typeof(field), item), \
-                              (unsigned int)sizeof(field.item));       \
+                              (unsigned int)sizeof(field.item),        \
+                              (unsigned int)is_signed_type(type));     \
        if (!ret)                                                       \
                return 0;
 
 #undef __array
 #define __array(type, item, len)                                               \
        ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t"    \
-                              "offset:%u;\tsize:%u;\n",                \
+                              "offset:%u;\tsize:%u;\tsigned:%u;\n",    \
                               (unsigned int)offsetof(typeof(field), item), \
-                              (unsigned int)sizeof(field.item));       \
+                              (unsigned int)sizeof(field.item),        \
+                              (unsigned int)is_signed_type(type));     \
        if (!ret)                                                       \
                return 0;
 
 #undef __dynamic_array
 #define __dynamic_array(type, item, len)                                      \
        ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\
-                              "offset:%u;\tsize:%u;\n",                       \
+                              "offset:%u;\tsize:%u;\tsigned:%u;\n",           \
                               (unsigned int)offsetof(typeof(field),           \
                                        __data_loc_##item),                    \
-                              (unsigned int)sizeof(field.__data_loc_##item)); \
+                              (unsigned int)sizeof(field.__data_loc_##item), \
+                              (unsigned int)is_signed_type(type));     \
        if (!ret)                                                              \
                return 0;
 
@@ -378,7 +381,7 @@ static inline int ftrace_get_offsets_##call(                                \
 #ifdef CONFIG_EVENT_PROFILE
 
 /*
- * Generate the functions needed for tracepoint perf_counter support.
+ * Generate the functions needed for tracepoint perf_event support.
  *
  * NOTE: The insertion profile callback (ftrace_profile_<call>) is defined later
  *
@@ -644,15 +647,16 @@ __attribute__((section("_ftrace_events"))) event_##call = {               \
  * {
  *     struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
  *     struct ftrace_event_call *event_call = &event_<call>;
- *     extern void perf_tpcounter_event(int, u64, u64, void *, int);
+ *     extern void perf_tp_event(int, u64, u64, void *, int);
  *     struct ftrace_raw_##call *entry;
  *     u64 __addr = 0, __count = 1;
  *     unsigned long irq_flags;
+ *     struct trace_entry *ent;
  *     int __entry_size;
  *     int __data_size;
+ *     int __cpu
  *     int pc;
  *
- *     local_save_flags(irq_flags);
  *     pc = preempt_count();
  *
  *     __data_size = ftrace_get_offsets_<call>(&__data_offsets, args);
@@ -663,25 +667,34 @@ __attribute__((section("_ftrace_events"))) event_##call = {               \
  *                          sizeof(u64));
  *     __entry_size -= sizeof(u32);
  *
- *     do {
- *             char raw_data[__entry_size]; <- allocate our sample in the stack
- *             struct trace_entry *ent;
+ *     // Protect the non nmi buffer
+ *     // This also protects the rcu read side
+ *     local_irq_save(irq_flags);
+ *     __cpu = smp_processor_id();
+ *
+ *     if (in_nmi())
+ *             raw_data = rcu_dereference(trace_profile_buf_nmi);
+ *     else
+ *             raw_data = rcu_dereference(trace_profile_buf);
+ *
+ *     if (!raw_data)
+ *             goto end;
  *
- *             zero dead bytes from alignment to avoid stack leak to userspace:
+ *     raw_data = per_cpu_ptr(raw_data, __cpu);
  *
- *             *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL;
- *             entry = (struct ftrace_raw_<call> *)raw_data;
- *             ent = &entry->ent;
- *             tracing_generic_entry_update(ent, irq_flags, pc);
- *             ent->type = event_call->id;
+ *     //zero dead bytes from alignment to avoid stack leak to userspace:
+ *     *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL;
+ *     entry = (struct ftrace_raw_<call> *)raw_data;
+ *     ent = &entry->ent;
+ *     tracing_generic_entry_update(ent, irq_flags, pc);
+ *     ent->type = event_call->id;
  *
- *             <tstruct> <- do some jobs with dynamic arrays
+ *     <tstruct> <- do some jobs with dynamic arrays
  *
- *             <assign>  <- affect our values
+ *     <assign>  <- affect our values
  *
- *             perf_tpcounter_event(event_call->id, __addr, __count, entry,
- *                          __entry_size);  <- submit them to perf counter
- *     } while (0);
+ *     perf_tp_event(event_call->id, __addr, __count, entry,
+ *                  __entry_size);  <- submit them to perf counter
  *
  * }
  */
@@ -700,15 +713,17 @@ static void ftrace_profile_##call(proto)                          \
 {                                                                      \
        struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
        struct ftrace_event_call *event_call = &event_##call;           \
-       extern void perf_tpcounter_event(int, u64, u64, void *, int);   \
+       extern void perf_tp_event(int, u64, u64, void *, int);  \
        struct ftrace_raw_##call *entry;                                \
        u64 __addr = 0, __count = 1;                                    \
        unsigned long irq_flags;                                        \
+       struct trace_entry *ent;                                        \
        int __entry_size;                                               \
        int __data_size;                                                \
+       char *raw_data;                                                 \
+       int __cpu;                                                      \
        int pc;                                                         \
                                                                        \
-       local_save_flags(irq_flags);                                    \
        pc = preempt_count();                                           \
                                                                        \
        __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
@@ -716,23 +731,38 @@ static void ftrace_profile_##call(proto)                          \
                             sizeof(u64));                              \
        __entry_size -= sizeof(u32);                                    \
                                                                        \
-       do {                                                            \
-               char raw_data[__entry_size];                            \
-               struct trace_entry *ent;                                \
+       if (WARN_ONCE(__entry_size > FTRACE_MAX_PROFILE_SIZE,           \
+                     "profile buffer not large enough"))               \
+               return;                                                 \
+                                                                       \
+       local_irq_save(irq_flags);                                      \
+       __cpu = smp_processor_id();                                     \
                                                                        \
-               *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \
-               entry = (struct ftrace_raw_##call *)raw_data;           \
-               ent = &entry->ent;                                      \
-               tracing_generic_entry_update(ent, irq_flags, pc);       \
-               ent->type = event_call->id;                             \
+       if (in_nmi())                                                   \
+               raw_data = rcu_dereference(trace_profile_buf_nmi);              \
+       else                                                            \
+               raw_data = rcu_dereference(trace_profile_buf);          \
                                                                        \
-               tstruct                                                 \
+       if (!raw_data)                                                  \
+               goto end;                                               \
                                                                        \
-               { assign; }                                             \
+       raw_data = per_cpu_ptr(raw_data, __cpu);                        \
                                                                        \
-               perf_tpcounter_event(event_call->id, __addr, __count, entry,\
+       *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL;         \
+       entry = (struct ftrace_raw_##call *)raw_data;                   \
+       ent = &entry->ent;                                              \
+       tracing_generic_entry_update(ent, irq_flags, pc);               \
+       ent->type = event_call->id;                                     \
+                                                                       \
+       tstruct                                                         \
+                                                                       \
+       { assign; }                                                     \
+                                                                       \
+       perf_tp_event(event_call->id, __addr, __count, entry,           \
                             __entry_size);                             \
-       } while (0);                                                    \
+                                                                       \
+end:                                                                   \
+       local_irq_restore(irq_flags);                                   \
                                                                        \
 }