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

Commit ef34c6ce authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'trace-fixes-v3.16-rc3' of...

Merge tag 'trace-fixes-v3.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing fixes from Steven Rostedt:
 "Oleg Nesterov found and fixed a bug in the perf/ftrace/uprobes code
  where running:

    # perf probe -x /lib/libc.so.6 syscall
    # echo 1 >> /sys/kernel/debug/tracing/events/probe_libc/enable
    # perf record -e probe_libc:syscall whatever

  kills the uprobe.  Along the way he found some other minor bugs and
  clean ups that he fixed up making it a total of 4 patches.

  Doing unrelated work, I found that the reading of the ftrace trace
  file disables all function tracer callbacks.  This was fine when
  ftrace was the only user, but now that it's used by perf and kprobes,
  this is a bug where reading trace can disable kprobes and perf.  A
  very unexpected side effect and should be fixed"

* tag 'trace-fixes-v3.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  tracing: Remove ftrace_stop/start() from reading the trace file
  tracing/uprobes: Fix the usage of uprobe_buffer_enable() in probe_event_enable()
  tracing/uprobes: Kill the bogus UPROBE_HANDLER_REMOVE code in uprobe_dispatcher()
  uprobes: Change unregister/apply to WARN() if uprobe/consumer is gone
  tracing/uprobes: Revert "Support mix of ftrace and perf"
parents af6f157a 099ed151
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -846,7 +846,7 @@ static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *u
{
	int err;

	if (!consumer_del(uprobe, uc))	/* WARN? */
	if (WARN_ON(!consumer_del(uprobe, uc)))
		return;

	err = register_for_each_vma(uprobe, NULL);
@@ -927,7 +927,7 @@ int uprobe_apply(struct inode *inode, loff_t offset,
	int ret = -ENOENT;

	uprobe = find_uprobe(inode, offset);
	if (!uprobe)
	if (WARN_ON(!uprobe))
		return ret;

	down_write(&uprobe->register_rwsem);
@@ -952,7 +952,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
	struct uprobe *uprobe;

	uprobe = find_uprobe(inode, offset);
	if (!uprobe)
	if (WARN_ON(!uprobe))
		return;

	down_write(&uprobe->register_rwsem);
+0 −2
Original line number Diff line number Diff line
@@ -1396,7 +1396,6 @@ void tracing_start(void)

	arch_spin_unlock(&global_trace.max_lock);

	ftrace_start();
 out:
	raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);
}
@@ -1443,7 +1442,6 @@ void tracing_stop(void)
	struct ring_buffer *buffer;
	unsigned long flags;

	ftrace_stop();
	raw_spin_lock_irqsave(&global_trace.start_lock, flags);
	if (global_trace.stop_count++)
		goto out;
+27 −19
Original line number Diff line number Diff line
@@ -893,6 +893,9 @@ probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file,
	int ret;

	if (file) {
		if (tu->tp.flags & TP_FLAG_PROFILE)
			return -EINTR;

		link = kmalloc(sizeof(*link), GFP_KERNEL);
		if (!link)
			return -ENOMEM;
@@ -901,29 +904,40 @@ probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file,
		list_add_tail_rcu(&link->list, &tu->tp.files);

		tu->tp.flags |= TP_FLAG_TRACE;
	} else
		tu->tp.flags |= TP_FLAG_PROFILE;
	} else {
		if (tu->tp.flags & TP_FLAG_TRACE)
			return -EINTR;

	ret = uprobe_buffer_enable();
	if (ret < 0)
		return ret;
		tu->tp.flags |= TP_FLAG_PROFILE;
	}

	WARN_ON(!uprobe_filter_is_empty(&tu->filter));

	if (enabled)
		return 0;

	ret = uprobe_buffer_enable();
	if (ret)
		goto err_flags;

	tu->consumer.filter = filter;
	ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
	if (ret) {
	if (ret)
		goto err_buffer;

	return 0;

 err_buffer:
	uprobe_buffer_disable();

 err_flags:
	if (file) {
		list_del(&link->list);
		kfree(link);
		tu->tp.flags &= ~TP_FLAG_TRACE;
		} else
	} else {
		tu->tp.flags &= ~TP_FLAG_PROFILE;
	}

	return ret;
}

@@ -1201,12 +1215,6 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)

	current->utask->vaddr = (unsigned long) &udd;

#ifdef CONFIG_PERF_EVENTS
	if ((tu->tp.flags & TP_FLAG_TRACE) == 0 &&
	    !uprobe_perf_filter(&tu->consumer, 0, current->mm))
		return UPROBE_HANDLER_REMOVE;
#endif

	if (WARN_ON_ONCE(!uprobe_cpu_buffer))
		return 0;