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

selftests/bpf: Add test for open coded dmabuf_iter

Use the same test buffers as the traditional iterator and a new BPF map
to verify the test buffers can be found with the open coded dmabuf
iterator.

Signed-off-by: T.J. Mercier <tjmercier@google.com>
Acked-by: Christian König <christian.koenig@amd.com>
Acked-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20250522230429.941193-6-tjmercier@google.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

T.J. Mercier and committed by
Alexei Starovoitov
7594dcb7 ae5d2c59

+94
+5
tools/testing/selftests/bpf/bpf_experimental.h
··· 591 591 extern struct kmem_cache *bpf_iter_kmem_cache_next(struct bpf_iter_kmem_cache *it) __weak __ksym; 592 592 extern void bpf_iter_kmem_cache_destroy(struct bpf_iter_kmem_cache *it) __weak __ksym; 593 593 594 + struct bpf_iter_dmabuf; 595 + extern int bpf_iter_dmabuf_new(struct bpf_iter_dmabuf *it) __weak __ksym; 596 + extern struct dma_buf *bpf_iter_dmabuf_next(struct bpf_iter_dmabuf *it) __weak __ksym; 597 + extern void bpf_iter_dmabuf_destroy(struct bpf_iter_dmabuf *it) __weak __ksym; 598 + 594 599 #endif
+41
tools/testing/selftests/bpf/prog_tests/dmabuf_iter.c
··· 219 219 close(iter_fd); 220 220 } 221 221 222 + static void subtest_dmabuf_iter_check_open_coded(struct dmabuf_iter *skel, int map_fd) 223 + { 224 + LIBBPF_OPTS(bpf_test_run_opts, topts); 225 + char key[DMA_BUF_NAME_LEN]; 226 + int err, fd; 227 + bool found; 228 + 229 + /* No need to attach it, just run it directly */ 230 + fd = bpf_program__fd(skel->progs.iter_dmabuf_for_each); 231 + 232 + err = bpf_prog_test_run_opts(fd, &topts); 233 + if (!ASSERT_OK(err, "test_run_opts err")) 234 + return; 235 + if (!ASSERT_OK(topts.retval, "test_run_opts retval")) 236 + return; 237 + 238 + if (!ASSERT_OK(bpf_map_get_next_key(map_fd, NULL, key), "get next key")) 239 + return; 240 + 241 + do { 242 + ASSERT_OK(bpf_map_lookup_elem(map_fd, key, &found), "lookup"); 243 + ASSERT_TRUE(found, "found test buffer"); 244 + } while (bpf_map_get_next_key(map_fd, key, key)); 245 + } 246 + 222 247 void test_dmabuf_iter(void) 223 248 { 224 249 struct dmabuf_iter *skel = NULL; 250 + int map_fd; 251 + const bool f = false; 225 252 226 253 skel = dmabuf_iter__open_and_load(); 227 254 if (!ASSERT_OK_PTR(skel, "dmabuf_iter__open_and_load")) 228 255 return; 256 + 257 + map_fd = bpf_map__fd(skel->maps.testbuf_hash); 258 + if (!ASSERT_OK_FD(map_fd, "map_fd")) 259 + goto destroy_skel; 260 + 261 + if (!ASSERT_OK(bpf_map_update_elem(map_fd, udmabuf_test_buffer_name, &f, BPF_ANY), 262 + "insert udmabuf")) 263 + goto destroy_skel; 264 + if (!ASSERT_OK(bpf_map_update_elem(map_fd, sysheap_test_buffer_name, &f, BPF_ANY), 265 + "insert sysheap buffer")) 266 + goto destroy_skel; 229 267 230 268 if (!ASSERT_OK(create_test_buffers(), "create_test_buffers")) 231 269 goto destroy; ··· 275 237 subtest_dmabuf_iter_check_no_infinite_reads(skel); 276 238 if (test__start_subtest("default_iter")) 277 239 subtest_dmabuf_iter_check_default_iter(skel); 240 + if (test__start_subtest("open_coded")) 241 + subtest_dmabuf_iter_check_open_coded(skel, map_fd); 278 242 279 243 destroy: 280 244 destroy_test_buffers(); 245 + destroy_skel: 281 246 dmabuf_iter__destroy(skel); 282 247 }
+48
tools/testing/selftests/bpf/progs/dmabuf_iter.c
··· 9 9 10 10 char _license[] SEC("license") = "GPL"; 11 11 12 + struct { 13 + __uint(type, BPF_MAP_TYPE_HASH); 14 + __uint(key_size, DMA_BUF_NAME_LEN); 15 + __type(value, bool); 16 + __uint(max_entries, 5); 17 + } testbuf_hash SEC(".maps"); 18 + 12 19 /* 13 20 * Fields output by this iterator are delimited by newlines. Convert any 14 21 * newlines in user-provided printed strings to spaces. ··· 56 49 } 57 50 58 51 BPF_SEQ_PRINTF(seq, "%lu\n%llu\n%s\n%s\n", inode, size, name, exporter); 52 + return 0; 53 + } 54 + 55 + SEC("syscall") 56 + int iter_dmabuf_for_each(const void *ctx) 57 + { 58 + struct dma_buf *d; 59 + 60 + bpf_for_each(dmabuf, d) { 61 + char name[DMA_BUF_NAME_LEN]; 62 + const char *pname; 63 + bool *found; 64 + long len; 65 + int i; 66 + 67 + if (bpf_core_read(&pname, sizeof(pname), &d->name)) 68 + return 1; 69 + 70 + /* Buffers are not required to be named */ 71 + if (!pname) 72 + continue; 73 + 74 + len = bpf_probe_read_kernel_str(name, sizeof(name), pname); 75 + if (len < 0) 76 + return 1; 77 + 78 + /* 79 + * The entire name buffer is used as a map key. 80 + * Zeroize any uninitialized trailing bytes after the NUL. 81 + */ 82 + bpf_for(i, len, DMA_BUF_NAME_LEN) 83 + name[i] = 0; 84 + 85 + found = bpf_map_lookup_elem(&testbuf_hash, name); 86 + if (found) { 87 + bool t = true; 88 + 89 + bpf_map_update_elem(&testbuf_hash, name, &t, BPF_EXIST); 90 + } 91 + } 92 + 59 93 return 0; 60 94 }