The test case creates 4 threads and then pins these 4 threads in CPU 0. These 4 threads will run different bpf program through bpf_prog_test_run_opts() and these bpf program will use bpf_obj_new() and bpf_obj_drop() to allocate and free local kptrs concurrently. Under preemptible kernel, bpf_obj_new() and bpf_obj_drop() may preempt each other, bpf_obj_new() may return NULL and the test will fail before applying these fixes as shown below: test_preempted_bpf_ma_op:PASS:open_and_load 0 nsec test_preempted_bpf_ma_op:PASS:attach 0 nsec test_preempted_bpf_ma_op:PASS:no test prog 0 nsec test_preempted_bpf_ma_op:PASS:no test prog 0 nsec test_preempted_bpf_ma_op:PASS:no test prog 0 nsec test_preempted_bpf_ma_op:PASS:no test prog 0 nsec test_preempted_bpf_ma_op:PASS:pthread_create 0 nsec test_preempted_bpf_ma_op:PASS:pthread_create 0 nsec test_preempted_bpf_ma_op:PASS:pthread_create 0 nsec test_preempted_bpf_ma_op:PASS:pthread_create 0 nsec test_preempted_bpf_ma_op:PASS:run prog err 0 nsec test_preempted_bpf_ma_op:PASS:run prog err 0 nsec test_preempted_bpf_ma_op:PASS:run prog err 0 nsec test_preempted_bpf_ma_op:PASS:run prog err 0 nsec test_preempted_bpf_ma_op:FAIL:ENOMEM unexpected ENOMEM: got TRUE #168 preempted_bpf_ma_op:FAIL Summary: 0/0 PASSED, 0 SKIPPED, 1 FAILED Signed-off-by: Hou Tao <houtao1@huawei.com> Link: https://lore.kernel.org/r/20230901111954.1804721-4-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
107 lines
1.7 KiB
C
107 lines
1.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (C) 2023. Huawei Technologies Co., Ltd */
|
|
#include <vmlinux.h>
|
|
#include <bpf/bpf_tracing.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
|
|
#include "bpf_experimental.h"
|
|
|
|
struct bin_data {
|
|
char data[256];
|
|
struct bpf_spin_lock lock;
|
|
};
|
|
|
|
struct map_value {
|
|
struct bin_data __kptr * data;
|
|
};
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
|
__type(key, int);
|
|
__type(value, struct map_value);
|
|
__uint(max_entries, 2048);
|
|
} array SEC(".maps");
|
|
|
|
char _license[] SEC("license") = "GPL";
|
|
|
|
bool nomem_err = false;
|
|
|
|
static int del_array(unsigned int i, int *from)
|
|
{
|
|
struct map_value *value;
|
|
struct bin_data *old;
|
|
|
|
value = bpf_map_lookup_elem(&array, from);
|
|
if (!value)
|
|
return 1;
|
|
|
|
old = bpf_kptr_xchg(&value->data, NULL);
|
|
if (old)
|
|
bpf_obj_drop(old);
|
|
|
|
(*from)++;
|
|
return 0;
|
|
}
|
|
|
|
static int add_array(unsigned int i, int *from)
|
|
{
|
|
struct bin_data *old, *new;
|
|
struct map_value *value;
|
|
|
|
value = bpf_map_lookup_elem(&array, from);
|
|
if (!value)
|
|
return 1;
|
|
|
|
new = bpf_obj_new(typeof(*new));
|
|
if (!new) {
|
|
nomem_err = true;
|
|
return 1;
|
|
}
|
|
|
|
old = bpf_kptr_xchg(&value->data, new);
|
|
if (old)
|
|
bpf_obj_drop(old);
|
|
|
|
(*from)++;
|
|
return 0;
|
|
}
|
|
|
|
static void del_then_add_array(int from)
|
|
{
|
|
int i;
|
|
|
|
i = from;
|
|
bpf_loop(512, del_array, &i, 0);
|
|
|
|
i = from;
|
|
bpf_loop(512, add_array, &i, 0);
|
|
}
|
|
|
|
SEC("fentry/bpf_fentry_test1")
|
|
int BPF_PROG2(test0, int, a)
|
|
{
|
|
del_then_add_array(0);
|
|
return 0;
|
|
}
|
|
|
|
SEC("fentry/bpf_fentry_test2")
|
|
int BPF_PROG2(test1, int, a, u64, b)
|
|
{
|
|
del_then_add_array(512);
|
|
return 0;
|
|
}
|
|
|
|
SEC("fentry/bpf_fentry_test3")
|
|
int BPF_PROG2(test2, char, a, int, b, u64, c)
|
|
{
|
|
del_then_add_array(1024);
|
|
return 0;
|
|
}
|
|
|
|
SEC("fentry/bpf_fentry_test4")
|
|
int BPF_PROG2(test3, void *, a, char, b, int, c, u64, d)
|
|
{
|
|
del_then_add_array(1536);
|
|
return 0;
|
|
}
|