Merge tag 'trace-v4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing updates from Steven Rostedt:
 "Some clean ups and small fixes, but the biggest change is the addition
  of the TRACE_DEFINE_ENUM() macro that can be used by tracepoints.

  Tracepoints have helper functions for the TP_printk() called
  __print_symbolic() and __print_flags() that lets a numeric number be
  displayed as a a human comprehensible text.  What is placed in the
  TP_printk() is also shown in the tracepoint format file such that user
  space tools like perf and trace-cmd can parse the binary data and
  express the values too.  Unfortunately, the way the TRACE_EVENT()
  macro works, anything placed in the TP_printk() will be shown pretty
  much exactly as is.  The problem arises when enums are used.  That's
  because unlike macros, enums will not be changed into their values by
  the C pre-processor.  Thus, the enum string is exported to the format
  file, and this makes it useless for user space tools.

  The TRACE_DEFINE_ENUM() solves this by converting the enum strings in
  the TP_printk() format into their number, and that is what is shown to
  user space.  For example, the tracepoint tlb_flush currently has this
  in its format file:

     __print_symbolic(REC->reason,
        { TLB_FLUSH_ON_TASK_SWITCH, "flush on task switch" },
        { TLB_REMOTE_SHOOTDOWN, "remote shootdown" },
        { TLB_LOCAL_SHOOTDOWN, "local shootdown" },
        { TLB_LOCAL_MM_SHOOTDOWN, "local mm shootdown" })

  After adding:

     TRACE_DEFINE_ENUM(TLB_FLUSH_ON_TASK_SWITCH);
     TRACE_DEFINE_ENUM(TLB_REMOTE_SHOOTDOWN);
     TRACE_DEFINE_ENUM(TLB_LOCAL_SHOOTDOWN);
     TRACE_DEFINE_ENUM(TLB_LOCAL_MM_SHOOTDOWN);

  Its format file will contain this:

     __print_symbolic(REC->reason,
        { 0, "flush on task switch" },
        { 1, "remote shootdown" },
        { 2, "local shootdown" },
        { 3, "local mm shootdown" })"

* tag 'trace-v4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (27 commits)
  tracing: Add enum_map file to show enums that have been mapped
  writeback: Export enums used by tracepoint to user space
  v4l: Export enums used by tracepoints to user space
  SUNRPC: Export enums in tracepoints to user space
  mm: tracing: Export enums in tracepoints to user space
  irq/tracing: Export enums in tracepoints to user space
  f2fs: Export the enums in the tracepoints to userspace
  net/9p/tracing: Export enums in tracepoints to userspace
  x86/tlb/trace: Export enums in used by tlb_flush tracepoint
  tracing/samples: Update the trace-event-sample.h with TRACE_DEFINE_ENUM()
  tracing: Allow for modules to convert their enums to values
  tracing: Add TRACE_DEFINE_ENUM() macro to map enums to their values
  tracing: Update trace-event-sample with TRACE_SYSTEM_VAR documentation
  tracing: Give system name a pointer
  brcmsmac: Move each system tracepoints to their own header
  iwlwifi: Move each system tracepoints to their own header
  mac80211: Move message tracepoints to their own header
  tracing: Add TRACE_SYSTEM_VAR to xhci-hcd
  tracing: Add TRACE_SYSTEM_VAR to kvm-s390
  tracing: Add TRACE_SYSTEM_VAR to intel-sst
  ...
This commit is contained in:
Linus Torvalds
2015-04-14 10:49:03 -07:00
52 changed files with 1959 additions and 909 deletions

View File

