mirror of
https://github.com/torvalds/linux.git
synced 2024-09-20 15:03:04 +00:00
selftests/bpf: Add kfunc_call test for simple dtor in bpf_testmod
add simple kfuncs to create/destroy a context type to bpf_testmod, register them and add a kfunc_call test to use them. This provides test coverage for registration of dtor kfuncs from modules. By transferring the context pointer to a map value as a __kptr we also trigger the map-based dtor cleanup logic, improving test coverage. Suggested-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Alan Maguire <alan.maguire@oracle.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20240620091733.1967885-7-alan.maguire@oracle.com
This commit is contained in:
parent
46fb0b62ea
commit
47a8cf0c5b
|
@ -159,6 +159,37 @@ __bpf_kfunc void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr,
|
|||
{
|
||||
}
|
||||
|
||||
__bpf_kfunc struct bpf_testmod_ctx *
|
||||
bpf_testmod_ctx_create(int *err)
|
||||
{
|
||||
struct bpf_testmod_ctx *ctx;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
|
||||
if (!ctx) {
|
||||
*err = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
refcount_set(&ctx->usage, 1);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void testmod_free_cb(struct rcu_head *head)
|
||||
{
|
||||
struct bpf_testmod_ctx *ctx;
|
||||
|
||||
ctx = container_of(head, struct bpf_testmod_ctx, rcu);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
__bpf_kfunc void bpf_testmod_ctx_release(struct bpf_testmod_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
if (refcount_dec_and_test(&ctx->usage))
|
||||
call_rcu(&ctx->rcu, testmod_free_cb);
|
||||
}
|
||||
|
||||
struct bpf_testmod_btf_type_tag_1 {
|
||||
int a;
|
||||
};
|
||||
|
@ -369,8 +400,14 @@ BTF_ID_FLAGS(func, bpf_iter_testmod_seq_next, KF_ITER_NEXT | KF_RET_NULL)
|
|||
BTF_ID_FLAGS(func, bpf_iter_testmod_seq_destroy, KF_ITER_DESTROY)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_common_test)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_dynptr_test)
|
||||
BTF_ID_FLAGS(func, bpf_testmod_ctx_create, KF_ACQUIRE | KF_RET_NULL)
|
||||
BTF_ID_FLAGS(func, bpf_testmod_ctx_release, KF_RELEASE)
|
||||
BTF_KFUNCS_END(bpf_testmod_common_kfunc_ids)
|
||||
|
||||
BTF_ID_LIST(bpf_testmod_dtor_ids)
|
||||
BTF_ID(struct, bpf_testmod_ctx)
|
||||
BTF_ID(func, bpf_testmod_ctx_release)
|
||||
|
||||
static const struct btf_kfunc_id_set bpf_testmod_common_kfunc_set = {
|
||||
.owner = THIS_MODULE,
|
||||
.set = &bpf_testmod_common_kfunc_ids,
|
||||
|
@ -904,6 +941,12 @@ extern int bpf_fentry_test1(int a);
|
|||
|
||||
static int bpf_testmod_init(void)
|
||||
{
|
||||
const struct btf_id_dtor_kfunc bpf_testmod_dtors[] = {
|
||||
{
|
||||
.btf_id = bpf_testmod_dtor_ids[0],
|
||||
.kfunc_btf_id = bpf_testmod_dtor_ids[1]
|
||||
},
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &bpf_testmod_common_kfunc_set);
|
||||
|
@ -912,6 +955,9 @@ static int bpf_testmod_init(void)
|
|||
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_testmod_kfunc_set);
|
||||
ret = ret ?: register_bpf_struct_ops(&bpf_bpf_testmod_ops, bpf_testmod_ops);
|
||||
ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops2, bpf_testmod_ops2);
|
||||
ret = ret ?: register_btf_id_dtor_kfuncs(bpf_testmod_dtors,
|
||||
ARRAY_SIZE(bpf_testmod_dtors),
|
||||
THIS_MODULE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bpf_fentry_test1(0) < 0)
|
||||
|
|
|
@ -80,6 +80,11 @@ struct sendmsg_args {
|
|||
int msglen;
|
||||
};
|
||||
|
||||
struct bpf_testmod_ctx {
|
||||
struct callback_head rcu;
|
||||
refcount_t usage;
|
||||
};
|
||||
|
||||
struct prog_test_ref_kfunc *
|
||||
bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym;
|
||||
void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym;
|
||||
|
@ -135,4 +140,8 @@ int bpf_kfunc_call_kernel_getsockname(struct addr_args *args) __ksym;
|
|||
int bpf_kfunc_call_kernel_getpeername(struct addr_args *args) __ksym;
|
||||
|
||||
void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr, struct bpf_dynptr *ptr__nullable) __ksym;
|
||||
|
||||
struct bpf_testmod_ctx *bpf_testmod_ctx_create(int *err) __ksym;
|
||||
void bpf_testmod_ctx_release(struct bpf_testmod_ctx *ctx) __ksym;
|
||||
|
||||
#endif /* _BPF_TESTMOD_KFUNC_H */
|
||||
|
|
|
@ -78,6 +78,7 @@ static struct kfunc_test_params kfunc_tests[] = {
|
|||
SYSCALL_TEST(kfunc_syscall_test, 0),
|
||||
SYSCALL_NULL_CTX_TEST(kfunc_syscall_test_null, 0),
|
||||
TC_TEST(kfunc_call_test_static_unused_arg, 0),
|
||||
TC_TEST(kfunc_call_ctx, 0),
|
||||
};
|
||||
|
||||
struct syscall_test_args {
|
||||
|
|
|
@ -177,4 +177,41 @@ int kfunc_call_test_static_unused_arg(struct __sk_buff *skb)
|
|||
return actual != expected ? -1 : 0;
|
||||
}
|
||||
|
||||
struct ctx_val {
|
||||
struct bpf_testmod_ctx __kptr *ctx;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, int);
|
||||
__type(value, struct ctx_val);
|
||||
} ctx_map SEC(".maps");
|
||||
|
||||
SEC("tc")
|
||||
int kfunc_call_ctx(struct __sk_buff *skb)
|
||||
{
|
||||
struct bpf_testmod_ctx *ctx;
|
||||
int err = 0;
|
||||
|
||||
ctx = bpf_testmod_ctx_create(&err);
|
||||
if (!ctx && !err)
|
||||
err = -1;
|
||||
if (ctx) {
|
||||
int key = 0;
|
||||
struct ctx_val *ctx_val = bpf_map_lookup_elem(&ctx_map, &key);
|
||||
|
||||
/* Transfer ctx to map to be freed via implicit dtor call
|
||||
* on cleanup.
|
||||
*/
|
||||
if (ctx_val)
|
||||
ctx = bpf_kptr_xchg(&ctx_val->ctx, ctx);
|
||||
if (ctx) {
|
||||
bpf_testmod_ctx_release(ctx);
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
|
Loading…
Reference in New Issue
Block a user