Commit 9f9559f0 authored by Emil Tsalapatis's avatar Emil Tsalapatis Committed by Alexei Starovoitov
Browse files

selftests/bpf: add selftests for bpf_arena_reserve_pages

parent 8fc3d2d8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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
+106 −0
Original line number Diff line number Diff line
@@ -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)
+98 −0
Original line number Diff line number Diff line
@@ -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 */