Skip to content

Commit 9f9559f

Browse files
etsalAlexei Starovoitov
authored andcommitted
selftests/bpf: add selftests for bpf_arena_reserve_pages
Add selftests for the new bpf_arena_reserve_pages kfunc. Acked-by: Yonghong Song <[email protected]> Signed-off-by: Emil Tsalapatis <[email protected]> Acked-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 8fc3d2d commit 9f9559f

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed

tools/testing/selftests/bpf/bpf_arena_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@
4646

4747
void __arena* bpf_arena_alloc_pages(void *map, void __arena *addr, __u32 page_cnt,
4848
int node_id, __u64 flags) __ksym __weak;
49+
int bpf_arena_reserve_pages(void *map, void __arena *addr, __u32 page_cnt) __ksym __weak;
4950
void bpf_arena_free_pages(void *map, void __arena *ptr, __u32 page_cnt) __ksym __weak;
5051

52+
#define arena_base(map) ((void __arena *)((struct bpf_arena *)(map))->user_vm_start)
53+
5154
#else /* when compiled as user space code */
5255

5356
#define __arena

tools/testing/selftests/bpf/progs/verifier_arena.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#define BPF_NO_KFUNC_PROTOTYPES
55
#include <vmlinux.h>
6+
#include <errno.h>
67
#include <bpf/bpf_helpers.h>
78
#include <bpf/bpf_tracing.h>
89
#include "bpf_misc.h"
@@ -114,6 +115,111 @@ int basic_alloc3(void *ctx)
114115
return 0;
115116
}
116117

118+
SEC("syscall")
119+
__success __retval(0)
120+
int basic_reserve1(void *ctx)
121+
{
122+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
123+
char __arena *page;
124+
int ret;
125+
126+
page = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
127+
if (!page)
128+
return 1;
129+
130+
page += __PAGE_SIZE;
131+
132+
/* Reserve the second page */
133+
ret = bpf_arena_reserve_pages(&arena, page, 1);
134+
if (ret)
135+
return 2;
136+
137+
/* Try to explicitly allocate the reserved page. */
138+
page = bpf_arena_alloc_pages(&arena, page, 1, NUMA_NO_NODE, 0);
139+
if (page)
140+
return 3;
141+
142+
/* Try to implicitly allocate the page (since there's only 2 of them). */
143+
page = bpf_arena_alloc_pages(&arena, NULL, 1, NUMA_NO_NODE, 0);
144+
if (page)
145+
return 4;
146+
#endif
147+
return 0;
148+
}
149+
150+
SEC("syscall")
151+
__success __retval(0)
152+
int basic_reserve2(void *ctx)
153+
{
154+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
155+
char __arena *page;
156+
int ret;
157+
158+
page = arena_base(&arena);
159+
ret = bpf_arena_reserve_pages(&arena, page, 1);
160+
if (ret)
161+
return 1;
162+
163+
page = bpf_arena_alloc_pages(&arena, page, 1, NUMA_NO_NODE, 0);
164+
if ((u64)page)
165+
return 2;
166+
#endif
167+
return 0;
168+
}
169+
170+
/* Reserve the same page twice, should return -EBUSY. */
171+
SEC("syscall")
172+
__success __retval(0)
173+
int reserve_twice(void *ctx)
174+
{
175+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
176+
char __arena *page;
177+
int ret;
178+
179+
page = arena_base(&arena);
180+
181+
ret = bpf_arena_reserve_pages(&arena, page, 1);
182+
if (ret)
183+
return 1;
184+
185+
ret = bpf_arena_reserve_pages(&arena, page, 1);
186+
if (ret != -EBUSY)
187+
return 2;
188+
#endif
189+
return 0;
190+
}
191+
192+
/* Try to reserve past the end of the arena. */
193+
SEC("syscall")
194+
__success __retval(0)
195+
int reserve_invalid_region(void *ctx)
196+
{
197+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
198+
char __arena *page;
199+
int ret;
200+
201+
/* Try a NULL pointer. */
202+
ret = bpf_arena_reserve_pages(&arena, NULL, 3);
203+
if (ret != -EINVAL)
204+
return 1;
205+
206+
page = arena_base(&arena);
207+
208+
ret = bpf_arena_reserve_pages(&arena, page, 3);
209+
if (ret != -EINVAL)
210+
return 2;
211+
212+
ret = bpf_arena_reserve_pages(&arena, page, 4096);
213+
if (ret != -EINVAL)
214+
return 3;
215+
216+
ret = bpf_arena_reserve_pages(&arena, page, (1ULL << 32) - 1);
217+
if (ret != -EINVAL)
218+
return 4;
219+
#endif
220+
return 0;
221+
}
222+
117223
SEC("iter.s/bpf_map")
118224
__success __log_level(2)
119225
int iter_maps1(struct bpf_iter__bpf_map *ctx)

