Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ca72feb authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'perf-fixes-for-linus' of...

Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  perf tools: Fix build on POSIX shells
  latencytop: Fix kconfig dependency warnings
  perf annotate tui: Fix exit and RIGHT keys handling
  tracing: Sanitize value returned from write(trace_marker, "...", len)
  tracing/events: Convert format output to seq_file
  tracing: Extend recordmcount to better support Blackfin mcount
  tracing: Fix ring_buffer_read_page reading out of page boundary
  tracing: Fix an unallocated memory access in function_graph
parents 7dfb2d40 9d5f3714
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -3846,6 +3846,9 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
			rpos = reader->read;
			rpos = reader->read;
			pos += size;
			pos += size;


			if (rpos >= commit)
				break;

			event = rb_reader_event(cpu_buffer);
			event = rb_reader_event(cpu_buffer);
			size = rb_event_length(event);
			size = rb_event_length(event);
		} while (len > size);
		} while (len > size);
+8 −3
Original line number Original line Diff line number Diff line
@@ -3463,6 +3463,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
					size_t cnt, loff_t *fpos)
					size_t cnt, loff_t *fpos)
{
{
	char *buf;
	char *buf;
	size_t written;


	if (tracing_disabled)
	if (tracing_disabled)
		return -EINVAL;
		return -EINVAL;
@@ -3484,11 +3485,15 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
	} else
	} else
		buf[cnt] = '\0';
		buf[cnt] = '\0';


	cnt = mark_printk("%s", buf);
	written = mark_printk("%s", buf);
	kfree(buf);
	kfree(buf);
	*fpos += cnt;
	*fpos += written;


	return cnt;
	/* don't tell userspace we wrote more - it might confuse them */
	if (written > cnt)
		written = cnt;

	return written;
}
}


static int tracing_clock_show(struct seq_file *m, void *v)
static int tracing_clock_show(struct seq_file *m, void *v)
+143 −64
Original line number Original line Diff line number Diff line
@@ -598,11 +598,114 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
	return ret;
	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;

	(*pos)++;

	switch ((unsigned long)v) {
	case FORMAT_HEADER:
		head = &ftrace_common_fields;

		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);

	return field;
}

static void *f_start(struct seq_file *m, loff_t *pos)
{
	loff_t l = 0;
	void *p;

	/* 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;
	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;

	case FORMAT_PRINTFMT:
		seq_printf(m, "\nprint fmt: %s\n",
			   call->print_fmt);
		return 0;
	}

	/*
	 * 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);
	}

	field = v;


	list_for_each_entry_reverse(field, head, link) {
	/*
	/*
	 * Smartly shows the array type(except dynamic array).
	 * Smartly shows the array type(except dynamic array).
	 * Normal:
	 * Normal:
@@ -610,76 +713,50 @@ static void print_event_fields(struct trace_seq *s, struct list_head *head)
	 * If TYPE := TYPE[LEN], it is shown:
	 * If TYPE := TYPE[LEN], it is shown:
	 *	field:TYPE VAR[LEN]
	 *	field:TYPE VAR[LEN]
	 */
	 */
		const char *array_descriptor = strchr(field->type, '[');
	array_descriptor = strchr(field->type, '[');


	if (!strncmp(field->type, "__data_loc", 10))
	if (!strncmp(field->type, "__data_loc", 10))
		array_descriptor = NULL;
		array_descriptor = NULL;


		if (!array_descriptor) {
	if (!array_descriptor)
			trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;"
		seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n",
					"\tsize:%u;\tsigned:%d;\n",
			   field->type, field->name, field->offset,
			   field->type, field->name, field->offset,
			   field->size, !!field->is_signed);
			   field->size, !!field->is_signed);
		} else {
	else
			trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;"
		seq_printf(m, "\tfield:%.*s %s%s;\toffset:%u;\tsize:%u;\tsigned:%d;\n",
					"\tsize:%u;\tsigned:%d;\n",
			   (int)(array_descriptor - field->type),
			   (int)(array_descriptor - field->type),
			   field->type, field->name,
			   field->type, field->name,
			   array_descriptor, field->offset,
			   array_descriptor, field->offset,
			   field->size, !!field->is_signed);
			   field->size, !!field->is_signed);
		}
	}
}


