Commit ef34c6ce authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -846,7 +846,7 @@ static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *u ...@@ -846,7 +846,7 @@ static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *u
{ {
int err; int err;
if (!consumer_del(uprobe, uc)) /* WARN? */ if (WARN_ON(!consumer_del(uprobe, uc)))
return; return;
err = register_for_each_vma(uprobe, NULL); err = register_for_each_vma(uprobe, NULL);
...@@ -927,7 +927,7 @@ int uprobe_apply(struct inode *inode, loff_t offset, ...@@ -927,7 +927,7 @@ int uprobe_apply(struct inode *inode, loff_t offset,
int ret = -ENOENT; int ret = -ENOENT;
uprobe = find_uprobe(inode, offset); uprobe = find_uprobe(inode, offset);
if (!uprobe) if (WARN_ON(!uprobe))
return ret; return ret;
down_write(&uprobe->register_rwsem); down_write(&uprobe->register_rwsem);
...@@ -952,7 +952,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume ...@@ -952,7 +952,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
struct uprobe *uprobe; struct uprobe *uprobe;
uprobe = find_uprobe(inode, offset); uprobe = find_uprobe(inode, offset);
if (!uprobe) if (WARN_ON(!uprobe))
return; return;
down_write(&uprobe->register_rwsem); down_write(&uprobe->register_rwsem);
......
...@@ -1396,7 +1396,6 @@ void tracing_start(void) ...@@ -1396,7 +1396,6 @@ void tracing_start(void)
arch_spin_unlock(&global_trace.max_lock); arch_spin_unlock(&global_trace.max_lock);
ftrace_start();
out: out:
raw_spin_unlock_irqrestore(&global_trace.start_lock, flags); raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);
} }
...@@ -1443,7 +1442,6 @@ void tracing_stop(void) ...@@ -1443,7 +1442,6 @@ void tracing_stop(void)
struct ring_buffer *buffer; struct ring_buffer *buffer;
unsigned long flags; unsigned long flags;
ftrace_stop();
raw_spin_lock_irqsave(&global_trace.start_lock, flags); raw_spin_lock_irqsave(&global_trace.start_lock, flags);
if (global_trace.stop_count++) if (global_trace.stop_count++)
goto out; goto out;
......
...@@ -893,6 +893,9 @@ probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file, ...@@ -893,6 +893,9 @@ probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file,
int ret; int ret;
if (file) { if (file) {
if (tu->tp.flags & TP_FLAG_PROFILE)
return -EINTR;
link = kmalloc(sizeof(*link), GFP_KERNEL); link = kmalloc(sizeof(*link), GFP_KERNEL);
if (!link) if (!link)
return -ENOMEM; return -ENOMEM;
...@@ -901,29 +904,40 @@ probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file, ...@@ -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); list_add_tail_rcu(&link->list, &tu->tp.files);
tu->tp.flags |= TP_FLAG_TRACE; tu->tp.flags |= TP_FLAG_TRACE;
} else } else {
tu->tp.flags |= TP_FLAG_PROFILE; if (tu->tp.flags & TP_FLAG_TRACE)
return -EINTR;
ret = uprobe_buffer_enable(); tu->tp.flags |= TP_FLAG_PROFILE;
if (ret < 0) }
return ret;
WARN_ON(!uprobe_filter_is_empty(&tu->filter)); WARN_ON(!uprobe_filter_is_empty(&tu->filter));
if (enabled) if (enabled)
return 0; return 0;
ret = uprobe_buffer_enable();
if (ret)
goto err_flags;
tu->consumer.filter = filter; tu->consumer.filter = filter;
ret = uprobe_register(tu->inode, tu->offset, &tu->consumer); ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
if (ret) { if (ret)
if (file) { goto err_buffer;
list_del(&link->list);
kfree(link);
tu->tp.flags &= ~TP_FLAG_TRACE;
} else
tu->tp.flags &= ~TP_FLAG_PROFILE;
}
return 0;
err_buffer:
uprobe_buffer_disable();
err_flags:
if (file) {
list_del(&link->list);
kfree(link);
tu->tp.flags &= ~TP_FLAG_TRACE;
} else {
tu->tp.flags &= ~TP_FLAG_PROFILE;
}
return ret; return ret;
} }
...@@ -1201,12 +1215,6 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) ...@@ -1201,12 +1215,6 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
current->utask->vaddr = (unsigned long) &udd; 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)) if (WARN_ON_ONCE(!uprobe_cpu_buffer))
return 0; return 0;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment