Skip to content

Commit

Permalink
Merge branch 'tracing-fixes-for-linus' of git://git.kernel.org/pub/sc…
Browse files Browse the repository at this point in the history
…m/linux/kernel/git/tip/linux-2.6-tip

* 'tracing-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  tracing, ring-buffer: add paranoid checks for loops
  ftrace: use kretprobe trampoline name to test in output
  tracing, alpha: undefined reference to `save_stack_trace'
  • Loading branch information
Linus Torvalds committed Nov 3, 2008
2 parents da4a22c + 818e3dd commit 457d2ee
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 19 deletions.
2 changes: 1 addition & 1 deletion kernel/trace/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ config TRACING
bool
select DEBUG_FS
select RING_BUFFER
select STACKTRACE
select STACKTRACE if STACKTRACE_SUPPORT
select TRACEPOINTS
select NOP_TRACER

Expand Down
56 changes: 56 additions & 0 deletions kernel/trace/ring_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1022,8 +1022,23 @@ rb_reserve_next_event(struct ring_buffer_per_cpu *cpu_buffer,
struct ring_buffer_event *event;
u64 ts, delta;
int commit = 0;
int nr_loops = 0;

again:
/*
* We allow for interrupts to reenter here and do a trace.
* If one does, it will cause this original code to loop
* back here. Even with heavy interrupts happening, this
* should only happen a few times in a row. If this happens
* 1000 times in a row, there must be either an interrupt
* storm or we have something buggy.
* Bail!
*/
if (unlikely(++nr_loops > 1000)) {
RB_WARN_ON(cpu_buffer, 1);
return NULL;
}

ts = ring_buffer_time_stamp(cpu_buffer->cpu);

/*
Expand Down Expand Up @@ -1532,10 +1547,23 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
{
struct buffer_page *reader = NULL;
unsigned long flags;
int nr_loops = 0;

spin_lock_irqsave(&cpu_buffer->lock, flags);

again:
/*
* This should normally only loop twice. But because the
* start of the reader inserts an empty page, it causes
* a case where we will loop three times. There should be no
* reason to loop four times (that I know of).
*/
if (unlikely(++nr_loops > 3)) {
RB_WARN_ON(cpu_buffer, 1);
reader = NULL;
goto out;
}

reader = cpu_buffer->reader_page;

/* If there's more to read, return this page */
Expand Down Expand Up @@ -1665,13 +1693,27 @@ ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
struct ring_buffer_per_cpu *cpu_buffer;
struct ring_buffer_event *event;
struct buffer_page *reader;
int nr_loops = 0;

if (!cpu_isset(cpu, buffer->cpumask))
return NULL;

cpu_buffer = buffer->buffers[cpu];

again:
/*
* We repeat when a timestamp is encountered. It is possible
* to get multiple timestamps from an interrupt entering just
* as one timestamp is about to be written. The max times
* that this can happen is the number of nested interrupts we
* can have. Nesting 10 deep of interrupts is clearly
* an anomaly.
*/
if (unlikely(++nr_loops > 10)) {
RB_WARN_ON(cpu_buffer, 1);
return NULL;
}

reader = rb_get_reader_page(cpu_buffer);
if (!reader)
return NULL;
Expand Down Expand Up @@ -1722,6 +1764,7 @@ ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
struct ring_buffer *buffer;
struct ring_buffer_per_cpu *cpu_buffer;
struct ring_buffer_event *event;
int nr_loops = 0;

if (ring_buffer_iter_empty(iter))
return NULL;
Expand All @@ -1730,6 +1773,19 @@ ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
buffer = cpu_buffer->buffer;

again:
/*
* We repeat when a timestamp is encountered. It is possible
* to get multiple timestamps from an interrupt entering just
* as one timestamp is about to be written. The max times
* that this can happen is the number of nested interrupts we
* can have. Nesting 10 deep of interrupts is clearly
* an anomaly.
*/
if (unlikely(++nr_loops > 10)) {
RB_WARN_ON(cpu_buffer, 1);
return NULL;
}

if (rb_per_cpu_empty(cpu_buffer))
return NULL;

Expand Down
41 changes: 23 additions & 18 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,7 @@ static void ftrace_trace_stack(struct trace_array *tr,
unsigned long flags,
int skip, int pc)
{
#ifdef CONFIG_STACKTRACE
struct ring_buffer_event *event;
struct stack_entry *entry;
struct stack_trace trace;
Expand All @@ -730,6 +731,7 @@ static void ftrace_trace_stack(struct trace_array *tr,

save_stack_trace(&trace);
ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
#endif
}

void __trace_stack(struct trace_array *tr,
Expand Down Expand Up @@ -1086,17 +1088,20 @@ static void s_stop(struct seq_file *m, void *p)
mutex_unlock(&trace_types_lock);
}

#define KRETPROBE_MSG "[unknown/kretprobe'd]"

#ifdef CONFIG_KRETPROBES
static inline int kretprobed(unsigned long addr)
static inline const char *kretprobed(const char *name)
{
return addr == (unsigned long)kretprobe_trampoline;
static const char tramp_name[] = "kretprobe_trampoline";
int size = sizeof(tramp_name);

if (strncmp(tramp_name, name, size) == 0)
return "[unknown/kretprobe'd]";
return name;
}
#else
static inline int kretprobed(unsigned long addr)
static inline const char *kretprobed(const char *name)
{
return 0;
return name;
}
#endif /* CONFIG_KRETPROBES */

Expand All @@ -1105,10 +1110,13 @@ seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
{
#ifdef CONFIG_KALLSYMS
char str[KSYM_SYMBOL_LEN];
const char *name;

kallsyms_lookup(address, NULL, NULL, NULL, str);

return trace_seq_printf(s, fmt, str);
name = kretprobed(str);

return trace_seq_printf(s, fmt, name);
#endif
return 1;
}
Expand All @@ -1119,9 +1127,12 @@ seq_print_sym_offset(struct trace_seq *s, const char *fmt,
{
#ifdef CONFIG_KALLSYMS
char str[KSYM_SYMBOL_LEN];
const char *name;

sprint_symbol(str, address);
return trace_seq_printf(s, fmt, str);
name = kretprobed(str);

return trace_seq_printf(s, fmt, name);
#endif
return 1;
}
Expand Down Expand Up @@ -1375,10 +1386,7 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)

seq_print_ip_sym(s, field->ip, sym_flags);
trace_seq_puts(s, " (");
if (kretprobed(field->parent_ip))
trace_seq_puts(s, KRETPROBE_MSG);
else
seq_print_ip_sym(s, field->parent_ip, sym_flags);
seq_print_ip_sym(s, field->parent_ip, sym_flags);
trace_seq_puts(s, ")\n");
break;
}
Expand Down Expand Up @@ -1494,12 +1502,9 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
ret = trace_seq_printf(s, " <-");
if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
if (kretprobed(field->parent_ip))
ret = trace_seq_puts(s, KRETPROBE_MSG);
else
ret = seq_print_ip_sym(s,
field->parent_ip,
sym_flags);
ret = seq_print_ip_sym(s,
field->parent_ip,
sym_flags);
if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
}
Expand Down

0 comments on commit 457d2ee

Please sign in to comment.