@@ -125,6 +125,42 @@ enum ftrace_dump_mode ftrace_dump_on_oops;
/* When set, tracing will stop when a WARN*() is hit */
int __disable_trace_on_warning;
#ifdef CONFIG_TRACE_ENUM_MAP_FILE
/* Map of enums to their values, for "enum_map" file */
struct trace_enum_map_head {
struct module *mod;
unsigned long length;
};
union trace_enum_map_item;
struct trace_enum_map_tail {
/*
* "end" is first and points to NULL as it must be different
* than "mod" or "enum_string"
*/
union trace_enum_map_item *next;
const char *end; /* points to NULL */
};
static DEFINE_MUTEX(trace_enum_mutex);
/*
* The trace_enum_maps are saved in an array with two extra elements,
* one at the beginning, and one at the end. The beginning item contains
* the count of the saved maps (head.length), and the module they
* belong to if not built in (head.mod). The ending item contains a
* pointer to the next array of saved enum_map items.
*/
union trace_enum_map_item {
struct trace_enum_map map;
struct trace_enum_map_head head;
struct trace_enum_map_tail tail;
};
static union trace_enum_map_item *trace_enum_maps;
#endif /* CONFIG_TRACE_ENUM_MAP_FILE */
static int tracing_set_tracer(struct trace_array *tr, const char *buf);
#define MAX_TRACER_SIZE 100
@@ -3910,6 +3946,182 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = {
.write = tracing_saved_cmdlines_size_write,
};
#ifdef CONFIG_TRACE_ENUM_MAP_FILE
static union trace_enum_map_item *
update_enum_map(union trace_enum_map_item *ptr)
{
if (!ptr->map.enum_string) {
if (ptr->tail.next) {
ptr = ptr->tail.next;
/* Set ptr to the next real item (skip head) */
ptr++;
} else
return NULL;
}
return ptr;
}
static void *enum_map_next(struct seq_file *m, void *v, loff_t *pos)
{
union trace_enum_map_item *ptr = v;
/*
* Paranoid! If ptr points to end, we don't want to increment past it.
* This really should never happen.
*/
ptr = update_enum_map(ptr);
if (WARN_ON_ONCE(!ptr))
return NULL;
ptr++;
(*pos)++;
ptr = update_enum_map(ptr);
return ptr;
}
static void *enum_map_start(struct seq_file *m, loff_t *pos)
{
union trace_enum_map_item *v;
loff_t l = 0;
mutex_lock(&trace_enum_mutex);
v = trace_enum_maps;
if (v)
v++;
while (v && l < *pos) {
v = enum_map_next(m, v, &l);
}
return v;
}
static void enum_map_stop(struct seq_file *m, void *v)
{
mutex_unlock(&trace_enum_mutex);
}
static int enum_map_show(struct seq_file *m, void *v)
{
union trace_enum_map_item *ptr = v;
seq_printf(m, "%s %ld (%s)\n",
ptr->map.enum_string, ptr->map.enum_value,
ptr->map.system);
return 0;
}
static const struct seq_operations tracing_enum_map_seq_ops = {
.start = enum_map_start,
.next = enum_map_next,
.stop = enum_map_stop,
.show = enum_map_show,
};
static int tracing_enum_map_open(struct inode *inode, struct file *filp)
{
if (tracing_disabled)
return -ENODEV;
return seq_open(filp, &tracing_enum_map_seq_ops);
}
static const struct file_operations tracing_enum_map_fops = {
.open = tracing_enum_map_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static inline union trace_enum_map_item *
trace_enum_jmp_to_tail(union trace_enum_map_item *ptr)
{
/* Return tail of array given the head */
return ptr + ptr->head.length + 1;
}
static void
trace_insert_enum_map_file(struct module *mod, struct trace_enum_map **start,
int len)
{
struct trace_enum_map **stop;
struct trace_enum_map **map;
union trace_enum_map_item *map_array;
union trace_enum_map_item *ptr;
stop = start + len;
/*
* The trace_enum_maps contains the map plus a head and tail item,
* where the head holds the module and length of array, and the
* tail holds a pointer to the next list.
*/
map_array = kmalloc(sizeof(*map_array) * (len + 2), GFP_KERNEL);
if (!map_array) {
pr_warning("Unable to allocate trace enum mapping\n");
return;
}
mutex_lock(&trace_enum_mutex);
if (!trace_enum_maps)
trace_enum_maps = map_array;
else {
ptr = trace_enum_maps;
for (;;) {
ptr = trace_enum_jmp_to_tail(ptr);
if (!ptr->tail.next)
break;
ptr = ptr->tail.next;
}
ptr->tail.next = map_array;
}
map_array->head.mod = mod;
map_array->head.length = len;
map_array++;
for (map = start; (unsigned long)map < (unsigned long)stop; map++) {
map_array->map = **map;
map_array++;
}
memset(map_array, 0, sizeof(*map_array));
mutex_unlock(&trace_enum_mutex);
}
static void trace_create_enum_file(struct dentry *d_tracer)
{
trace_create_file("enum_map", 0444, d_tracer,
NULL, &tracing_enum_map_fops);
}
#else /* CONFIG_TRACE_ENUM_MAP_FILE */
static inline void trace_create_enum_file(struct dentry *d_tracer) { }
static inline void trace_insert_enum_map_file(struct module *mod,
struct trace_enum_map **start, int len) { }
#endif /* !CONFIG_TRACE_ENUM_MAP_FILE */
static void trace_insert_enum_map(struct module *mod,
struct trace_enum_map **start, int len)
{
struct trace_enum_map **map;
if (len <= 0)
return;
map = start;
trace_event_enum_update(map, len);
trace_insert_enum_map_file(mod, start, len);
}
static ssize_t
tracing_set_trace_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
@@ -6527,6 +6739,88 @@ struct dentry *tracing_init_dentry(void)
return NULL;
}
extern struct trace_enum_map *__start_ftrace_enum_maps[];
extern struct trace_enum_map *__stop_ftrace_enum_maps[];
static void __init trace_enum_init(void)
{
int len;
len = __stop_ftrace_enum_maps - __start_ftrace_enum_maps;
trace_insert_enum_map(NULL, __start_ftrace_enum_maps, len);
}
#ifdef CONFIG_MODULES
static void trace_module_add_enums(struct module *mod)
{
if (!mod->num_trace_enums)
return;
/*
* Modules with bad taint do not have events created, do
* not bother with enums either.
*/
if (trace_module_has_bad_taint(mod))
return;
trace_insert_enum_map(mod, mod->trace_enums, mod->num_trace_enums);
}
#ifdef CONFIG_TRACE_ENUM_MAP_FILE
static void trace_module_remove_enums(struct module *mod)
{
union trace_enum_map_item *map;
union trace_enum_map_item **last = &trace_enum_maps;
if (!mod->num_trace_enums)
return;
mutex_lock(&trace_enum_mutex);
map = trace_enum_maps;
while (map) {
if (map->head.mod == mod)
break;
map = trace_enum_jmp_to_tail(map);
last = &map->tail.next;
map = map->tail.next;
}
if (!map)
goto out;
*last = trace_enum_jmp_to_tail(map)->tail.next;
kfree(map);
out:
mutex_unlock(&trace_enum_mutex);
}
#else
static inline void trace_module_remove_enums(struct module *mod) { }
#endif /* CONFIG_TRACE_ENUM_MAP_FILE */
static int trace_module_notify(struct notifier_block *self,
unsigned long val, void *data)
{
struct module *mod = data;
switch (val) {
case MODULE_STATE_COMING:
trace_module_add_enums(mod);
break;
case MODULE_STATE_GOING:
trace_module_remove_enums(mod);
break;
}
return 0;
}
static struct notifier_block trace_module_nb = {
.notifier_call = trace_module_notify,
.priority = 0,
};
#endif /* CONFIG_MODULES */
static __init int tracer_init_tracefs(void)
{
struct dentry *d_tracer;
@@ -6551,6 +6845,14 @@ static __init int tracer_init_tracefs(void)
trace_create_file("saved_cmdlines_size", 0644, d_tracer,
NULL, &tracing_saved_cmdlines_size_fops);
trace_enum_init();
trace_create_enum_file(d_tracer);
#ifdef CONFIG_MODULES
register_module_notifier(&trace_module_nb);
#endif
#ifdef CONFIG_DYNAMIC_FTRACE
trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
&ftrace_update_tot_cnt, &tracing_dyn_info_fops);
@@ -6877,7 +7179,7 @@ void __init trace_init(void)
tracepoint_printk = 0;
}
tracer_alloc_buffers();
trace_event_init();
trace_event_init();
}
__init static int clear_boot_tracer(void)