Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Cross-merge bpf fixes after downstream PR. No conflicts. Adjacent changes in: include/linux/bpf.h include/uapi/linux/bpf.h kernel/bpf/btf.c kernel/bpf/helpers.c kernel/bpf/syscall.c kernel/bpf/verifier.c kernel/trace/bpf_trace.c mm/slab_common.c tools/include/uapi/linux/bpf.h tools/testing/selftests/bpf/Makefile Link: https://lore.kernel.org/all/20241024215724.60017-1-daniel@iogearbox.net/ Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
+19
-23
@@ -1226,7 +1226,7 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_CTX,
|
||||
.arg2_type = ARG_ANYTHING,
|
||||
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
||||
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||
.arg3_size = sizeof(u64),
|
||||
};
|
||||
|
||||
@@ -1243,7 +1243,7 @@ static const struct bpf_func_proto bpf_get_func_ret_proto = {
|
||||
.func = get_func_ret,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_CTX,
|
||||
.arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
||||
.arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||
.arg2_size = sizeof(u64),
|
||||
};
|
||||
|
||||
@@ -2240,8 +2240,6 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
|
||||
|
||||
old_array = bpf_event_rcu_dereference(event->tp_event->prog_array);
|
||||
ret = bpf_prog_array_copy(old_array, event->prog, NULL, 0, &new_array);
|
||||
if (ret == -ENOENT)
|
||||
goto unlock;
|
||||
if (ret < 0) {
|
||||
bpf_prog_array_delete_safe(old_array, event->prog);
|
||||
} else {
|
||||
@@ -3157,7 +3155,8 @@ static int bpf_uprobe_multi_link_fill_link_info(const struct bpf_link *link,
|
||||
struct bpf_uprobe_multi_link *umulti_link;
|
||||
u32 ucount = info->uprobe_multi.count;
|
||||
int err = 0, i;
|
||||
long left;
|
||||
char *p, *buf;
|
||||
long left = 0;
|
||||
|
||||
if (!upath ^ !upath_size)
|
||||
return -EINVAL;
|
||||
@@ -3171,26 +3170,23 @@ static int bpf_uprobe_multi_link_fill_link_info(const struct bpf_link *link,
|
||||
info->uprobe_multi.pid = umulti_link->task ?
|
||||
task_pid_nr_ns(umulti_link->task, task_active_pid_ns(current)) : 0;
|
||||
|
||||
if (upath) {
|
||||
char *p, *buf;
|
||||
|
||||
upath_size = min_t(u32, upath_size, PATH_MAX);
|
||||
|
||||
buf = kmalloc(upath_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
p = d_path(&umulti_link->path, buf, upath_size);
|
||||
if (IS_ERR(p)) {
|
||||
kfree(buf);
|
||||
return PTR_ERR(p);
|
||||
}
|
||||
upath_size = buf + upath_size - p;
|
||||
left = copy_to_user(upath, p, upath_size);
|
||||
upath_size = upath_size ? min_t(u32, upath_size, PATH_MAX) : PATH_MAX;
|
||||
buf = kmalloc(upath_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
p = d_path(&umulti_link->path, buf, upath_size);
|
||||
if (IS_ERR(p)) {
|
||||
kfree(buf);
|
||||
if (left)
|
||||
return -EFAULT;
|
||||
info->uprobe_multi.path_size = upath_size;
|
||||
return PTR_ERR(p);
|
||||
}
|
||||
upath_size = buf + upath_size - p;
|
||||
|
||||
if (upath)
|
||||
left = copy_to_user(upath, p, upath_size);
|
||||
kfree(buf);
|
||||
if (left)
|
||||
return -EFAULT;
|
||||
info->uprobe_multi.path_size = upath_size;
|
||||
|
||||
if (!uoffsets && !ucookies && !uref_ctr_offsets)
|
||||
return 0;
|
||||
|
||||
+23
-8
@@ -1160,19 +1160,14 @@ void fgraph_update_pid_func(void)
|
||||
static int start_graph_tracing(void)
|
||||
{
|
||||
unsigned long **ret_stack_list;
|
||||
int ret, cpu;
|
||||
int ret;
|
||||
|
||||
ret_stack_list = kmalloc(SHADOW_STACK_SIZE, GFP_KERNEL);
|
||||
ret_stack_list = kcalloc(FTRACE_RETSTACK_ALLOC_SIZE,
|
||||
sizeof(*ret_stack_list), GFP_KERNEL);
|
||||
|
||||
if (!ret_stack_list)
|
||||
return -ENOMEM;
|
||||
|
||||
/* 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_idle_task(idle_task(cpu), cpu);
|
||||
}
|
||||
|
||||
do {
|
||||
ret = alloc_retstack_tasklist(ret_stack_list);
|
||||
} while (ret == -EAGAIN);
|
||||
@@ -1242,14 +1237,34 @@ static void ftrace_graph_disable_direct(bool disable_branch)
|
||||
fgraph_direct_gops = &fgraph_stub;
|
||||
}
|
||||
|
||||
/* The cpu_boot init_task->ret_stack will never be freed */
|
||||
static int fgraph_cpu_init(unsigned int cpu)
|
||||
{
|
||||
if (!idle_task(cpu)->ret_stack)
|
||||
ftrace_graph_init_idle_task(idle_task(cpu), cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_ftrace_graph(struct fgraph_ops *gops)
|
||||
{
|
||||
static bool fgraph_initialized;
|
||||
int command = 0;
|
||||
int ret = 0;
|
||||
int i = -1;
|
||||
|
||||
mutex_lock(&ftrace_lock);
|
||||
|
||||
if (!fgraph_initialized) {
|
||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "fgraph_idle_init",
|
||||
fgraph_cpu_init, NULL);
|
||||
if (ret < 0) {
|
||||
pr_warn("fgraph: Error to init cpu hotplug support\n");
|
||||
return ret;
|
||||
}
|
||||
fgraph_initialized = true;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!fgraph_array[0]) {
|
||||
/* The array must always have real data on it */
|
||||
for (i = 0; i < FGRAPH_ARRAY_SIZE; i++)
|
||||
|
||||
+32
-21
@@ -2337,9 +2337,12 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
|
||||
if (!buffer->buffers[cpu])
|
||||
goto fail_free_buffers;
|
||||
|
||||
ret = cpuhp_state_add_instance(CPUHP_TRACE_RB_PREPARE, &buffer->node);
|
||||
if (ret < 0)
|
||||
goto fail_free_buffers;
|
||||
/* If already mapped, do not hook to CPU hotplug */
|
||||
if (!start) {
|
||||
ret = cpuhp_state_add_instance(CPUHP_TRACE_RB_PREPARE, &buffer->node);
|
||||
if (ret < 0)
|
||||
goto fail_free_buffers;
|
||||
}
|
||||
|
||||
mutex_init(&buffer->mutex);
|
||||
|
||||
@@ -6725,39 +6728,38 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
|
||||
}
|
||||
|
||||
for_each_buffer_cpu(buffer, cpu) {
|
||||
struct buffer_data_page *old_free_data_page;
|
||||
struct list_head old_pages;
|
||||
unsigned long flags;
|
||||
|
||||
if (!cpumask_test_cpu(cpu, buffer->cpumask))
|
||||
continue;
|
||||
|
||||
cpu_buffer = buffer->buffers[cpu];
|
||||
|
||||
raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
|
||||
|
||||
/* Clear the head bit to make the link list normal to read */
|
||||
rb_head_page_deactivate(cpu_buffer);
|
||||
|
||||
/* Now walk the list and free all the old sub buffers */
|
||||
list_for_each_entry_safe(bpage, tmp, cpu_buffer->pages, list) {
|
||||
list_del_init(&bpage->list);
|
||||
free_buffer_page(bpage);
|
||||
}
|
||||
/* The above loop stopped an the last page needing to be freed */
|
||||
bpage = list_entry(cpu_buffer->pages, struct buffer_page, list);
|
||||
free_buffer_page(bpage);
|
||||
|
||||
/* Free the current reader page */
|
||||
free_buffer_page(cpu_buffer->reader_page);
|
||||
/*
|
||||
* Collect buffers from the cpu_buffer pages list and the
|
||||
* reader_page on old_pages, so they can be freed later when not
|
||||
* under a spinlock. The pages list is a linked list with no
|
||||
* head, adding old_pages turns it into a regular list with
|
||||
* old_pages being the head.
|
||||
*/
|
||||
list_add(&old_pages, cpu_buffer->pages);
|
||||
list_add(&cpu_buffer->reader_page->list, &old_pages);
|
||||
|
||||
/* One page was allocated for the reader page */
|
||||
cpu_buffer->reader_page = list_entry(cpu_buffer->new_pages.next,
|
||||
struct buffer_page, list);
|
||||
list_del_init(&cpu_buffer->reader_page->list);
|
||||
|
||||
/* The cpu_buffer pages are a link list with no head */
|
||||
/* Install the new pages, remove the head from the list */
|
||||
cpu_buffer->pages = cpu_buffer->new_pages.next;
|
||||
cpu_buffer->new_pages.next->prev = cpu_buffer->new_pages.prev;
|
||||
cpu_buffer->new_pages.prev->next = cpu_buffer->new_pages.next;
|
||||
|
||||
/* Clear the new_pages list */
|
||||
INIT_LIST_HEAD(&cpu_buffer->new_pages);
|
||||
list_del_init(&cpu_buffer->new_pages);
|
||||
|
||||
cpu_buffer->head_page
|
||||
= list_entry(cpu_buffer->pages, struct buffer_page, list);
|
||||
@@ -6766,11 +6768,20 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
|
||||
cpu_buffer->nr_pages = cpu_buffer->nr_pages_to_update;
|
||||
cpu_buffer->nr_pages_to_update = 0;
|
||||
|
||||
free_pages((unsigned long)cpu_buffer->free_page, old_order);
|
||||
old_free_data_page = cpu_buffer->free_page;
|
||||
cpu_buffer->free_page = NULL;
|
||||
|
||||
rb_head_page_activate(cpu_buffer);
|
||||
|
||||
raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
|
||||
|
||||
/* Free old sub buffers */
|
||||
list_for_each_entry_safe(bpage, tmp, &old_pages, list) {
|
||||
list_del_init(&bpage->list);
|
||||
free_buffer_page(bpage);
|
||||
}
|
||||
free_pages((unsigned long)old_free_data_page, old_order);
|
||||
|
||||
rb_check_pages(cpu_buffer);
|
||||
}
|
||||
|
||||
|
||||
+16
-5
@@ -3697,8 +3697,8 @@ static void test_can_verify(void)
|
||||
void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
long text_delta = iter->tr->text_delta;
|
||||
long data_delta = iter->tr->data_delta;
|
||||
long text_delta = 0;
|
||||
long data_delta = 0;
|
||||
const char *p = fmt;
|
||||
const char *str;
|
||||
bool good;
|
||||
@@ -3710,6 +3710,17 @@ void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
|
||||
if (static_branch_unlikely(&trace_no_verify))
|
||||
goto print;
|
||||
|
||||
/*
|
||||
* When the kernel is booted with the tp_printk command line
|
||||
* parameter, trace events go directly through to printk().
|
||||
* It also is checked by this function, but it does not
|
||||
* have an associated trace_array (tr) for it.
|
||||
*/
|
||||
if (iter->tr) {
|
||||
text_delta = iter->tr->text_delta;
|
||||
data_delta = iter->tr->data_delta;
|
||||
}
|
||||
|
||||
/* Don't bother checking when doing a ftrace_dump() */
|
||||
if (iter->fmt == static_fmt_buf)
|
||||
goto print;
|
||||
@@ -10610,10 +10621,10 @@ __init static void enable_instances(void)
|
||||
* cannot be deleted by user space, so keep the reference
|
||||
* to it.
|
||||
*/
|
||||
if (start)
|
||||
if (start) {
|
||||
tr->flags |= TRACE_ARRAY_FL_BOOT;
|
||||
else
|
||||
trace_array_put(tr);
|
||||
tr->ref++;
|
||||
}
|
||||
|
||||
while ((tok = strsep(&curr_str, ","))) {
|
||||
early_enable_events(tr, tok, true);
|
||||
|
||||
@@ -912,6 +912,11 @@ static int __trace_eprobe_create(int argc, const char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - 2 > MAX_TRACE_ARGS) {
|
||||
ret = -E2BIG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
mutex_lock(&event_mutex);
|
||||
event_call = find_and_get_event(sys_name, sys_event);
|
||||
ep = alloc_event_probe(group, event, event_call, argc - 2);
|
||||
@@ -937,7 +942,7 @@ static int __trace_eprobe_create(int argc, const char *argv[])
|
||||
|
||||
argc -= 2; argv += 2;
|
||||
/* parse arguments */
|
||||
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
trace_probe_log_set_index(i + 2);
|
||||
ret = trace_eprobe_tp_update_arg(ep, argv, i);
|
||||
if (ret)
|
||||
|
||||
@@ -1187,6 +1187,10 @@ static int __trace_fprobe_create(int argc, const char *argv[])
|
||||
argc = new_argc;
|
||||
argv = new_argv;
|
||||
}
|
||||
if (argc > MAX_TRACE_ARGS) {
|
||||
ret = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
|
||||
if (ret)
|
||||
@@ -1203,7 +1207,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
|
||||
}
|
||||
|
||||
/* parse arguments */
|
||||
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
trace_probe_log_set_index(i + 2);
|
||||
ctx.offset = 0;
|
||||
ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], &ctx);
|
||||
|
||||
@@ -520,6 +520,8 @@ static void hwlat_hotplug_workfn(struct work_struct *dummy)
|
||||
if (!hwlat_busy || hwlat_data.thread_mode != MODE_PER_CPU)
|
||||
goto out_unlock;
|
||||
|
||||
if (!cpu_online(cpu))
|
||||
goto out_unlock;
|
||||
if (!cpumask_test_cpu(cpu, tr->tracing_cpumask))
|
||||
goto out_unlock;
|
||||
|
||||
|
||||
@@ -1013,6 +1013,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
||||
argc = new_argc;
|
||||
argv = new_argv;
|
||||
}
|
||||
if (argc > MAX_TRACE_ARGS) {
|
||||
ret = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
|
||||
if (ret)
|
||||
@@ -1029,7 +1033,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
||||
}
|
||||
|
||||
/* parse arguments */
|
||||
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
trace_probe_log_set_index(i + 2);
|
||||
ctx.offset = 0;
|
||||
ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
|
||||
|
||||
@@ -1953,12 +1953,8 @@ static void stop_kthread(unsigned int cpu)
|
||||
{
|
||||
struct task_struct *kthread;
|
||||
|
||||
mutex_lock(&interface_lock);
|
||||
kthread = per_cpu(per_cpu_osnoise_var, cpu).kthread;
|
||||
kthread = xchg_relaxed(&(per_cpu(per_cpu_osnoise_var, cpu).kthread), NULL);
|
||||
if (kthread) {
|
||||
per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;
|
||||
mutex_unlock(&interface_lock);
|
||||
|
||||
if (cpumask_test_and_clear_cpu(cpu, &kthread_cpumask) &&
|
||||
!WARN_ON(!test_bit(OSN_WORKLOAD, &osnoise_options))) {
|
||||
kthread_stop(kthread);
|
||||
@@ -1972,7 +1968,6 @@ static void stop_kthread(unsigned int cpu)
|
||||
put_task_struct(kthread);
|
||||
}
|
||||
} else {
|
||||
mutex_unlock(&interface_lock);
|
||||
/* if no workload, just return */
|
||||
if (!test_bit(OSN_WORKLOAD, &osnoise_options)) {
|
||||
/*
|
||||
@@ -1994,8 +1989,12 @@ static void stop_per_cpu_kthreads(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
cpus_read_lock();
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
stop_kthread(cpu);
|
||||
|
||||
cpus_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2007,6 +2006,10 @@ static int start_kthread(unsigned int cpu)
|
||||
void *main = osnoise_main;
|
||||
char comm[24];
|
||||
|
||||
/* Do not start a new thread if it is already running */
|
||||
if (per_cpu(per_cpu_osnoise_var, cpu).kthread)
|
||||
return 0;
|
||||
|
||||
if (timerlat_enabled()) {
|
||||
snprintf(comm, 24, "timerlat/%d", cpu);
|
||||
main = timerlat_main;
|
||||
@@ -2061,11 +2064,10 @@ static int start_per_cpu_kthreads(void)
|
||||
if (cpumask_test_and_clear_cpu(cpu, &kthread_cpumask)) {
|
||||
struct task_struct *kthread;
|
||||
|
||||
kthread = per_cpu(per_cpu_osnoise_var, cpu).kthread;
|
||||
kthread = xchg_relaxed(&(per_cpu(per_cpu_osnoise_var, cpu).kthread), NULL);
|
||||
if (!WARN_ON(!kthread))
|
||||
kthread_stop(kthread);
|
||||
}
|
||||
per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL;
|
||||
}
|
||||
|
||||
for_each_cpu(cpu, current_mask) {
|
||||
@@ -2095,6 +2097,8 @@ static void osnoise_hotplug_workfn(struct work_struct *dummy)
|
||||
mutex_lock(&interface_lock);
|
||||
cpus_read_lock();
|
||||
|
||||
if (!cpu_online(cpu))
|
||||
goto out_unlock;
|
||||
if (!cpumask_test_cpu(cpu, &osnoise_cpumask))
|
||||
goto out_unlock;
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
|
||||
}
|
||||
trace_probe_log_err(offset, NO_EVENT_NAME);
|
||||
return -EINVAL;
|
||||
} else if (len > MAX_EVENT_NAME_LEN) {
|
||||
} else if (len >= MAX_EVENT_NAME_LEN) {
|
||||
trace_probe_log_err(offset, EVENT_TOO_LONG);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1485,7 +1485,7 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)
|
||||
/* reset the max latency */
|
||||
tr->max_latency = 0;
|
||||
|
||||
while (p->on_rq) {
|
||||
while (task_is_runnable(p)) {
|
||||
/*
|
||||
* Sleep to make sure the -deadline thread is asleep too.
|
||||
* On virtual machines we can't rely on timings,
|
||||
|
||||
@@ -565,6 +565,8 @@ static int __trace_uprobe_create(int argc, const char **argv)
|
||||
|
||||
if (argc < 2)
|
||||
return -ECANCELED;
|
||||
if (argc - 2 > MAX_TRACE_ARGS)
|
||||
return -E2BIG;
|
||||
|
||||
if (argv[0][1] == ':')
|
||||
event = &argv[0][2];
|
||||
@@ -690,7 +692,7 @@ static int __trace_uprobe_create(int argc, const char **argv)
|
||||
tu->filename = filename;
|
||||
|
||||
/* parse arguments */
|
||||
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
struct traceprobe_parse_context ctx = {
|
||||
.flags = (is_return ? TPARG_FL_RETURN : 0) | TPARG_FL_USER,
|
||||
};
|
||||
@@ -875,6 +877,7 @@ struct uprobe_cpu_buffer {
|
||||
};
|
||||
static struct uprobe_cpu_buffer __percpu *uprobe_cpu_buffer;
|
||||
static int uprobe_buffer_refcnt;
|
||||
#define MAX_UCB_BUFFER_SIZE PAGE_SIZE
|
||||
|
||||
static int uprobe_buffer_init(void)
|
||||
{
|
||||
@@ -979,6 +982,11 @@ static struct uprobe_cpu_buffer *prepare_uprobe_buffer(struct trace_uprobe *tu,
|
||||
ucb = uprobe_buffer_get();
|
||||
ucb->dsize = tu->tp.size + dsize;
|
||||
|
||||
if (WARN_ON_ONCE(ucb->dsize > MAX_UCB_BUFFER_SIZE)) {
|
||||
ucb->dsize = MAX_UCB_BUFFER_SIZE;
|
||||
dsize = MAX_UCB_BUFFER_SIZE - tu->tp.size;
|
||||
}
|
||||
|
||||
store_trace_args(ucb->buf, &tu->tp, regs, NULL, esize, dsize);
|
||||
|
||||
*ucbp = ucb;
|
||||
@@ -998,9 +1006,6 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
|
||||
|
||||
WARN_ON(call != trace_file->event_call);
|
||||
|
||||
if (WARN_ON_ONCE(ucb->dsize > PAGE_SIZE))
|
||||
return;
|
||||
|
||||
if (trace_trigger_soft_disabled(trace_file))
|
||||
return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user