Merge tag 'v5.2-rc6' into perf/core, to refresh branch
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@ -410,8 +410,6 @@ static const struct bpf_func_proto bpf_perf_event_read_value_proto = {
|
||||
.arg4_type = ARG_CONST_SIZE,
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct perf_sample_data, bpf_trace_sd);
|
||||
|
||||
static __always_inline u64
|
||||
__bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
|
||||
u64 flags, struct perf_sample_data *sd)
|
||||
@ -442,24 +440,50 @@ __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
|
||||
return perf_event_output(event, sd, regs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support executing tracepoints in normal, irq, and nmi context that each call
|
||||
* bpf_perf_event_output
|
||||
*/
|
||||
struct bpf_trace_sample_data {
|
||||
struct perf_sample_data sds[3];
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct bpf_trace_sample_data, bpf_trace_sds);
|
||||
static DEFINE_PER_CPU(int, bpf_trace_nest_level);
|
||||
BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map,
|
||||
u64, flags, void *, data, u64, size)
|
||||
{
|
||||
struct perf_sample_data *sd = this_cpu_ptr(&bpf_trace_sd);
|
||||
struct bpf_trace_sample_data *sds = this_cpu_ptr(&bpf_trace_sds);
|
||||
int nest_level = this_cpu_inc_return(bpf_trace_nest_level);
|
||||
struct perf_raw_record raw = {
|
||||
.frag = {
|
||||
.size = size,
|
||||
.data = data,
|
||||
},
|
||||
};
|
||||
struct perf_sample_data *sd;
|
||||
int err;
|
||||
|
||||
if (unlikely(flags & ~(BPF_F_INDEX_MASK)))
|
||||
return -EINVAL;
|
||||
if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(sds->sds))) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sd = &sds->sds[nest_level - 1];
|
||||
|
||||
if (unlikely(flags & ~(BPF_F_INDEX_MASK))) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
perf_sample_data_init(sd, 0, 0);
|
||||
sd->raw = &raw;
|
||||
|
||||
return __bpf_perf_event_output(regs, map, flags, sd);
|
||||
err = __bpf_perf_event_output(regs, map, flags, sd);
|
||||
|
||||
out:
|
||||
this_cpu_dec(bpf_trace_nest_level);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct bpf_func_proto bpf_perf_event_output_proto = {
|
||||
@ -822,16 +846,48 @@ pe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
||||
/*
|
||||
* bpf_raw_tp_regs are separate from bpf_pt_regs used from skb/xdp
|
||||
* to avoid potential recursive reuse issue when/if tracepoints are added
|
||||
* inside bpf_*_event_output, bpf_get_stackid and/or bpf_get_stack
|
||||
* inside bpf_*_event_output, bpf_get_stackid and/or bpf_get_stack.
|
||||
*
|
||||
* Since raw tracepoints run despite bpf_prog_active, support concurrent usage
|
||||
* in normal, irq, and nmi context.
|
||||
*/
|
||||
static DEFINE_PER_CPU(struct pt_regs, bpf_raw_tp_regs);
|
||||
struct bpf_raw_tp_regs {
|
||||
struct pt_regs regs[3];
|
||||
};
|
||||
static DEFINE_PER_CPU(struct bpf_raw_tp_regs, bpf_raw_tp_regs);
|
||||
static DEFINE_PER_CPU(int, bpf_raw_tp_nest_level);
|
||||
static struct pt_regs *get_bpf_raw_tp_regs(void)
|
||||
{
|
||||
struct bpf_raw_tp_regs *tp_regs = this_cpu_ptr(&bpf_raw_tp_regs);
|
||||
int nest_level = this_cpu_inc_return(bpf_raw_tp_nest_level);
|
||||
|
||||
if (WARN_ON_ONCE(nest_level > ARRAY_SIZE(tp_regs->regs))) {
|
||||
this_cpu_dec(bpf_raw_tp_nest_level);
|
||||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
return &tp_regs->regs[nest_level - 1];
|
||||
}
|
||||
|
||||
static void put_bpf_raw_tp_regs(void)
|
||||
{
|
||||
this_cpu_dec(bpf_raw_tp_nest_level);
|
||||
}
|
||||
|
||||
BPF_CALL_5(bpf_perf_event_output_raw_tp, struct bpf_raw_tracepoint_args *, args,
|
||||
struct bpf_map *, map, u64, flags, void *, data, u64, size)
|
||||
{
|
||||
struct pt_regs *regs = this_cpu_ptr(&bpf_raw_tp_regs);
|
||||
struct pt_regs *regs = get_bpf_raw_tp_regs();
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
perf_fetch_caller_regs(regs);
|
||||
return ____bpf_perf_event_output(regs, map, flags, data, size);
|
||||
ret = ____bpf_perf_event_output(regs, map, flags, data, size);
|
||||
|
||||
put_bpf_raw_tp_regs();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = {
|
||||
@ -848,12 +904,18 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = {
|
||||
BPF_CALL_3(bpf_get_stackid_raw_tp, struct bpf_raw_tracepoint_args *, args,
|
||||
struct bpf_map *, map, u64, flags)
|
||||
{
|
||||
struct pt_regs *regs = this_cpu_ptr(&bpf_raw_tp_regs);
|
||||
struct pt_regs *regs = get_bpf_raw_tp_regs();
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
perf_fetch_caller_regs(regs);
|
||||
/* similar to bpf_perf_event_output_tp, but pt_regs fetched differently */
|
||||
return bpf_get_stackid((unsigned long) regs, (unsigned long) map,
|
||||
flags, 0, 0);
|
||||
ret = bpf_get_stackid((unsigned long) regs, (unsigned long) map,
|
||||
flags, 0, 0);
|
||||
put_bpf_raw_tp_regs();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct bpf_func_proto bpf_get_stackid_proto_raw_tp = {
|
||||
@ -868,11 +930,17 @@ static const struct bpf_func_proto bpf_get_stackid_proto_raw_tp = {
|
||||
BPF_CALL_4(bpf_get_stack_raw_tp, struct bpf_raw_tracepoint_args *, args,
|
||||
void *, buf, u32, size, u64, flags)
|
||||
{
|
||||
struct pt_regs *regs = this_cpu_ptr(&bpf_raw_tp_regs);
|
||||
struct pt_regs *regs = get_bpf_raw_tp_regs();
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
perf_fetch_caller_regs(regs);
|
||||
return bpf_get_stack((unsigned long) regs, (unsigned long) buf,
|
||||
(unsigned long) size, flags, 0);
|
||||
ret = bpf_get_stack((unsigned long) regs, (unsigned long) buf,
|
||||
(unsigned long) size, flags, 0);
|
||||
put_bpf_raw_tp_regs();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/hash.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/memory.h>
|
||||
|
||||
#include <trace/events/sched.h>
|
||||
|
||||
@ -2610,10 +2611,12 @@ static void ftrace_run_update_code(int command)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&text_mutex);
|
||||
|
||||
ret = ftrace_arch_code_modify_prepare();
|
||||
FTRACE_WARN_ON(ret);
|
||||
if (ret)
|
||||
return;
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* By default we use stop_machine() to modify the code.
|
||||
@ -2625,6 +2628,9 @@ static void ftrace_run_update_code(int command)
|
||||
|
||||
ret = ftrace_arch_code_modify_post_process();
|
||||
FTRACE_WARN_ON(ret);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&text_mutex);
|
||||
}
|
||||
|
||||
static void ftrace_run_modify_code(struct ftrace_ops *ops, int command,
|
||||
@ -2935,14 +2941,13 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
|
||||
p = &pg->records[i];
|
||||
p->flags = rec_flags;
|
||||
|
||||
#ifndef CC_USING_NOP_MCOUNT
|
||||
/*
|
||||
* Do the initial record conversion from mcount jump
|
||||
* to the NOP instructions.
|
||||
*/
|
||||
if (!ftrace_code_disable(mod, p))
|
||||
if (!__is_defined(CC_USING_NOP_MCOUNT) &&
|
||||
!ftrace_code_disable(mod, p))
|
||||
break;
|
||||
#endif
|
||||
|
||||
update_cnt++;
|
||||
}
|
||||
@ -4221,10 +4226,13 @@ void free_ftrace_func_mapper(struct ftrace_func_mapper *mapper,
|
||||
struct ftrace_func_entry *entry;
|
||||
struct ftrace_func_map *map;
|
||||
struct hlist_head *hhd;
|
||||
int size = 1 << mapper->hash.size_bits;
|
||||
int i;
|
||||
int size, i;
|
||||
|
||||
if (!mapper)
|
||||
return;
|
||||
|
||||
if (free_func && mapper->hash.count) {
|
||||
size = 1 << mapper->hash.size_bits;
|
||||
for (i = 0; i < size; i++) {
|
||||
hhd = &mapper->hash.buckets[i];
|
||||
hlist_for_each_entry(entry, hhd, hlist) {
|
||||
@ -5776,6 +5784,7 @@ void ftrace_module_enable(struct module *mod)
|
||||
struct ftrace_page *pg;
|
||||
|
||||
mutex_lock(&ftrace_lock);
|
||||
mutex_lock(&text_mutex);
|
||||
|
||||
if (ftrace_disabled)
|
||||
goto out_unlock;
|
||||
@ -5837,6 +5846,7 @@ void ftrace_module_enable(struct module *mod)
|
||||
ftrace_arch_code_modify_post_process();
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&text_mutex);
|
||||
mutex_unlock(&ftrace_lock);
|
||||
|
||||
process_cached_mods(mod->name);
|
||||
|
@ -6923,7 +6923,7 @@ struct tracing_log_err {
|
||||
|
||||
static DEFINE_MUTEX(tracing_err_log_lock);
|
||||
|
||||
struct tracing_log_err *get_tracing_log_err(struct trace_array *tr)
|
||||
static struct tracing_log_err *get_tracing_log_err(struct trace_array *tr)
|
||||
{
|
||||
struct tracing_log_err *err;
|
||||
|
||||
@ -8192,7 +8192,7 @@ static const struct file_operations buffer_percent_fops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
struct dentry *trace_instance_dir;
|
||||
static struct dentry *trace_instance_dir;
|
||||
|
||||
static void
|
||||
init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer);
|
||||
|
@ -1057,7 +1057,7 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
|
||||
|
||||
trace_seq_puts(s, "<stack trace>\n");
|
||||
|
||||
for (p = field->caller; p && *p != ULONG_MAX && p < end; p++) {
|
||||
for (p = field->caller; p && p < end && *p != ULONG_MAX; p++) {
|
||||
|
||||
if (trace_seq_has_overflowed(s))
|
||||
break;
|
||||
|
@ -426,8 +426,6 @@ end:
|
||||
/*
|
||||
* Argument syntax:
|
||||
* - Add uprobe: p|r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS]
|
||||
*
|
||||
* - Remove uprobe: -:[GRP/]EVENT
|
||||
*/
|
||||
static int trace_uprobe_create(int argc, const char **argv)
|
||||
{
|
||||
@ -443,10 +441,17 @@ static int trace_uprobe_create(int argc, const char **argv)
|
||||
ret = 0;
|
||||
ref_ctr_offset = 0;
|
||||
|
||||
/* argc must be >= 1 */
|
||||
if (argv[0][0] == 'r')
|
||||
switch (argv[0][0]) {
|
||||
case 'r':
|
||||
is_return = true;
|
||||
else if (argv[0][0] != 'p' || argc < 2)
|
||||
break;
|
||||
case 'p':
|
||||
break;
|
||||
default:
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
if (argc < 2)
|
||||
return -ECANCELED;
|
||||
|
||||
if (argv[0][1] == ':')
|
||||
|
Reference in New Issue
Block a user