This patch adds a test to check for deadlock failure in bpf_task_storage_{get,delete} when called by a sleepable bpf_lsm prog. It also checks if the prog_info.recursion_misses is non zero. The test starts with 32 threads and they are affinitized to one cpu. In my qemu setup, with CONFIG_PREEMPT=y, I can reproduce it within one second if it is run without the previous patches of this set. Here is the test error message before adding the no deadlock detection version of the bpf_task_storage_{get,delete}: test_nodeadlock:FAIL:bpf_task_storage_get busy unexpected bpf_task_storage_get busy: actual 2 != expected 0 test_nodeadlock:FAIL:bpf_task_storage_delete busy unexpected bpf_task_storage_delete busy: actual 2 != expected 0 Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org> Link: https://lore.kernel.org/r/20221025184524.3526117-9-martin.lau@linux.dev Signed-off-by: Alexei Starovoitov <ast@kernel.org>
47 lines
1 KiB
C
47 lines
1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include "vmlinux.h"
|
|
#include <bpf/bpf_helpers.h>
|
|
#include <bpf/bpf_tracing.h>
|
|
|
|
char _license[] SEC("license") = "GPL";
|
|
|
|
#ifndef EBUSY
|
|
#define EBUSY 16
|
|
#endif
|
|
|
|
extern bool CONFIG_PREEMPT __kconfig __weak;
|
|
int nr_get_errs = 0;
|
|
int nr_del_errs = 0;
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
|
|
__uint(map_flags, BPF_F_NO_PREALLOC);
|
|
__type(key, int);
|
|
__type(value, int);
|
|
} task_storage SEC(".maps");
|
|
|
|
SEC("lsm.s/socket_post_create")
|
|
int BPF_PROG(socket_post_create, struct socket *sock, int family, int type,
|
|
int protocol, int kern)
|
|
{
|
|
struct task_struct *task;
|
|
int ret, zero = 0;
|
|
int *value;
|
|
|
|
if (!CONFIG_PREEMPT)
|
|
return 0;
|
|
|
|
task = bpf_get_current_task_btf();
|
|
value = bpf_task_storage_get(&task_storage, task, &zero,
|
|
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
|
if (!value)
|
|
__sync_fetch_and_add(&nr_get_errs, 1);
|
|
|
|
ret = bpf_task_storage_delete(&task_storage,
|
|
bpf_get_current_task_btf());
|
|
if (ret == -EBUSY)
|
|
__sync_fetch_and_add(&nr_del_errs, 1);
|
|
|
|
return 0;
|
|
}
|