From: Steven Rostedt Date: Mon, 16 Aug 2010 15:17:30 +0000 (-0400) Subject: Merge branch 'tip/perf/urgent-3' of git://git.kernel.org/pub/scm/linux/kernel/git... X-Git-Tag: v2.6.36-rc2~40^2~3 X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=commitdiff_plain;h=d244b6bd41e09ecbb09c738cc2c108be227398c8 Merge branch 'tip/perf/urgent-3' of git://git./linux/kernel/git/rostedt/linux-2.6-trace into trace/tip/perf/urgent-4 Conflicts: kernel/trace/trace_events.c Signed-off-by: Steven Rostedt --- d244b6bd41e09ecbb09c738cc2c108be227398c8 diff --cc kernel/trace/trace_events.c index 09b4fa6e4d3b,45a8968707aa..4c758f146328 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@@ -598,88 -546,155 +598,165 @@@ out return ret; } - static void print_event_fields(struct trace_seq *s, struct list_head *head) + enum { + FORMAT_HEADER = 1, + FORMAT_PRINTFMT = 2, + }; + + static void *f_next(struct seq_file *m, void *v, loff_t *pos) { + struct ftrace_event_call *call = m->private; struct ftrace_event_field *field; + struct list_head *head; - loff_t index = *pos; - list_for_each_entry_reverse(field, head, link) { - /* - * Smartly shows the array type(except dynamic array). - * Normal: - * field:TYPE VAR - * If TYPE := TYPE[LEN], it is shown: - * field:TYPE VAR[LEN] - */ - const char *array_descriptor = strchr(field->type, '['); + (*pos)++; - if (!strncmp(field->type, "__data_loc", 10)) - array_descriptor = NULL; - head = trace_get_fields(call); - + switch ((unsigned long)v) { + case FORMAT_HEADER: ++ head = &ftrace_common_fields; - if (!array_descriptor) { - trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" - "\tsize:%u;\tsigned:%d;\n", - field->type, field->name, field->offset, - field->size, !!field->is_signed); - } else { - trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" - "\tsize:%u;\tsigned:%d;\n", - (int)(array_descriptor - field->type), - field->type, field->name, - array_descriptor, field->offset, - field->size, !!field->is_signed); - } + if (unlikely(list_empty(head))) + return NULL; + + field = list_entry(head->prev, struct ftrace_event_field, link); + return field; + + case FORMAT_PRINTFMT: + /* all done */ + return NULL; + } + ++ head = trace_get_fields(call); ++ + /* + * To separate common fields from event fields, the + * LSB is set on the first event field. Clear it in case. + */ + v = (void *)((unsigned long)v & ~1L); + + field = v; ++ /* ++ * If this is a common field, and at the end of the list, then ++ * continue with main list. ++ */ ++ if (field->link.prev == &ftrace_common_fields) { ++ if (unlikely(list_empty(head))) ++ return NULL; ++ field = list_entry(head->prev, struct ftrace_event_field, link); ++ /* Set the LSB to notify f_show to print an extra newline */ ++ field = (struct ftrace_event_field *) ++ ((unsigned long)field | 1); ++ return field; + } ++ ++ /* If we are done tell f_show to print the format */ + if (field->link.prev == head) + return (void *)FORMAT_PRINTFMT; + + field = list_entry(field->link.prev, struct ftrace_event_field, link); + - /* Set the LSB to notify f_show to print an extra newline */ - if (index == COMMON_FIELD_COUNT) - field = (struct ftrace_event_field *) - ((unsigned long)field | 1); - + return field; } - static ssize_t - event_format_read(struct file *filp, char __user *ubuf, size_t cnt, - loff_t *ppos) + static void *f_start(struct seq_file *m, loff_t *pos) { - struct ftrace_event_call *call = filp->private_data; - struct list_head *head; - struct trace_seq *s; - char *buf; - int r; + loff_t l = 0; + void *p; - if (*ppos) + /* Start by showing the header */ + if (!*pos) + return (void *)FORMAT_HEADER; + + p = (void *)FORMAT_HEADER; + do { + p = f_next(m, p, &l); + } while (p && l < *pos); + + return p; + } + + static int f_show(struct seq_file *m, void *v) + { + struct ftrace_event_call *call = m->private; + struct ftrace_event_field *field; + const char *array_descriptor; + + switch ((unsigned long)v) { + case FORMAT_HEADER: + seq_printf(m, "name: %s\n", call->name); + seq_printf(m, "ID: %d\n", call->event.type); + seq_printf(m, "format:\n"); return 0; - s = kmalloc(sizeof(*s), GFP_KERNEL); - if (!s) - return -ENOMEM; + case FORMAT_PRINTFMT: + seq_printf(m, "\nprint fmt: %s\n", + call->print_fmt); + return 0; + } - trace_seq_init(s); + /* + * To separate common fields from event fields, the + * LSB is set on the first event field. Clear it and + * print a newline if it is set. + */ + if ((unsigned long)v & 1) { + seq_putc(m, '\n'); + v = (void *)((unsigned long)v & ~1L); + } - trace_seq_printf(s, "name: %s\n", call->name); - trace_seq_printf(s, "ID: %d\n", call->event.type); - trace_seq_printf(s, "format:\n"); + field = v; - /* print common fields */ - print_event_fields(s, &ftrace_common_fields); + /* + * Smartly shows the array type(except dynamic array). + * Normal: + * field:TYPE VAR + * If TYPE := TYPE[LEN], it is shown: + * field:TYPE VAR[LEN] + */ + array_descriptor = strchr(field->type, '['); - trace_seq_putc(s, '\n'); + if (!strncmp(field->type, "__data_loc", 10)) + array_descriptor = NULL; - /* print event specific fields */ - head = trace_get_fields(call); - print_event_fields(s, head); + if (!array_descriptor) + seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", + field->type, field->name, field->offset, + field->size, !!field->is_signed); + else + seq_printf(m, "\tfield:%.*s %s%s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", + (int)(array_descriptor - field->type), + field->type, field->name, + array_descriptor, field->offset, + field->size, !!field->is_signed); - r = trace_seq_printf(s, "\nprint fmt: %s\n", call->print_fmt); + return 0; + } - if (!r) { - /* - * ug! The format output is bigger than a PAGE!! - */ - buf = "FORMAT TOO BIG\n"; - r = simple_read_from_buffer(ubuf, cnt, ppos, - buf, strlen(buf)); - goto out; - } + static void f_stop(struct seq_file *m, void *p) + { + } - r = simple_read_from_buffer(ubuf, cnt, ppos, - s->buffer, s->len); - out: - kfree(s); - return r; + static const struct seq_operations trace_format_seq_ops = { + .start = f_start, + .next = f_next, + .stop = f_stop, + .show = f_show, + }; + + static int trace_format_open(struct inode *inode, struct file *file) + { + struct ftrace_event_call *call = inode->i_private; + struct seq_file *m; + int ret; + + ret = seq_open(file, &trace_format_seq_ops); + if (ret < 0) + return ret; + + m = file->private_data; + m->private = call; + + return 0; } static ssize_t