Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 169730
b: refs/heads/master
c: ce71b9d
h: refs/heads/master
v: v3
  • Loading branch information
Frederic Weisbecker authored and Ingo Molnar committed Nov 22, 2009
1 parent 68816f8 commit 31d2609
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 108 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e25613683bd5c46d3e8c8ae6416dccc9f357dcdc
refs/heads/master: ce71b9df8893ec954e56c5979df6da274f20f65e
9 changes: 2 additions & 7 deletions trunk/include/linux/ftrace_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,8 @@ struct ftrace_event_call {

#define FTRACE_MAX_PROFILE_SIZE 2048

struct perf_trace_buf {
char buf[FTRACE_MAX_PROFILE_SIZE];
int recursion;
};

extern struct perf_trace_buf *perf_trace_buf;
extern struct perf_trace_buf *perf_trace_buf_nmi;
extern char *perf_trace_buf;
extern char *perf_trace_buf_nmi;

#define MAX_FILTER_PRED 32
#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */
Expand Down
4 changes: 4 additions & 0 deletions trunk/include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,8 @@ extern int perf_output_begin(struct perf_output_handle *handle,
extern void perf_output_end(struct perf_output_handle *handle);
extern void perf_output_copy(struct perf_output_handle *handle,
const void *buf, unsigned int len);
extern int perf_swevent_get_recursion_context(int **recursion);
extern void perf_swevent_put_recursion_context(int *recursion);
#else
static inline void
perf_event_task_sched_in(struct task_struct *task, int cpu) { }
Expand Down Expand Up @@ -902,6 +904,8 @@ static inline void perf_event_mmap(struct vm_area_struct *vma) { }
static inline void perf_event_comm(struct task_struct *tsk) { }
static inline void perf_event_fork(struct task_struct *tsk) { }
static inline void perf_event_init(void) { }
static int perf_swevent_get_recursion_context(int **recursion) { return -1; }
static void perf_swevent_put_recursion_context(int *recursion) { }

#endif

Expand Down
23 changes: 12 additions & 11 deletions trunk/include/trace/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,16 +724,19 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
static void ftrace_profile_##call(proto) \
{ \
struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
extern int perf_swevent_get_recursion_context(int **recursion); \
extern void perf_swevent_put_recursion_context(int *recursion); \
struct ftrace_event_call *event_call = &event_##call; \
extern void perf_tp_event(int, u64, u64, void *, int); \
struct ftrace_raw_##call *entry; \
struct perf_trace_buf *trace_buf; \
u64 __addr = 0, __count = 1; \
unsigned long irq_flags; \
struct trace_entry *ent; \
int __entry_size; \
int __data_size; \
char *trace_buf; \
char *raw_data; \
int *recursion; \
int __cpu; \
int pc; \
\
Expand All @@ -749,6 +752,10 @@ static void ftrace_profile_##call(proto) \
return; \
\
local_irq_save(irq_flags); \
\
if (perf_swevent_get_recursion_context(&recursion)) \
goto end_recursion; \
\
__cpu = smp_processor_id(); \
\
if (in_nmi()) \
Expand All @@ -759,13 +766,7 @@ static void ftrace_profile_##call(proto) \
if (!trace_buf) \
goto end; \
\
trace_buf = per_cpu_ptr(trace_buf, __cpu); \
if (trace_buf->recursion++) \
goto end_recursion; \
\
barrier(); \
\
raw_data = trace_buf->buf; \
raw_data = per_cpu_ptr(trace_buf, __cpu); \
\
*(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \
entry = (struct ftrace_raw_##call *)raw_data; \
Expand All @@ -780,9 +781,9 @@ static void ftrace_profile_##call(proto) \
perf_tp_event(event_call->id, __addr, __count, entry, \
__entry_size); \
\
end_recursion: \
trace_buf->recursion--; \
end: \
end: \
perf_swevent_put_recursion_context(recursion); \
end_recursion: \
local_irq_restore(irq_flags); \
\
}
Expand Down
68 changes: 45 additions & 23 deletions trunk/kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -3880,34 +3880,42 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx,
}
}

static int *perf_swevent_recursion_context(struct perf_cpu_context *cpuctx)
/*
* Must be called with preemption disabled
*/
int perf_swevent_get_recursion_context(int **recursion)
{
struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);

if (in_nmi())
return &cpuctx->recursion[3];
*recursion = &cpuctx->recursion[3];
else if (in_irq())
*recursion = &cpuctx->recursion[2];
else if (in_softirq())
*recursion = &cpuctx->recursion[1];
else
*recursion = &cpuctx->recursion[0];

if (in_irq())
return &cpuctx->recursion[2];
if (**recursion)
return -1;

if (in_softirq())
return &cpuctx->recursion[1];
(**recursion)++;

return &cpuctx->recursion[0];
return 0;
}

static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
u64 nr, int nmi,
struct perf_sample_data *data,
struct pt_regs *regs)
void perf_swevent_put_recursion_context(int *recursion)
{
struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context);
int *recursion = perf_swevent_recursion_context(cpuctx);
struct perf_event_context *ctx;

if (*recursion)
goto out;
(*recursion)--;
}

(*recursion)++;
barrier();
static void __do_perf_sw_event(enum perf_type_id type, u32 event_id,
u64 nr, int nmi,
struct perf_sample_data *data,
struct pt_regs *regs)
{
struct perf_event_context *ctx;
struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);

rcu_read_lock();
perf_swevent_ctx_event(&cpuctx->ctx, type, event_id,
Expand All @@ -3920,12 +3928,25 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
if (ctx)
perf_swevent_ctx_event(ctx, type, event_id, nr, nmi, data, regs);
rcu_read_unlock();
}