static ssize_t
event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
		  loff_t *ppos)
{
	struct ftrace_event_call *call = filp->private_data;
	struct list_head *head;
	struct trace_seq *s;
	char *buf;
	int r;

	if (*ppos)
	return 0;
	return 0;
}


	s = kmalloc(sizeof(*s), GFP_KERNEL);
static void f_stop(struct seq_file *m, void *p)
	if (!s)
{
		return -ENOMEM;
}

	trace_seq_init(s);

	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");

	/* print common fields */
	print_event_fields(s, &ftrace_common_fields);


	trace_seq_putc(s, '\n');
static const struct seq_operations trace_format_seq_ops = {
	.start		= f_start,
	.next		= f_next,
	.stop		= f_stop,
	.show		= f_show,
};


	/* print event specific fields */
static int trace_format_open(struct inode *inode, struct file *file)
	head = trace_get_fields(call);
{
	print_event_fields(s, head);
	struct ftrace_event_call *call = inode->i_private;
	struct seq_file *m;
	int ret;


	r = trace_seq_printf(s, "\nprint fmt: %s\n", call->print_fmt);
	ret = seq_open(file, &trace_format_seq_ops);
	if (ret < 0)
		return ret;


	if (!r) {
	m = file->private_data;
		/*
	m->private = call;
		 * 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;
	}


	r = simple_read_from_buffer(ubuf, cnt, ppos,
	return 0;
				    s->buffer, s->len);
 out:
	kfree(s);
	return r;
}
}


static ssize_t
static ssize_t
@@ -877,8 +954,10 @@ static const struct file_operations ftrace_enable_fops = {
};
};


static const struct file_operations ftrace_event_format_fops = {
static const struct file_operations ftrace_event_format_fops = {
	.open = tracing_open_generic,
	.open = trace_format_open,
	.read = event_format_read,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = seq_release,
};
};


static const struct file_operations ftrace_event_id_fops = {
static const struct file_operations ftrace_event_id_fops = {
+9 −1
Original line number Original line Diff line number Diff line
@@ -507,7 +507,15 @@ get_return_for_leaf(struct trace_iterator *iter,
			 * if the output fails.
			 * if the output fails.
			 */
			 */
			data->ent = *curr;
			data->ent = *curr;
			/*
			 * If the next event is not a return type, then
			 * we only care about what type it is. Otherwise we can
			 * safely copy the entire event.
			 */
			if (next->ent.type == TRACE_GRAPH_RET)
				data->ret = *next;
				data->ret = *next;
			else
				data->ret.ent.type = next->ent.type;
		}
		}
	}
	}


+4 −1
Original line number Original line Diff line number Diff line
@@ -994,13 +994,16 @@ config FAULT_INJECTION_STACKTRACE_FILTER


config LATENCYTOP
config LATENCYTOP
	bool "Latency measuring infrastructure"
	bool "Latency measuring infrastructure"
	depends on HAVE_LATENCYTOP_SUPPORT
	depends on DEBUG_KERNEL
	depends on STACKTRACE_SUPPORT
	depends on PROC_FS
	select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE
	select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE
	select KALLSYMS
	select KALLSYMS
	select KALLSYMS_ALL
	select KALLSYMS_ALL
	select STACKTRACE
	select STACKTRACE
	select SCHEDSTATS
	select SCHEDSTATS
	select SCHED_DEBUG
	select SCHED_DEBUG
	depends on HAVE_LATENCYTOP_SUPPORT
	help
	help
	  Enable this option if you want to use the LatencyTOP tool
	  Enable this option if you want to use the LatencyTOP tool
	  to find out which userspace is blocking on what kernel operations.
	  to find out which userspace is blocking on what kernel operations.
Loading