tools/testing/selftests/bpf/progs/verifier_arena_large.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,104 @@ int big_alloc1(void *ctx)
6767
return 0;
6868
}
6969

70+
/* Try to access a reserved page. Behavior should be identical with accessing unallocated pages. */
71+
SEC("syscall")
72+
__success __retval(0)
73+
int access_reserved(void *ctx)
74+
{
75+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
76+
volatile char __arena *page;
77+
char __arena *base;
78+
const size_t len = 4;
79+
int ret, i;
80+
81+
/* Get a separate region of the arena. */
82+
page = base = arena_base(&arena) + 16384 * PAGE_SIZE;
83+
84+
ret = bpf_arena_reserve_pages(&arena, base, len);
85+
if (ret)
86+
return 1;
87+
88+
/* Try to dirty reserved memory. */
89+
for (i = 0; i < len && can_loop; i++)
90+
*page = 0x5a;
91+
92+
for (i = 0; i < len && can_loop; i++) {
93+
page = (volatile char __arena *)(base + i * PAGE_SIZE);
94+
95+
/*
96+
* Error out in case either the write went through,
97+
* or the address has random garbage.
98+
*/
99+
if (*page == 0x5a)
100+
return 2 + 2 * i;
101+
102+
if (*page)
103+
return 2 + 2 * i + 1;
104+
}
105+
#endif
106+
return 0;
107+
}
108+
109+
/* Try to allocate a region overlapping with a reservation. */
110+
SEC("syscall")
111+
__success __retval(0)
112+
int request_partially_reserved(void *ctx)
113+
{
114+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
115+
volatile char __arena *page;
116+
char __arena *base;
117+
int ret;
118+
119+
/* Add an arbitrary page offset. */
120+
page = base = arena_base(&arena) + 4096 * __PAGE_SIZE;
121+
122+
ret = bpf_arena_reserve_pages(&arena, base + 3 * __PAGE_SIZE, 4);
123+
if (ret)
124+
return 1;
125+
126+
page = bpf_arena_alloc_pages(&arena, base, 5, NUMA_NO_NODE, 0);
127+
if ((u64)page != 0ULL)
128+
return 2;
129+
#endif
130+
return 0;
131+
}
132+
133+
SEC("syscall")
134+
__success __retval(0)
135+
int free_reserved(void *ctx)
136+
{
137+
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
138+
char __arena *addr;
139+
char __arena *page;
140+
int ret;
141+
142+
/* Add an arbitrary page offset. */
143+
addr = arena_base(&arena) + 32768 * __PAGE_SIZE;
144+
145+
page = bpf_arena_alloc_pages(&arena, addr, 2, NUMA_NO_NODE, 0);
146+
if (!page)
147+
return 1;
148+
149+
ret = bpf_arena_reserve_pages(&arena, addr + 2 * __PAGE_SIZE, 2);
150+
if (ret)
151+
return 2;
152+
153+
/*
154+
* Reserved and allocated pages should be interchangeable for
155+
* bpf_arena_free_pages(). Free a reserved and an allocated
156+
* page with a single call.
157+
*/
158+
bpf_arena_free_pages(&arena, addr + __PAGE_SIZE , 2);
159+
160+
/* The free call above should have succeeded, so this allocation should too. */
161+
page = bpf_arena_alloc_pages(&arena, addr + __PAGE_SIZE, 2, NUMA_NO_NODE, 0);
162+
if (!page)
163+
return 3;
164+
#endif
165+
return 0;
166+
}
167+
70168
#if defined(__BPF_FEATURE_ADDR_SPACE_CAST)
71169
#define PAGE_CNT 100
72170
__u8 __arena * __arena page[PAGE_CNT]; /* occupies the first page */

0 commit comments

Comments
 (0)