Skip to content

Commit

Permalink
Merge tag 'trace-fixes-v3.16-rc3' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/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"
  • Loading branch information
Linus Torvalds committed Jul 4, 2014
2 parents af6f157 + 099ed15 commit ef34c6c
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 24 deletions.
6 changes: 3 additions & 3 deletions kernel/events/uprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down
46 changes: 27 additions & 19 deletions kernel/trace/trace_uprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 (file) {
list_del(&link->list);
kfree(link);
tu->tp.flags &= ~TP_FLAG_TRACE;
} else
tu->tp.flags &= ~TP_FLAG_PROFILE;
}
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 {
tu->tp.flags &= ~TP_FLAG_PROFILE;
}
return ret;
}

Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit ef34c6c

Please sign in to comment.