mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
selftests/bpf: add selftests for bpf_arena_reserve_pages
Add selftests for the new bpf_arena_reserve_pages kfunc. Acked-by: Yonghong Song <yonghong.song@linux.dev> Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com> Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20250709191312.29840-3-emil@etsalapatis.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
8fc3d2d8b5
commit
9f9559f0ac
|
|
@ -46,8 +46,11 @@
|
|||
|
||||
void __arena* bpf_arena_alloc_pages(void *map, void __arena *addr, __u32 page_cnt,
|
||||
int node_id, __u64 flags) __ksym __weak;
|
||||
int bpf_arena_reserve_pages(void *map, void __arena *addr, __u32 page_cnt) __ksym __weak;
|
||||
void bpf_arena_free_pages(void *map, void __arena *ptr, __u32 page_cnt) __ksym __weak;
|
||||
|
||||
#define arena_base(map) ((void __arena *)((struct bpf_arena *)(map))->user_vm_start)
|
||||
|
||||
#else /* when compiled as user space code */
|
||||
|
||||
#define __arena
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#define BPF_NO_KFUNC_PROTOTYPES
|
||||
#include <vmlinux.h>
|
||||
#include <errno.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include "bpf_misc.h"
|
||||
|
|
@ -114,6 +115,111 @@ int basic_alloc3(void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__success __retval(0)
|
||||
int basic_reserve1(void *ctx)
|
||||
{
|
||||
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
|
||||
char __arena *page;
|
||||
int ret;
|
||||
|
||||
page = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
|
||||
if (!page)
|
||||
return 1;
|
||||
|
||||
page += __PAGE_SIZE;
|
||||
|
||||
/* Reserve the second page */
|
||||
ret = bpf_arena_reserve_pages(&arena, page, 1);
|
||||
if (ret)
|
||||
return 2;
|
||||
|
||||
/* Try to explicitly allocate the reserved page. */
|
||||
page = bpf_arena_alloc_pages(&arena, page, 1, NUMA_NO_NODE, 0);
|
||||
if (page)
|
||||
return 3;
|
||||
|
||||
/* Try to implicitly allocate the page (since there's only 2 of them). */
|
||||
page = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
|
||||
if (page)
|
||||
return 4;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__success __retval(0)
|
||||
int basic_reserve2(void *ctx)
|
||||
{
|
||||
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
|
||||
char __arena *page;
|
||||
int ret;
|
||||
|
||||
page = arena_base(&arena);
|
||||
ret = bpf_arena_reserve_pages(&arena, page, 1);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
page = bpf_arena_alloc_pages(&arena, page, 1, NUMA_NO_NODE, 0);
|
||||
if ((u64)page)
|
||||
return 2;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reserve the same page twice, should return -EBUSY. */
|
||||
SEC("syscall")
|
||||
__success __retval(0)
|
||||
int reserve_twice(void *ctx)
|
||||
{
|
||||
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
|
||||
char __arena *page;
|
||||
int ret;
|
||||
|
||||
page = arena_base(&arena);
|
||||
|
||||
ret = bpf_arena_reserve_pages(&arena, page, 1);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
ret = bpf_arena_reserve_pages(&arena, page, 1);
|
||||
if (ret != -EBUSY)
|
||||
return 2;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to reserve past the end of the arena. */
|
||||
SEC("syscall")
|
||||
__success __retval(0)
|
||||
int reserve_invalid_region(void *ctx)
|
||||
{
|
||||
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
|
||||
char __arena *page;
|
||||
int ret;
|
||||
|
||||
/* Try a NULL pointer. */
|
||||
ret = bpf_arena_reserve_pages(&arena, NULL, 3);
|
||||
if (ret != -EINVAL)
|
||||
return 1;
|
||||
|
||||
page = arena_base(&arena);
|
||||
|
||||
ret = bpf_arena_reserve_pages(&arena, page, 3);
|
||||
if (ret != -EINVAL)
|
||||
return 2;
|
||||
|
||||
ret = bpf_arena_reserve_pages(&arena, page, 4096);
|
||||
if (ret != -EINVAL)
|
||||
return 3;
|
||||
|
||||
ret = bpf_arena_reserve_pages(&arena, page, (1ULL << 32) - 1);
|
||||
if (ret != -EINVAL)
|
||||
return 4;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("iter.s/bpf_map")
|
||||
__success __log_level(2)
|
||||
int iter_maps1(struct bpf_iter__bpf_map *ctx)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,104 @@ int big_alloc1(void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Try to access a reserved page. Behavior should be identical with accessing unallocated pages. */
|
||||
SEC("syscall")
|
||||
__success __retval(0)
|
||||
int access_reserved(void *ctx)
|
||||
{
|
||||
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
|
||||
volatile char __arena *page;
|
||||
char __arena *base;
|
||||
const size_t len = 4;
|
||||
int ret, i;
|
||||
|
||||
/* Get a separate region of the arena. */
|
||||
page = base = arena_base(&arena) + 16384 * PAGE_SIZE;
|
||||
|
||||
ret = bpf_arena_reserve_pages(&arena, base, len);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
/* Try to dirty reserved memory. */
|
||||
for (i = 0; i < len && can_loop; i++)
|
||||
*page = 0x5a;
|
||||
|
||||
for (i = 0; i < len && can_loop; i++) {
|
||||
page = (volatile char __arena *)(base + i * PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Error out in case either the write went through,
|
||||
* or the address has random garbage.
|
||||
*/
|
||||
if (*page == 0x5a)
|
||||
return 2 + 2 * i;
|
||||
|
||||
if (*page)
|
||||
return 2 + 2 * i + 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to allocate a region overlapping with a reservation. */
|
||||
SEC("syscall")
|
||||
__success __retval(0)
|
||||
int request_partially_reserved(void *ctx)
|
||||
{
|
||||
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
|
||||
volatile char __arena *page;
|
||||
char __arena *base;
|
||||
int ret;
|
||||
|
||||
/* Add an arbitrary page offset. */
|
||||
page = base = arena_base(&arena) + 4096 * __PAGE_SIZE;
|
||||
|
||||
ret = bpf_arena_reserve_pages(&arena, base + 3 * __PAGE_SIZE, 4);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
page = bpf_arena_alloc_pages(&arena, base, 5, NUMA_NO_NODE, 0);
|
||||
if ((u64)page != 0ULL)
|
||||
return 2;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__success __retval(0)
|
||||
int free_reserved(void *ctx)
|
||||
{
|
||||
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
|
||||
char __arena *addr;
|
||||
char __arena *page;
|
||||
int ret;
|
||||
|
||||
/* Add an arbitrary page offset. */
|
||||
addr = arena_base(&arena) + 32768 * __PAGE_SIZE;
|
||||
|
||||
page = bpf_arena_alloc_pages(&arena, addr, 2, NUMA_NO_NODE, 0);
|
||||
if (!page)
|
||||
return 1;
|
||||
|
||||
ret = bpf_arena_reserve_pages(&arena, addr + 2 * __PAGE_SIZE, 2);
|
||||
if (ret)
|
||||
return 2;
|
||||
|
||||
/*
|
||||
* Reserved and allocated pages should be interchangeable for
|
||||
* bpf_arena_free_pages(). Free a reserved and an allocated
|
||||
* page with a single call.
|
||||
*/
|
||||
bpf_arena_free_pages(&arena, addr + __PAGE_SIZE , 2);
|
||||
|
||||
/* The free call above should have succeeded, so this allocation should too. */
|
||||
page = bpf_arena_alloc_pages(&arena, addr + __PAGE_SIZE, 2, NUMA_NO_NODE, 0);
|
||||
if (!page)
|
||||
return 3;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
|
||||
#define PAGE_CNT 100
|
||||
__u8 __arena * __arena page[PAGE_CNT]; /* occupies the first page */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user