barrier();
(*recursion)--;
static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
u64 nr, int nmi,
struct perf_sample_data *data,
struct pt_regs *regs)
{
int *recursion;

preempt_disable();

if (perf_swevent_get_recursion_context(&recursion))
goto out;

__do_perf_sw_event(type, event_id, nr, nmi, data, regs);

perf_swevent_put_recursion_context(recursion);
out:
put_cpu_var(perf_cpu_context);
preempt_enable();
}

void __perf_sw_event(u32 event_id, u64 nr, int nmi,
Expand Down Expand Up @@ -4159,7 +4180,8 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
if (!regs)
regs = task_pt_regs(current);

do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1,
/* Trace events already protected against recursion */
__do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1,
&data, regs);
}
EXPORT_SYMBOL_GPL(perf_tp_event);
Expand Down
14 changes: 8 additions & 6 deletions trunk/kernel/trace/trace_event_profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,33 @@
#include "trace.h"


struct perf_trace_buf *perf_trace_buf;
char *perf_trace_buf;
EXPORT_SYMBOL_GPL(perf_trace_buf);

struct perf_trace_buf *perf_trace_buf_nmi;
char *perf_trace_buf_nmi;
EXPORT_SYMBOL_GPL(perf_trace_buf_nmi);

typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ;

/* Count the events in use (per event id, not per instance) */
static int total_profile_count;

static int ftrace_profile_enable_event(struct ftrace_event_call *event)
{
struct perf_trace_buf *buf;
char *buf;
int ret = -ENOMEM;

if (atomic_inc_return(&event->profile_count))
return 0;

if (!total_profile_count) {
buf = alloc_percpu(struct perf_trace_buf);
buf = (char *)alloc_percpu(perf_trace_t);
if (!buf)
goto fail_buf;

rcu_assign_pointer(perf_trace_buf, buf);

buf = alloc_percpu(struct perf_trace_buf);
buf = (char *)alloc_percpu(perf_trace_t);
if (!buf)
goto fail_buf_nmi;

Expand Down Expand Up @@ -79,7 +81,7 @@ int ftrace_profile_enable(int event_id)

static void ftrace_profile_disable_event(struct ftrace_event_call *event)
{
struct perf_trace_buf *buf, *nmi_buf;
char *buf, *nmi_buf;

if (!atomic_add_negative(-1, &event->profile_count))
return;
Expand Down
48 changes: 18 additions & 30 deletions trunk/kernel/trace/trace_kprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1208,11 +1208,12 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp,
struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
struct ftrace_event_call *call = &tp->call;
struct kprobe_trace_entry *entry;
struct perf_trace_buf *trace_buf;
struct trace_entry *ent;
int size, __size, i, pc, __cpu;
unsigned long irq_flags;
char *trace_buf;
char *raw_data;
int *recursion;

pc = preempt_count();
__size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args);
Expand All @@ -1227,6 +1228,10 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp,
* This also protects the rcu read side
*/
local_irq_save(irq_flags);

if (perf_swevent_get_recursion_context(&recursion))
goto end_recursion;

__cpu = smp_processor_id();

if (in_nmi())
Expand All @@ -1237,18 +1242,7 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp,
if (!trace_buf)
goto end;

trace_buf = per_cpu_ptr(trace_buf, __cpu);

if (trace_buf->recursion++)
goto end_recursion;

/*
* Make recursion update visible before entering perf_tp_event
* so that we protect from perf recursions.
*/
barrier();

raw_data = trace_buf->buf;
raw_data = per_cpu_ptr(trace_buf, __cpu);

/* Zero dead bytes from alignment to avoid buffer leak to userspace */
*(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
Expand All @@ -1263,9 +1257,9 @@ static __kprobes int kprobe_profile_func(struct kprobe *kp,
entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
perf_tp_event(call->id, entry->ip, 1, entry, size);

end_recursion:
trace_buf->recursion--;
end:
perf_swevent_put_recursion_context(recursion);
end_recursion:
local_irq_restore(irq_flags);

return 0;
Expand All @@ -1278,10 +1272,11 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
struct ftrace_event_call *call = &tp->call;
struct kretprobe_trace_entry *entry;
struct perf_trace_buf *trace_buf;
struct trace_entry *ent;
int size, __size, i, pc, __cpu;
unsigned long irq_flags;
char *trace_buf;
int *recursion;
char *raw_data;

pc = preempt_count();
Expand All @@ -1297,6 +1292,10 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
* This also protects the rcu read side
*/
local_irq_save(irq_flags);

if (perf_swevent_get_recursion_context(&recursion))
goto end_recursion;

__cpu = smp_processor_id();

if (in_nmi())
Expand All @@ -1307,18 +1306,7 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
if (!trace_buf)
goto end;

trace_buf = per_cpu_ptr(trace_buf, __cpu);

if (trace_buf->recursion++)
goto end_recursion;

/*
* Make recursion update visible before entering perf_tp_event
* so that we protect from perf recursions.
*/
barrier();

raw_data = trace_buf->buf;
raw_data = per_cpu_ptr(trace_buf, __cpu);

/* Zero dead bytes from alignment to avoid buffer leak to userspace */
*(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
Expand All @@ -1334,9 +1322,9 @@ static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
perf_tp_event(call->id, entry->ret_ip, 1, entry, size);

end_recursion:
trace_buf->recursion--;
end:
perf_swevent_put_recursion_context(recursion);
end_recursion:
local_irq_restore(irq_flags);

return 0;
Expand Down
Loading

0 comments on commit 31d2609

Please sign in to comment.