Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (184 commits) perf probe: Clean up probe_point_lazy_walker() return value tracing: Fix irqoff selftest expanding max buffer tracing: Align 4 byte ints together in struct tracer tracing: Export trace_set_clr_event() tracing: Explain about unstable clock on resume with ring buffer warning ftrace/graph: Trace function entry before updating index ftrace: Add .ref.text as one of the safe areas to trace tracing: Adjust conditional expression latency formatting. tracing: Fix event alignment: skb:kfree_skb tracing: Fix event alignment: mce:mce_record tracing: Fix event alignment: kvm:kvm_hv_hypercall tracing: Fix event alignment: module:module_request tracing: Fix event alignment: ftrace:context_switch and ftrace:wakeup tracing: Remove lock_depth from event entry perf header: Stop using 'self' perf session: Use evlist/evsel for managing perf.data attributes perf top: Don't let events to eat up whole header line perf top: Fix events overflow in top command ring-buffer: Remove unused #include <linux/trace_irq.h> tracing: Add an 'overwrite' trace_option. ...
This commit is contained in:
@@ -4230,20 +4230,8 @@ void cgroup_post_fork(struct task_struct *child)
|
||||
*/
|
||||
void cgroup_exit(struct task_struct *tsk, int run_callbacks)
|
||||
{
|
||||
int i;
|
||||
struct css_set *cg;
|
||||
|
||||
if (run_callbacks && need_forkexit_callback) {
|
||||
/*
|
||||
* modular subsystems can't use callbacks, so no need to lock
|
||||
* the subsys array
|
||||
*/
|
||||
for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
|
||||
struct cgroup_subsys *ss = subsys[i];
|
||||
if (ss->exit)
|
||||
ss->exit(ss, tsk);
|
||||
}
|
||||
}
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Unlink from the css_set task list if necessary.
|
||||
@@ -4261,7 +4249,24 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
|
||||
task_lock(tsk);
|
||||
cg = tsk->cgroups;
|
||||
tsk->cgroups = &init_css_set;
|
||||
|
||||
if (run_callbacks && need_forkexit_callback) {
|
||||
/*
|
||||
* modular subsystems can't use callbacks, so no need to lock
|
||||
* the subsys array
|
||||
*/
|
||||
for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
|
||||
struct cgroup_subsys *ss = subsys[i];
|
||||
if (ss->exit) {
|
||||
struct cgroup *old_cgrp =
|
||||
rcu_dereference_raw(cg->subsys[i])->cgroup;
|
||||
struct cgroup *cgrp = task_cgroup(tsk, i);
|
||||
ss->exit(ss, cgrp, old_cgrp, tsk);
|
||||
}
|
||||
}
|
||||
}
|
||||
task_unlock(tsk);
|
||||
|
||||
if (cg)
|
||||
put_css_set_taskexit(cg);
|
||||
}
|
||||
@@ -4813,6 +4818,29 @@ css_get_next(struct cgroup_subsys *ss, int id,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* get corresponding css from file open on cgroupfs directory
|
||||
*/
|
||||
struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id)
|
||||
{
|
||||
struct cgroup *cgrp;
|
||||
struct inode *inode;
|
||||
struct cgroup_subsys_state *css;
|
||||
|
||||
inode = f->f_dentry->d_inode;
|
||||
/* check in cgroup filesystem dir */
|
||||
if (inode->i_op != &cgroup_dir_inode_operations)
|
||||
return ERR_PTR(-EBADF);
|
||||
|
||||
if (id < 0 || id >= CGROUP_SUBSYS_COUNT)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* get cgroup */
|
||||
cgrp = __d_cgrp(f->f_dentry);
|
||||
css = cgrp->subsys[id];
|
||||
return css ? css : ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CGROUP_DEBUG
|
||||
static struct cgroup_subsys_state *debug_create(struct cgroup_subsys *ss,
|
||||
struct cgroup *cont)
|
||||
|
1004
kernel/perf_event.c
1004
kernel/perf_event.c
File diff suppressed because it is too large
Load Diff
@@ -606,9 +606,6 @@ static inline struct task_group *task_group(struct task_struct *p)
|
||||
struct task_group *tg;
|
||||
struct cgroup_subsys_state *css;
|
||||
|
||||
if (p->flags & PF_EXITING)
|
||||
return &root_task_group;
|
||||
|
||||
css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
|
||||
lockdep_is_held(&task_rq(p)->lock));
|
||||
tg = container_of(css, struct task_group, css);
|
||||
@@ -2265,27 +2262,6 @@ void kick_process(struct task_struct *p)
|
||||
EXPORT_SYMBOL_GPL(kick_process);
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
/**
|
||||
* task_oncpu_function_call - call a function on the cpu on which a task runs
|
||||
* @p: the task to evaluate
|
||||
* @func: the function to be called
|
||||
* @info: the function call argument
|
||||
*
|
||||
* Calls the function @func when the task is currently running. This might
|
||||
* be on the current CPU, which just calls the function directly
|
||||
*/
|
||||
void task_oncpu_function_call(struct task_struct *p,
|
||||
void (*func) (void *info), void *info)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
preempt_disable();
|
||||
cpu = task_cpu(p);
|
||||
if (task_curr(p))
|
||||
smp_call_function_single(cpu, func, info, 1);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* ->cpus_allowed is protected by either TASK_WAKING or rq->lock held.
|
||||
@@ -2776,9 +2752,12 @@ static inline void
|
||||
prepare_task_switch(struct rq *rq, struct task_struct *prev,
|
||||
struct task_struct *next)
|
||||
{
|
||||
sched_info_switch(prev, next);
|
||||
perf_event_task_sched_out(prev, next);
|
||||
fire_sched_out_preempt_notifiers(prev, next);
|
||||
prepare_lock_switch(rq, next);
|
||||
prepare_arch_switch(next);
|
||||
trace_sched_switch(prev, next);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2911,7 +2890,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
|
||||
struct mm_struct *mm, *oldmm;
|
||||
|
||||
prepare_task_switch(rq, prev, next);
|
||||
trace_sched_switch(prev, next);
|
||||
|
||||
mm = next->mm;
|
||||
oldmm = prev->active_mm;
|
||||
/*
|
||||
@@ -3989,9 +3968,6 @@ need_resched_nonpreemptible:
|
||||
rq->skip_clock_update = 0;
|
||||
|
||||
if (likely(prev != next)) {
|
||||
sched_info_switch(prev, next);
|
||||
perf_event_task_sched_out(prev, next);
|
||||
|
||||
rq->nr_switches++;
|
||||
rq->curr = next;
|
||||
++*switch_count;
|
||||
@@ -5572,7 +5548,7 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
|
||||
* The idle tasks have their own, simple scheduling class:
|
||||
*/
|
||||
idle->sched_class = &idle_sched_class;
|
||||
ftrace_graph_init_task(idle);
|
||||
ftrace_graph_init_idle_task(idle, cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -8885,7 +8861,8 @@ cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_cgroup_exit(struct cgroup_subsys *ss, struct task_struct *task)
|
||||
cpu_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
||||
struct cgroup *old_cgrp, struct task_struct *task)
|
||||
{
|
||||
/*
|
||||
* cgroup_exit() is called in the copy_process() failure path.
|
||||
|
@@ -948,7 +948,7 @@ static struct ctl_table kern_table[] = {
|
||||
.data = &sysctl_perf_event_sample_rate,
|
||||
.maxlen = sizeof(sysctl_perf_event_sample_rate),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
.proc_handler = perf_proc_update_handler,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_KMEMCHECK
|
||||
|
@@ -3328,7 +3328,7 @@ static int start_graph_tracing(void)
|
||||
/* The cpu_boot init_task->ret_stack will never be freed */
|
||||
for_each_online_cpu(cpu) {
|
||||
if (!idle_task(cpu)->ret_stack)
|
||||
ftrace_graph_init_task(idle_task(cpu));
|
||||
ftrace_graph_init_idle_task(idle_task(cpu), cpu);
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -3418,6 +3418,49 @@ void unregister_ftrace_graph(void)
|
||||
mutex_unlock(&ftrace_lock);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct ftrace_ret_stack *, idle_ret_stack);
|
||||
|
||||
static void
|
||||
graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack)
|
||||
{
|
||||
atomic_set(&t->tracing_graph_pause, 0);
|
||||
atomic_set(&t->trace_overrun, 0);
|
||||
t->ftrace_timestamp = 0;
|
||||
/* make curr_ret_stack visable before we add the ret_stack */
|
||||
smp_wmb();
|
||||
t->ret_stack = ret_stack;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a return stack for the idle task. May be the first
|
||||
* time through, or it may be done by CPU hotplug online.
|
||||
*/
|
||||
void ftrace_graph_init_idle_task(struct task_struct *t, int cpu)
|
||||
{
|
||||
t->curr_ret_stack = -1;
|
||||
/*
|
||||
* The idle task has no parent, it either has its own
|
||||
* stack or no stack at all.
|
||||
*/
|
||||
if (t->ret_stack)
|
||||
WARN_ON(t->ret_stack != per_cpu(idle_ret_stack, cpu));
|
||||
|
||||
if (ftrace_graph_active) {
|
||||
struct ftrace_ret_stack *ret_stack;
|
||||
|
||||
ret_stack = per_cpu(idle_ret_stack, cpu);
|
||||
if (!ret_stack) {
|
||||
ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH
|
||||
* sizeof(struct ftrace_ret_stack),
|
||||
GFP_KERNEL);
|
||||
if (!ret_stack)
|
||||
return;
|
||||
per_cpu(idle_ret_stack, cpu) = ret_stack;
|
||||
}
|
||||
graph_init_task(t, ret_stack);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate a return stack for newly created task */
|
||||
void ftrace_graph_init_task(struct task_struct *t)
|
||||
{
|
||||
@@ -3433,12 +3476,7 @@ void ftrace_graph_init_task(struct task_struct *t)
|
||||
GFP_KERNEL);
|
||||
if (!ret_stack)
|
||||
return;
|
||||
atomic_set(&t->tracing_graph_pause, 0);
|
||||
atomic_set(&t->trace_overrun, 0);
|
||||
t->ftrace_timestamp = 0;
|
||||
/* make curr_ret_stack visable before we add the ret_stack */
|
||||
smp_wmb();
|
||||
t->ret_stack = ret_stack;
|
||||
graph_init_task(t, ret_stack);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
#include <linux/ring_buffer.h>
|
||||
#include <linux/trace_clock.h>
|
||||
#include <linux/ftrace_irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
@@ -1429,6 +1428,17 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ring_buffer_resize);
|
||||
|
||||
void ring_buffer_change_overwrite(struct ring_buffer *buffer, int val)
|
||||
{
|
||||
mutex_lock(&buffer->mutex);
|
||||
if (val)
|
||||
buffer->flags |= RB_FL_OVERWRITE;
|
||||
else
|
||||
buffer->flags &= ~RB_FL_OVERWRITE;
|
||||
mutex_unlock(&buffer->mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ring_buffer_change_overwrite);
|
||||
|
||||
static inline void *
|
||||
__rb_data_page_index(struct buffer_data_page *bpage, unsigned index)
|
||||
{
|
||||
@@ -2162,11 +2172,19 @@ rb_reserve_next_event(struct ring_buffer *buffer,
|
||||
if (likely(ts >= cpu_buffer->write_stamp)) {
|
||||
delta = diff;
|
||||
if (unlikely(test_time_stamp(delta))) {
|
||||
int local_clock_stable = 1;
|
||||
#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
|
||||
local_clock_stable = sched_clock_stable;
|
||||
#endif
|
||||
WARN_ONCE(delta > (1ULL << 59),
|
||||
KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n",
|
||||
KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s",
|
||||
(unsigned long long)delta,
|
||||
(unsigned long long)ts,
|
||||
(unsigned long long)cpu_buffer->write_stamp);
|
||||
(unsigned long long)cpu_buffer->write_stamp,
|
||||
local_clock_stable ? "" :
|
||||
"If you just came from a suspend/resume,\n"
|
||||
"please switch to the trace global clock:\n"
|
||||
" echo global > /sys/kernel/debug/tracing/trace_clock\n");
|
||||
add_timestamp = 1;
|
||||
}
|
||||
}
|
||||
|
@@ -41,8 +41,6 @@
|
||||
#include "trace.h"
|
||||
#include "trace_output.h"
|
||||
|
||||
#define TRACE_BUFFER_FLAGS (RB_FL_OVERWRITE)
|
||||
|
||||
/*
|
||||
* On boot up, the ring buffer is set to the minimum size, so that
|
||||
* we do not waste memory on systems that are not using tracing.
|
||||
@@ -340,7 +338,7 @@ static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
|
||||
/* trace_flags holds trace_options default values */
|
||||
unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
|
||||
TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
|
||||
TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD;
|
||||
TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE;
|
||||
|
||||
static int trace_stop_count;
|
||||
static DEFINE_SPINLOCK(tracing_start_lock);
|
||||
@@ -425,6 +423,7 @@ static const char *trace_options[] = {
|
||||
"sleep-time",
|
||||
"graph-time",
|
||||
"record-cmd",
|
||||
"overwrite",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -780,6 +779,11 @@ __acquires(kernel_lock)
|
||||
tracing_reset_online_cpus(tr);
|
||||
|
||||
current_trace = type;
|
||||
|
||||
/* If we expanded the buffers, make sure the max is expanded too */
|
||||
if (ring_buffer_expanded && type->use_max_tr)
|
||||
ring_buffer_resize(max_tr.buffer, trace_buf_size);
|
||||
|
||||
/* the test is responsible for initializing and enabling */
|
||||
pr_info("Testing tracer %s: ", type->name);
|
||||
ret = type->selftest(type, tr);
|
||||
@@ -792,6 +796,10 @@ __acquires(kernel_lock)
|
||||
/* Only reset on passing, to avoid touching corrupted buffers */
|
||||
tracing_reset_online_cpus(tr);
|
||||
|
||||
/* Shrink the max buffer again */
|
||||
if (ring_buffer_expanded && type->use_max_tr)
|
||||
ring_buffer_resize(max_tr.buffer, 1);
|
||||
|
||||
printk(KERN_CONT "PASSED\n");
|
||||
}
|
||||
#endif
|
||||
@@ -1102,7 +1110,6 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
|
||||
|
||||
entry->preempt_count = pc & 0xff;
|
||||
entry->pid = (tsk) ? tsk->pid : 0;
|
||||
entry->lock_depth = (tsk) ? tsk->lock_depth : 0;
|
||||
entry->flags =
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
|
||||
(irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
|
||||
@@ -1749,10 +1756,9 @@ static void print_lat_help_header(struct seq_file *m)
|
||||
seq_puts(m, "# | / _----=> need-resched \n");
|
||||
seq_puts(m, "# || / _---=> hardirq/softirq \n");
|
||||
seq_puts(m, "# ||| / _--=> preempt-depth \n");
|
||||
seq_puts(m, "# |||| /_--=> lock-depth \n");
|
||||
seq_puts(m, "# |||||/ delay \n");
|
||||
seq_puts(m, "# cmd pid |||||| time | caller \n");
|
||||
seq_puts(m, "# \\ / |||||| \\ | / \n");
|
||||
seq_puts(m, "# |||| / delay \n");
|
||||
seq_puts(m, "# cmd pid ||||| time | caller \n");
|
||||
seq_puts(m, "# \\ / ||||| \\ | / \n");
|
||||
}
|
||||
|
||||
static void print_func_help_header(struct seq_file *m)
|
||||
@@ -2529,6 +2535,9 @@ static void set_tracer_flags(unsigned int mask, int enabled)
|
||||
|
||||
if (mask == TRACE_ITER_RECORD_CMD)
|
||||
trace_event_enable_cmd_record(enabled);
|
||||
|
||||
if (mask == TRACE_ITER_OVERWRITE)
|
||||
ring_buffer_change_overwrite(global_trace.buffer, enabled);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@@ -2710,6 +2719,10 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf,
|
||||
|
||||
mutex_lock(&trace_types_lock);
|
||||
if (tracer_enabled ^ val) {
|
||||
|
||||
/* Only need to warn if this is used to change the state */
|
||||
WARN_ONCE(1, "tracing_enabled is deprecated. Use tracing_on");
|
||||
|
||||
if (val) {
|
||||
tracer_enabled = 1;
|
||||
if (current_trace->start)
|
||||
@@ -4551,9 +4564,11 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
|
||||
__init static int tracer_alloc_buffers(void)
|
||||
{
|
||||
int ring_buf_size;
|
||||
enum ring_buffer_flags rb_flags;
|
||||
int i;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
|
||||
if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))
|
||||
goto out;
|
||||
|
||||
@@ -4566,12 +4581,13 @@ __init static int tracer_alloc_buffers(void)
|
||||
else
|
||||
ring_buf_size = 1;
|
||||
|
||||
rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
|
||||
|
||||
cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
|
||||
cpumask_copy(tracing_cpumask, cpu_all_mask);
|
||||
|
||||
/* TODO: make the number of buffers hot pluggable with CPUS */
|
||||
global_trace.buffer = ring_buffer_alloc(ring_buf_size,
|
||||
TRACE_BUFFER_FLAGS);
|
||||
global_trace.buffer = ring_buffer_alloc(ring_buf_size, rb_flags);
|
||||
if (!global_trace.buffer) {
|
||||
printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
|
||||
WARN_ON(1);
|
||||
@@ -4581,7 +4597,7 @@ __init static int tracer_alloc_buffers(void)
|
||||
|
||||
|
||||
#ifdef CONFIG_TRACER_MAX_TRACE
|
||||
max_tr.buffer = ring_buffer_alloc(1, TRACE_BUFFER_FLAGS);
|
||||
max_tr.buffer = ring_buffer_alloc(1, rb_flags);
|
||||
if (!max_tr.buffer) {
|
||||
printk(KERN_ERR "tracer: failed to allocate max ring buffer!\n");
|
||||
WARN_ON(1);
|
||||
|
@@ -272,8 +272,8 @@ struct tracer {
|
||||
/* If you handled the flag setting, return 0 */
|
||||
int (*set_flag)(u32 old_flags, u32 bit, int set);
|
||||
struct tracer *next;
|
||||
int print_max;
|
||||
struct tracer_flags *flags;
|
||||
int print_max;
|
||||
int use_max_tr;
|
||||
};
|
||||
|
||||
@@ -606,6 +606,7 @@ enum trace_iterator_flags {
|
||||
TRACE_ITER_SLEEP_TIME = 0x40000,
|
||||
TRACE_ITER_GRAPH_TIME = 0x80000,
|
||||
TRACE_ITER_RECORD_CMD = 0x100000,
|
||||
TRACE_ITER_OVERWRITE = 0x200000,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -661,8 +662,10 @@ struct ftrace_event_field {
|
||||
};
|
||||
|
||||
struct event_filter {
|
||||
int n_preds;
|
||||
struct filter_pred **preds;
|
||||
int n_preds; /* Number assigned */
|
||||
int a_preds; /* allocated */
|
||||
struct filter_pred *preds;
|
||||
struct filter_pred *root;
|
||||
char *filter_string;
|
||||
};
|
||||
|
||||
@@ -674,11 +677,23 @@ struct event_subsystem {
|
||||
int nr_events;
|
||||
};
|
||||
|
||||
#define FILTER_PRED_INVALID ((unsigned short)-1)
|
||||
#define FILTER_PRED_IS_RIGHT (1 << 15)
|
||||
#define FILTER_PRED_FOLD (1 << 15)
|
||||
|
||||
/*
|
||||
* The max preds is the size of unsigned short with
|
||||
* two flags at the MSBs. One bit is used for both the IS_RIGHT
|
||||
* and FOLD flags. The other is reserved.
|
||||
*
|
||||
* 2^14 preds is way more than enough.
|
||||
*/
|
||||
#define MAX_FILTER_PRED 16384
|
||||
|
||||
struct filter_pred;
|
||||
struct regex;
|
||||
|
||||
typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
|
||||
int val1, int val2);
|
||||
typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event);
|
||||
|
||||
typedef int (*regex_match_func)(char *str, struct regex *r, int len);
|
||||
|
||||
@@ -700,11 +715,23 @@ struct filter_pred {
|
||||
filter_pred_fn_t fn;
|
||||
u64 val;
|
||||
struct regex regex;
|
||||
char *field_name;
|
||||
/*
|
||||
* Leaf nodes use field_name, ops is used by AND and OR
|
||||
* nodes. The field_name is always freed when freeing a pred.
|
||||
* We can overload field_name for ops and have it freed
|
||||
* as well.
|
||||
*/
|
||||
union {
|
||||
char *field_name;
|
||||
unsigned short *ops;
|
||||
};
|
||||
int offset;
|
||||
int not;
|
||||
int op;
|
||||
int pop_n;
|
||||
unsigned short index;
|
||||
unsigned short parent;
|
||||
unsigned short left;
|
||||
unsigned short right;
|
||||
};
|
||||
|
||||
extern struct list_head ftrace_common_fields;
|
||||
|
@@ -109,12 +109,12 @@ FTRACE_ENTRY(funcgraph_exit, ftrace_graph_ret_entry,
|
||||
*/
|
||||
#define FTRACE_CTX_FIELDS \
|
||||
__field( unsigned int, prev_pid ) \
|
||||
__field( unsigned int, next_pid ) \
|
||||
__field( unsigned int, next_cpu ) \
|
||||
__field( unsigned char, prev_prio ) \
|
||||
__field( unsigned char, prev_state ) \
|
||||
__field( unsigned int, next_pid ) \
|
||||
__field( unsigned char, next_prio ) \
|
||||
__field( unsigned char, next_state ) \
|
||||
__field( unsigned int, next_cpu )
|
||||
__field( unsigned char, next_state )
|
||||
|
||||
FTRACE_ENTRY(context_switch, ctx_switch_entry,
|
||||
|
||||
|
@@ -116,7 +116,6 @@ static int trace_define_common_fields(void)
|
||||
__common_field(unsigned char, flags);
|
||||
__common_field(unsigned char, preempt_count);
|
||||
__common_field(int, pid);
|
||||
__common_field(int, lock_depth);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -326,6 +325,7 @@ int trace_set_clr_event(const char *system, const char *event, int set)
|
||||
{
|
||||
return __ftrace_set_clr_event(NULL, system, event, set);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(trace_set_clr_event);
|
||||
|
||||
/* 128 should be much more than enough */
|
||||
#define EVENT_BUF_SIZE 127
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -353,6 +353,43 @@ static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
/* Bitfield fetch function */
|
||||
struct bitfield_fetch_param {
|
||||
struct fetch_param orig;
|
||||
unsigned char hi_shift;
|
||||
unsigned char low_shift;
|
||||
};
|
||||
|
||||
#define DEFINE_FETCH_bitfield(type) \
|
||||
static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\
|
||||
void *data, void *dest) \
|
||||
{ \
|
||||
struct bitfield_fetch_param *bprm = data; \
|
||||
type buf = 0; \
|
||||
call_fetch(&bprm->orig, regs, &buf); \
|
||||
if (buf) { \
|
||||
buf <<= bprm->hi_shift; \
|
||||
buf >>= bprm->low_shift; \
|
||||
} \
|
||||
*(type *)dest = buf; \
|
||||
}
|
||||
DEFINE_BASIC_FETCH_FUNCS(bitfield)
|
||||
#define fetch_bitfield_string NULL
|
||||
#define fetch_bitfield_string_size NULL
|
||||
|
||||
static __kprobes void
|
||||
free_bitfield_fetch_param(struct bitfield_fetch_param *data)
|
||||
{
|
||||
/*
|
||||
* Don't check the bitfield itself, because this must be the
|
||||
* last fetch function.
|
||||
*/
|
||||
if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
|
||||
free_deref_fetch_param(data->orig.data);
|
||||
else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
|
||||
free_symbol_cache(data->orig.data);
|
||||
kfree(data);
|
||||
}
|
||||
/* Default (unsigned long) fetch type */
|
||||
#define __DEFAULT_FETCH_TYPE(t) u##t
|
||||
#define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
|
||||
@@ -367,6 +404,7 @@ enum {
|
||||
FETCH_MTD_memory,
|
||||
FETCH_MTD_symbol,
|
||||
FETCH_MTD_deref,
|
||||
FETCH_MTD_bitfield,
|
||||
FETCH_MTD_END,
|
||||
};
|
||||
|
||||
@@ -387,6 +425,7 @@ ASSIGN_FETCH_FUNC(retval, ftype), \
|
||||
ASSIGN_FETCH_FUNC(memory, ftype), \
|
||||
ASSIGN_FETCH_FUNC(symbol, ftype), \
|
||||
ASSIGN_FETCH_FUNC(deref, ftype), \
|
||||
ASSIGN_FETCH_FUNC(bitfield, ftype), \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -430,9 +469,33 @@ static const struct fetch_type *find_fetch_type(const char *type)
|
||||
if (!type)
|
||||
type = DEFAULT_FETCH_TYPE_STR;
|
||||
|
||||
/* Special case: bitfield */
|
||||
if (*type == 'b') {
|
||||
unsigned long bs;
|
||||
type = strchr(type, '/');
|
||||
if (!type)
|
||||
goto fail;
|
||||
type++;
|
||||
if (strict_strtoul(type, 0, &bs))
|
||||
goto fail;
|
||||
switch (bs) {
|
||||
case 8:
|
||||
return find_fetch_type("u8");
|
||||
case 16:
|
||||
return find_fetch_type("u16");
|
||||
case 32:
|
||||
return find_fetch_type("u32");
|
||||
case 64:
|
||||
return find_fetch_type("u64");
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++)
|
||||
if (strcmp(type, fetch_type_table[i].name) == 0)
|
||||
return &fetch_type_table[i];
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -586,7 +649,9 @@ error:
|
||||
|
||||
static void free_probe_arg(struct probe_arg *arg)
|
||||
{
|
||||
if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
|
||||
if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
|
||||
free_bitfield_fetch_param(arg->fetch.data);
|
||||
else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
|
||||
free_deref_fetch_param(arg->fetch.data);
|
||||
else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
|
||||
free_symbol_cache(arg->fetch.data);
|
||||
@@ -767,16 +832,15 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t,
|
||||
}
|
||||
break;
|
||||
case '+': /* deref memory */
|
||||
arg++; /* Skip '+', because strict_strtol() rejects it. */
|
||||
case '-':
|
||||
tmp = strchr(arg, '(');
|
||||
if (!tmp)
|
||||
break;
|
||||
*tmp = '\0';
|
||||
ret = strict_strtol(arg + 1, 0, &offset);
|
||||
ret = strict_strtol(arg, 0, &offset);
|
||||
if (ret)
|
||||
break;
|
||||
if (arg[0] == '-')
|
||||
offset = -offset;
|
||||
arg = tmp + 1;
|
||||
tmp = strrchr(arg, ')');
|
||||
if (tmp) {
|
||||
@@ -807,6 +871,41 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long))
|
||||
|
||||
/* Bitfield type needs to be parsed into a fetch function */
|
||||
static int __parse_bitfield_probe_arg(const char *bf,
|
||||
const struct fetch_type *t,
|
||||
struct fetch_param *f)
|
||||
{
|
||||
struct bitfield_fetch_param *bprm;
|
||||
unsigned long bw, bo;
|
||||
char *tail;
|
||||
|
||||
if (*bf != 'b')
|
||||
return 0;
|
||||
|
||||
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
|
||||
if (!bprm)
|
||||
return -ENOMEM;
|
||||
bprm->orig = *f;
|
||||
f->fn = t->fetch[FETCH_MTD_bitfield];
|
||||
f->data = (void *)bprm;
|
||||
|
||||
bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */
|
||||
if (bw == 0 || *tail != '@')
|
||||
return -EINVAL;
|
||||
|
||||
bf = tail + 1;
|
||||
bo = simple_strtoul(bf, &tail, 0);
|
||||
if (tail == bf || *tail != '/')
|
||||
return -EINVAL;
|
||||
|
||||
bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
|
||||
bprm->low_shift = bprm->hi_shift + bo;
|
||||
return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
/* String length checking wrapper */
|
||||
static int parse_probe_arg(char *arg, struct trace_probe *tp,
|
||||
struct probe_arg *parg, int is_return)
|
||||
@@ -836,6 +935,8 @@ static int parse_probe_arg(char *arg, struct trace_probe *tp,
|
||||
parg->offset = tp->size;
|
||||
tp->size += parg->type->size;
|
||||
ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return);
|
||||
if (ret >= 0 && t != NULL)
|
||||
ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
|
||||
if (ret >= 0) {
|
||||
parg->fetch_size.fn = get_fetch_size_function(parg->type,
|
||||
parg->fetch.fn);
|
||||
@@ -1130,7 +1231,7 @@ static int command_trace_probe(const char *buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define WRITE_BUFSIZE 128
|
||||
#define WRITE_BUFSIZE 4096
|
||||
|
||||
static ssize_t probes_write(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
|
@@ -529,24 +529,34 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
|
||||
* @entry: The trace entry field from the ring buffer
|
||||
*
|
||||
* Prints the generic fields of irqs off, in hard or softirq, preempt
|
||||
* count and lock depth.
|
||||
* count.
|
||||
*/
|
||||
int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
|
||||
{
|
||||
int hardirq, softirq;
|
||||
char hardsoft_irq;
|
||||
char need_resched;
|
||||
char irqs_off;
|
||||
int hardirq;
|
||||
int softirq;
|
||||
int ret;
|
||||
|
||||
hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
|
||||
softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
|
||||
|
||||
irqs_off =
|
||||
(entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
|
||||
(entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ? 'X' :
|
||||
'.';
|
||||
need_resched =
|
||||
(entry->flags & TRACE_FLAG_NEED_RESCHED) ? 'N' : '.';
|
||||
hardsoft_irq =
|
||||
(hardirq && softirq) ? 'H' :
|
||||
hardirq ? 'h' :
|
||||
softirq ? 's' :
|
||||
'.';
|
||||
|
||||
if (!trace_seq_printf(s, "%c%c%c",
|
||||
(entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
|
||||
(entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
|
||||
'X' : '.',
|
||||
(entry->flags & TRACE_FLAG_NEED_RESCHED) ?
|
||||
'N' : '.',
|
||||
(hardirq && softirq) ? 'H' :
|
||||
hardirq ? 'h' : softirq ? 's' : '.'))
|
||||
irqs_off, need_resched, hardsoft_irq))
|
||||
return 0;
|
||||
|
||||
if (entry->preempt_count)
|
||||
@@ -554,13 +564,7 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
|
||||
else
|
||||
ret = trace_seq_putc(s, '.');
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
if (entry->lock_depth < 0)
|
||||
return trace_seq_putc(s, '.');
|
||||
|
||||
return trace_seq_printf(s, "%d", entry->lock_depth);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@@ -247,51 +247,3 @@ void tracing_sched_switch_assign_trace(struct trace_array *tr)
|
||||
ctx_trace = tr;
|
||||
}
|
||||
|
||||
static void stop_sched_trace(struct trace_array *tr)
|
||||
{
|
||||
tracing_stop_sched_switch_record();
|
||||
}
|
||||
|
||||
static int sched_switch_trace_init(struct trace_array *tr)
|
||||
{
|
||||
ctx_trace = tr;
|
||||
tracing_reset_online_cpus(tr);
|
||||
tracing_start_sched_switch_record();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sched_switch_trace_reset(struct trace_array *tr)
|
||||
{
|
||||
if (sched_ref)
|
||||
stop_sched_trace(tr);
|
||||
}
|
||||
|
||||
static void sched_switch_trace_start(struct trace_array *tr)
|
||||
{
|
||||
sched_stopped = 0;
|
||||
}
|
||||
|
||||
static void sched_switch_trace_stop(struct trace_array *tr)
|
||||
{
|
||||
sched_stopped = 1;
|
||||
}
|
||||
|
||||
static struct tracer sched_switch_trace __read_mostly =
|
||||
{
|
||||
.name = "sched_switch",
|
||||
.init = sched_switch_trace_init,
|
||||
.reset = sched_switch_trace_reset,
|
||||
.start = sched_switch_trace_start,
|
||||
.stop = sched_switch_trace_stop,
|
||||
.wait_pipe = poll_wait_pipe,
|
||||
#ifdef CONFIG_FTRACE_SELFTEST
|
||||
.selftest = trace_selftest_startup_sched_switch,
|
||||
#endif
|
||||
};
|
||||
|
||||
__init static int init_sched_switch_trace(void)
|
||||
{
|
||||
return register_tracer(&sched_switch_trace);
|
||||
}
|
||||
device_initcall(init_sched_switch_trace);
|
||||
|
||||
|
@@ -60,6 +60,19 @@ extern struct syscall_metadata *__stop_syscalls_metadata[];
|
||||
|
||||
static struct syscall_metadata **syscalls_metadata;
|
||||
|
||||
#ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME
|
||||
static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
|
||||
{
|
||||
/*
|
||||
* Only compare after the "sys" prefix. Archs that use
|
||||
* syscall wrappers may have syscalls symbols aliases prefixed
|
||||
* with "SyS" instead of "sys", leading to an unwanted
|
||||
* mismatch.
|
||||
*/
|
||||
return !strcmp(sym + 3, name + 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
static __init struct syscall_metadata *
|
||||
find_syscall_meta(unsigned long syscall)
|
||||
{
|
||||
@@ -72,14 +85,11 @@ find_syscall_meta(unsigned long syscall)
|
||||
stop = __stop_syscalls_metadata;
|
||||
kallsyms_lookup(syscall, NULL, NULL, NULL, str);
|
||||
|
||||
if (arch_syscall_match_sym_name(str, "sys_ni_syscall"))
|
||||
return NULL;
|
||||
|
||||
for ( ; start < stop; start++) {
|
||||
/*
|
||||
* Only compare after the "sys" prefix. Archs that use
|
||||
* syscall wrappers may have syscalls symbols aliases prefixed
|
||||
* with "SyS" instead of "sys", leading to an unwanted
|
||||
* mismatch.
|
||||
*/
|
||||
if ((*start)->name && !strcmp((*start)->name + 3, str + 3))
|
||||
if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name))
|
||||
return *start;
|
||||
}
|
||||
return NULL;
|
||||
@@ -359,7 +369,7 @@ int reg_event_syscall_enter(struct ftrace_event_call *call)
|
||||
int num;
|
||||
|
||||
num = ((struct syscall_metadata *)call->data)->syscall_nr;
|
||||
if (num < 0 || num >= NR_syscalls)
|
||||
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
|
||||
return -ENOSYS;
|
||||
mutex_lock(&syscall_trace_lock);
|
||||
if (!sys_refcount_enter)
|
||||
@@ -377,7 +387,7 @@ void unreg_event_syscall_enter(struct ftrace_event_call *call)
|
||||
int num;
|
||||
|
||||
num = ((struct syscall_metadata *)call->data)->syscall_nr;
|
||||
if (num < 0 || num >= NR_syscalls)
|
||||
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
|
||||
return;
|
||||
mutex_lock(&syscall_trace_lock);
|
||||
sys_refcount_enter--;
|
||||
@@ -393,7 +403,7 @@ int reg_event_syscall_exit(struct ftrace_event_call *call)
|
||||
int num;
|
||||
|
||||
num = ((struct syscall_metadata *)call->data)->syscall_nr;
|
||||
if (num < 0 || num >= NR_syscalls)
|
||||
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
|
||||
return -ENOSYS;
|
||||
mutex_lock(&syscall_trace_lock);
|
||||
if (!sys_refcount_exit)
|
||||
@@ -411,7 +421,7 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call)
|
||||
int num;
|
||||
|
||||
num = ((struct syscall_metadata *)call->data)->syscall_nr;
|
||||
if (num < 0 || num >= NR_syscalls)
|
||||
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
|
||||
return;
|
||||
mutex_lock(&syscall_trace_lock);
|
||||
sys_refcount_exit--;
|
||||
@@ -424,6 +434,14 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call)
|
||||
int init_syscall_trace(struct ftrace_event_call *call)
|
||||
{
|
||||
int id;
|
||||
int num;
|
||||
|
||||
num = ((struct syscall_metadata *)call->data)->syscall_nr;
|
||||
if (num < 0 || num >= NR_syscalls) {
|
||||
pr_debug("syscall %s metadata not mapped, disabling ftrace event\n",
|
||||
((struct syscall_metadata *)call->data)->name);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
if (set_syscall_print_fmt(call) < 0)
|
||||
return -ENOMEM;
|
||||
@@ -438,7 +456,7 @@ int init_syscall_trace(struct ftrace_event_call *call)
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned long __init arch_syscall_addr(int nr)
|
||||
unsigned long __init __weak arch_syscall_addr(int nr)
|
||||
{
|
||||
return (unsigned long)sys_call_table[nr];
|
||||
}
|
||||
|
Reference in New Issue
Block a user