Commit 2669dde7 authored by Kumar Kartikeya Dwivedi's avatar Kumar Kartikeya Dwivedi Committed by Alexei Starovoitov
Browse files

selftests/bpf: Fix map_kptr grace period wait



Commit c27cea44 ("rcu: Re-implement RCU Tasks Trace in terms of SRCU-fast")
broke map_kptr selftest since it removed the function we were kprobing.
Use a new kfunc that invokes call_rcu_tasks_trace and sets a program
provided pointer to an integer to 1. Technically this can be unsafe if
the memory being written to from the callback disappears, but this is
just for usage in a test where we ensure we spin until we see the value
to be set to 1, so it's ok.

Reported-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
Fixes: c27cea44 ("rcu: Re-implement RCU Tasks Trace in terms of SRCU-fast")
Signed-off-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260211185747.3630539-1-memxor@gmail.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 48f624c3
Loading
Loading
Loading
Loading
+6 −9
Original line number Diff line number Diff line
@@ -118,15 +118,16 @@ static void test_map_kptr_success(bool test_run)

static int kern_sync_rcu_tasks_trace(struct rcu_tasks_trace_gp *rcu)
{
	long gp_seq = READ_ONCE(rcu->bss->gp_seq);
	LIBBPF_OPTS(bpf_test_run_opts, opts);
	int ret;

	if (!ASSERT_OK(bpf_prog_test_run_opts(bpf_program__fd(rcu->progs.do_call_rcu_tasks_trace),
					      &opts), "do_call_rcu_tasks_trace"))
	WRITE_ONCE(rcu->bss->done, 0);
	ret = bpf_prog_test_run_opts(bpf_program__fd(rcu->progs.call_rcu_tasks_trace), &opts);
	if (!ASSERT_OK(ret, "call_rcu_tasks_trace"))
		return -EFAULT;
	if (!ASSERT_OK(opts.retval, "opts.retval == 0"))
	if (!ASSERT_OK(opts.retval, "call_rcu_tasks_trace retval"))
		return -EFAULT;
	while (gp_seq == READ_ONCE(rcu->bss->gp_seq))
	while (!READ_ONCE(rcu->bss->done))
		sched_yield();
	return 0;
}
@@ -159,8 +160,6 @@ void serial_test_map_kptr(void)
	skel = rcu_tasks_trace_gp__open_and_load();
	if (!ASSERT_OK_PTR(skel, "rcu_tasks_trace_gp__open_and_load"))
		return;
	if (!ASSERT_OK(rcu_tasks_trace_gp__attach(skel), "rcu_tasks_trace_gp__attach"))
		goto end;

	if (test__start_subtest("success-map")) {
		test_map_kptr_success(true);
@@ -180,7 +179,5 @@ void serial_test_map_kptr(void)
		test_map_kptr_success(true);
	}

end:
	rcu_tasks_trace_gp__destroy(skel);
	return;
}
+4 −26
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include <vmlinux.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_helpers.h>
#include "../test_kmods/bpf_testmod_kfunc.h"

struct task_ls_map {
	__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
	__uint(map_flags, BPF_F_NO_PREALLOC);
	__type(key, int);
	__type(value, int);
} task_ls_map SEC(".maps");

long gp_seq;
int done;

SEC("syscall")
int do_call_rcu_tasks_trace(void *ctx)
{
    struct task_struct *current;
    int *v;

    current = bpf_get_current_task_btf();
    v = bpf_task_storage_get(&task_ls_map, current, NULL, BPF_LOCAL_STORAGE_GET_F_CREATE);
    if (!v)
        return 1;
    /* Invoke call_rcu_tasks_trace */
    return bpf_task_storage_delete(&task_ls_map, current);
}

SEC("kprobe/rcu_tasks_trace_postgp")
int rcu_tasks_trace_postgp(void *ctx)
int call_rcu_tasks_trace(void *ctx)
{
    __sync_add_and_fetch(&gp_seq, 1);
    return 0;
	return bpf_kfunc_call_test_call_rcu_tasks_trace(&done);
}

char _license[] SEC("license") = "GPL";
+28 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/in6.h>
#include <linux/un.h>
#include <linux/filter.h>
#include <linux/rcupdate_trace.h>
#include <net/sock.h>
#include <linux/namei.h>
#include "bpf_testmod.h"
@@ -885,6 +886,32 @@ __bpf_kfunc void bpf_kfunc_call_test_sleepable(void)
{
}

struct bpf_kfunc_rcu_tasks_trace_data {
	struct rcu_head rcu;
	int *done;
};

static void bpf_kfunc_rcu_tasks_trace_cb(struct rcu_head *rhp)
{
	struct bpf_kfunc_rcu_tasks_trace_data *data;

	data = container_of(rhp, struct bpf_kfunc_rcu_tasks_trace_data, rcu);
	WRITE_ONCE(*data->done, 1);
	kfree(data);
}

__bpf_kfunc int bpf_kfunc_call_test_call_rcu_tasks_trace(int *done)
{
	struct bpf_kfunc_rcu_tasks_trace_data *data;

	data = kmalloc(sizeof(*data), GFP_ATOMIC);
	if (!data)
		return -ENOMEM;
	data->done = done;
	call_rcu_tasks_trace(&data->rcu, bpf_kfunc_rcu_tasks_trace_cb);
	return 0;
}

__bpf_kfunc int bpf_kfunc_init_sock(struct init_sock_args *args)
{
	int proto;
@@ -1222,6 +1249,7 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_destructive, KF_DESTRUCTIVE)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_sleepable, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_kfunc_call_test_call_rcu_tasks_trace)
BTF_ID_FLAGS(func, bpf_kfunc_init_sock, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_kfunc_close_sock, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_kfunc_call_kernel_connect, KF_SLEEPABLE)
+1 −0
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym;

void bpf_kfunc_call_test_destructive(void) __ksym;
void bpf_kfunc_call_test_sleepable(void) __ksym;
int bpf_kfunc_call_test_call_rcu_tasks_trace(int *done) __ksym;

void bpf_kfunc_call_test_offset(struct prog_test_ref_kfunc *p);
struct prog_test_member *bpf_kfunc_call_memb_acquire(void);