Skip to content

Commit 0c557e2

Browse files
laoarKernel Patches Daemon
authored andcommitted
selftests/bpf: add test case to update THP policy
This test case exercises the BPF THP update mechanism by modifying an existing policy. The behavior confirms that: - EBUSY error occurs when attempting to install a BPF program on a process that already has an active BPF program - Updates to currently running programs are successfully processed - Local prog can't be updated by a global prog - Global prog can't be updated by a local prog - Global prog can be attached even if there's a local prog - Local prog can't be attached if there's a global prog Signed-off-by: Yafang Shao <[email protected]>
1 parent 093cd45 commit 0c557e2

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

tools/testing/selftests/bpf/prog_tests/thp_adjust.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,79 @@ static void subtest_thp_eligible(void)
194194
bpf_link__destroy(ops_link);
195195
}
196196

197+
static void subtest_thp_policy_update(void)
198+
{
199+
struct bpf_link *old_link, *new_link;
200+
int elighble, err, pid;
201+
char *ptr;
202+
203+
pid = getpid();
204+
ptr = thp_alloc();
205+
206+
old_link = bpf_map__attach_struct_ops(skel->maps.thp_eligible_ops);
207+
if (!ASSERT_OK_PTR(old_link, "attach_old_link"))
208+
goto free;
209+
210+
elighble = get_thp_eligible(pid, (unsigned long)ptr);
211+
ASSERT_EQ(elighble, 0, "THPeligible");
212+
213+
/* Attach multi BPF-THP to a single process is rejected. */
214+
new_link = bpf_map__attach_struct_ops(skel->maps.thp_eligible_ops2);
215+
if (!ASSERT_NULL(new_link, "attach_new_link"))
216+
goto destory_old;
217+
ASSERT_EQ(errno, EBUSY, "attach_new_link");
218+
219+
elighble = get_thp_eligible(pid, (unsigned long)ptr);
220+
ASSERT_EQ(elighble, 0, "THPeligible");
221+
222+
err = bpf_link__update_map(old_link, skel->maps.thp_eligible_ops2);
223+
ASSERT_EQ(err, 0, "update_old_link");
224+
225+
elighble = get_thp_eligible(pid, (unsigned long)ptr);
226+
ASSERT_EQ(elighble, 1, "THPeligible");
227+
228+
/* Per process prog can't be update by a global prog */
229+
err = bpf_link__update_map(old_link, skel->maps.swap_ops);
230+
ASSERT_EQ(err, -EINVAL, "update_old_link");
231+
232+
destory_old:
233+
bpf_link__destroy(old_link);
234+
free:
235+
thp_free(ptr);
236+
}
237+
238+
static void subtest_thp_global_policy(void)
239+
{
240+
struct bpf_link *local_link, *global_link;
241+
int err;
242+
243+
local_link = bpf_map__attach_struct_ops(skel->maps.thp_eligible_ops);
244+
if (!ASSERT_OK_PTR(local_link, "attach_local_link"))
245+
return;
246+
247+
/* global prog can be attached even if there is a local prog */
248+
global_link = bpf_map__attach_struct_ops(skel->maps.swap_ops);
249+
if (!ASSERT_OK_PTR(global_link, "attach_global_link")) {
250+
bpf_link__destroy(local_link);
251+
return;
252+
}
253+
254+
bpf_link__destroy(local_link);
255+
256+
/* local prog can't be attaached if there is a global prog */
257+
local_link = bpf_map__attach_struct_ops(skel->maps.thp_eligible_ops);
258+
if (!ASSERT_NULL(local_link, "attach_new_link"))
259+
goto destory_global;
260+
ASSERT_EQ(errno, EBUSY, "attach_new_link");
261+
262+
/* global prog can't be updated by a local prog */
263+
err = bpf_link__update_map(global_link, skel->maps.thp_eligible_ops);
264+
ASSERT_EQ(err, -EINVAL, "update_old_link");
265+
266+
destory_global:
267+
bpf_link__destroy(global_link);
268+
}
269+
197270
static int thp_adjust_setup(void)
198271
{
199272
int err = -1, pmd_order;
@@ -214,6 +287,8 @@ static int thp_adjust_setup(void)
214287

215288
skel->bss->pmd_order = pmd_order;
216289
skel->struct_ops.thp_eligible_ops->pid = getpid();
290+
skel->struct_ops.thp_eligible_ops2->pid = getpid();
291+
/* swap_ops is a global prog since its pid is not set. */
217292

218293
err = test_thp_adjust__load(skel);
219294
if (!ASSERT_OK(err, "load"))
@@ -240,6 +315,10 @@ void test_thp_adjust(void)
240315

241316
if (test__start_subtest("thp_eligible"))
242317
subtest_thp_eligible();
318+
if (test__start_subtest("policy_update"))
319+
subtest_thp_policy_update();
320+
if (test__start_subtest("global_policy"))
321+
subtest_thp_global_policy();
243322

244323
thp_adjust_destroy();
245324
}

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,32 @@ SEC(".struct_ops.link")
2222
struct bpf_thp_ops thp_eligible_ops = {
2323
.thp_get_order = (void *)thp_not_eligible,
2424
};
25+
26+
SEC("struct_ops/thp_get_order")
27+
int BPF_PROG(thp_eligible, struct vm_area_struct *vma, enum tva_type type,
28+
unsigned long orders)
29+
{
30+
/* THPeligible in /proc/pid/smaps is 1 */
31+
if (type == TVA_SMAPS)
32+
return pmd_order;
33+
return pmd_order;
34+
}
35+
36+
SEC(".struct_ops.link")
37+
struct bpf_thp_ops thp_eligible_ops2 = {
38+
.thp_get_order = (void *)thp_eligible,
39+
};
40+
41+
SEC("struct_ops/thp_get_order")
42+
int BPF_PROG(alloc_not_in_swap, struct vm_area_struct *vma, enum tva_type type,
43+
unsigned long orders)
44+
{
45+
if (type == TVA_SWAP_PAGEFAULT)
46+
return 0;
47+
return -1;
48+
}
49+
50+
SEC(".struct_ops.link")
51+
struct bpf_thp_ops swap_ops = {
52+
.thp_get_order = (void *)alloc_not_in_swap,
53+
};

0 commit comments

Comments
 (0)