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

Configure Feed

Select the types of activity you want to include in your feed.

selftests/bpf: Add a test for mmap-able map in map

Regular BPF hash map is not mmap-able from user space. However, map-in-map
with outer map of type BPF_MAP_TYPE_HASH_OF_MAPS and mmap-able array as
inner map can perform similar operations as a mmap-able hash map. This
can be used by applications that benefit from fast accesses to some local
data.

Add a selftest to show this use case.

Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20240723051455.1589192-1-song@kernel.org
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

authored by

Song Liu and committed by
Andrii Nakryiko
c7db4873 1edf364a

+114
+57
tools/testing/selftests/bpf/prog_tests/test_mmap_inner_array.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 + #include <test_progs.h> 4 + #include <sys/mman.h> 5 + #include "mmap_inner_array.skel.h" 6 + 7 + void test_mmap_inner_array(void) 8 + { 9 + const long page_size = sysconf(_SC_PAGE_SIZE); 10 + struct mmap_inner_array *skel; 11 + int inner_array_fd, err; 12 + void *tmp; 13 + __u64 *val; 14 + 15 + skel = mmap_inner_array__open_and_load(); 16 + 17 + if (!ASSERT_OK_PTR(skel, "open_and_load")) 18 + return; 19 + 20 + inner_array_fd = bpf_map__fd(skel->maps.inner_array); 21 + tmp = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, inner_array_fd, 0); 22 + if (!ASSERT_OK_PTR(tmp, "inner array mmap")) 23 + goto out; 24 + val = (void *)tmp; 25 + 26 + err = mmap_inner_array__attach(skel); 27 + if (!ASSERT_OK(err, "attach")) 28 + goto out_unmap; 29 + 30 + skel->bss->pid = getpid(); 31 + usleep(1); 32 + 33 + /* pid is set, pid_match == true and outer_map_match == false */ 34 + ASSERT_TRUE(skel->bss->pid_match, "pid match 1"); 35 + ASSERT_FALSE(skel->bss->outer_map_match, "outer map match 1"); 36 + ASSERT_FALSE(skel->bss->done, "done 1"); 37 + ASSERT_EQ(*val, 0, "value match 1"); 38 + 39 + err = bpf_map__update_elem(skel->maps.outer_map, 40 + &skel->bss->pid, sizeof(skel->bss->pid), 41 + &inner_array_fd, sizeof(inner_array_fd), 42 + BPF_ANY); 43 + if (!ASSERT_OK(err, "update elem")) 44 + goto out_unmap; 45 + usleep(1); 46 + 47 + /* outer map key is set, outer_map_match == true */ 48 + ASSERT_TRUE(skel->bss->pid_match, "pid match 2"); 49 + ASSERT_TRUE(skel->bss->outer_map_match, "outer map match 2"); 50 + ASSERT_TRUE(skel->bss->done, "done 2"); 51 + ASSERT_EQ(*val, skel->data->match_value, "value match 2"); 52 + 53 + out_unmap: 54 + munmap(tmp, page_size); 55 + out: 56 + mmap_inner_array__destroy(skel); 57 + }
+57
tools/testing/selftests/bpf/progs/mmap_inner_array.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include "vmlinux.h" 5 + #include <bpf/bpf_helpers.h> 6 + 7 + #include "bpf_misc.h" 8 + 9 + char _license[] SEC("license") = "GPL"; 10 + 11 + struct inner_array_type { 12 + __uint(type, BPF_MAP_TYPE_ARRAY); 13 + __uint(map_flags, BPF_F_MMAPABLE); 14 + __type(key, __u32); 15 + __type(value, __u64); 16 + __uint(max_entries, 1); 17 + } inner_array SEC(".maps"); 18 + 19 + struct { 20 + __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); 21 + __uint(key_size, 4); 22 + __uint(value_size, 4); 23 + __uint(max_entries, 1); 24 + __array(values, struct inner_array_type); 25 + } outer_map SEC(".maps"); 26 + 27 + int pid = 0; 28 + __u64 match_value = 0x13572468; 29 + bool done = false; 30 + bool pid_match = false; 31 + bool outer_map_match = false; 32 + 33 + SEC("fentry/" SYS_PREFIX "sys_nanosleep") 34 + int add_to_list_in_inner_array(void *ctx) 35 + { 36 + __u32 curr_pid, zero = 0; 37 + struct bpf_map *map; 38 + __u64 *value; 39 + 40 + curr_pid = (u32)bpf_get_current_pid_tgid(); 41 + if (done || curr_pid != pid) 42 + return 0; 43 + 44 + pid_match = true; 45 + map = bpf_map_lookup_elem(&outer_map, &curr_pid); 46 + if (!map) 47 + return 0; 48 + 49 + outer_map_match = true; 50 + value = bpf_map_lookup_elem(map, &zero); 51 + if (!value) 52 + return 0; 53 + 54 + *value = match_value; 55 + done = true; 56 + return 0; 57 + }