Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add test for bpf_list_{front,back}

This patch adds the "list_peek" test to use the new
bpf_list_{front,back} kfunc.

The test_{front,back}* tests ensure that the return value
is a non_own_ref node pointer and requires the spinlock to be held.

Suggested-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> # check non_own_ref marking
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/r/20250506015857.817950-9-martin.lau@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
29318b4d fb5b4802

+119
+6
tools/testing/selftests/bpf/prog_tests/linked_list.c
··· 7 7 8 8 #include "linked_list.skel.h" 9 9 #include "linked_list_fail.skel.h" 10 + #include "linked_list_peek.skel.h" 10 11 11 12 static char log_buf[1024 * 1024]; 12 13 ··· 805 804 test_linked_list_success(LIST_IN_LIST, false); 806 805 test_linked_list_success(LIST_IN_LIST, true); 807 806 test_linked_list_success(TEST_ALL, false); 807 + } 808 + 809 + void test_linked_list_peek(void) 810 + { 811 + RUN_TESTS(linked_list_peek); 808 812 }
+113
tools/testing/selftests/bpf/progs/linked_list_peek.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <vmlinux.h> 5 + #include <bpf/bpf_helpers.h> 6 + #include "bpf_misc.h" 7 + #include "bpf_experimental.h" 8 + 9 + struct node_data { 10 + struct bpf_list_node l; 11 + int key; 12 + }; 13 + 14 + #define private(name) SEC(".data." #name) __hidden __attribute__((aligned(8))) 15 + private(A) struct bpf_spin_lock glock; 16 + private(A) struct bpf_list_head ghead __contains(node_data, l); 17 + 18 + #define list_entry(ptr, type, member) container_of(ptr, type, member) 19 + #define NR_NODES 16 20 + 21 + int zero = 0; 22 + 23 + SEC("syscall") 24 + __retval(0) 25 + long list_peek(void *ctx) 26 + { 27 + struct bpf_list_node *l_n; 28 + struct node_data *n; 29 + int i, err = 0; 30 + 31 + bpf_spin_lock(&glock); 32 + l_n = bpf_list_front(&ghead); 33 + bpf_spin_unlock(&glock); 34 + if (l_n) 35 + return __LINE__; 36 + 37 + bpf_spin_lock(&glock); 38 + l_n = bpf_list_back(&ghead); 39 + bpf_spin_unlock(&glock); 40 + if (l_n) 41 + return __LINE__; 42 + 43 + for (i = zero; i < NR_NODES && can_loop; i++) { 44 + n = bpf_obj_new(typeof(*n)); 45 + if (!n) 46 + return __LINE__; 47 + n->key = i; 48 + bpf_spin_lock(&glock); 49 + bpf_list_push_back(&ghead, &n->l); 50 + bpf_spin_unlock(&glock); 51 + } 52 + 53 + bpf_spin_lock(&glock); 54 + 55 + l_n = bpf_list_front(&ghead); 56 + if (!l_n) { 57 + err = __LINE__; 58 + goto done; 59 + } 60 + 61 + n = list_entry(l_n, struct node_data, l); 62 + if (n->key != 0) { 63 + err = __LINE__; 64 + goto done; 65 + } 66 + 67 + l_n = bpf_list_back(&ghead); 68 + if (!l_n) { 69 + err = __LINE__; 70 + goto done; 71 + } 72 + 73 + n = list_entry(l_n, struct node_data, l); 74 + if (n->key != NR_NODES - 1) { 75 + err = __LINE__; 76 + goto done; 77 + } 78 + 79 + done: 80 + bpf_spin_unlock(&glock); 81 + return err; 82 + } 83 + 84 + #define TEST_FB(op, dolock) \ 85 + SEC("syscall") \ 86 + __failure __msg(MSG) \ 87 + long test_##op##_spinlock_##dolock(void *ctx) \ 88 + { \ 89 + struct bpf_list_node *l_n; \ 90 + __u64 jiffies = 0; \ 91 + \ 92 + if (dolock) \ 93 + bpf_spin_lock(&glock); \ 94 + l_n = bpf_list_##op(&ghead); \ 95 + if (l_n) \ 96 + jiffies = bpf_jiffies64(); \ 97 + if (dolock) \ 98 + bpf_spin_unlock(&glock); \ 99 + \ 100 + return !!jiffies; \ 101 + } 102 + 103 + #define MSG "call bpf_list_{{(front|back).+}}; R0{{(_w)?}}=ptr_or_null_node_data(id={{[0-9]+}},non_own_ref" 104 + TEST_FB(front, true) 105 + TEST_FB(back, true) 106 + #undef MSG 107 + 108 + #define MSG "bpf_spin_lock at off=0 must be held for bpf_list_head" 109 + TEST_FB(front, false) 110 + TEST_FB(back, false) 111 + #undef MSG 112 + 113 + char _license[] SEC("license") = "GPL";