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

selftests/bpf: Add test case for element reuse in htab map

The reinitialization of spin-lock in map value after immediate reuse may
corrupt lookup with BPF_F_LOCK flag and result in hard lock-up, so add
one test case to demonstrate the problem.

Signed-off-by: Hou Tao <houtao1@huawei.com>
Link: https://lore.kernel.org/r/20230215082132.3856544-3-houtao@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Hou Tao and committed by
Alexei Starovoitov
f88da2d4 997849c4

+120
+101
tools/testing/selftests/bpf/prog_tests/htab_reuse.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (C) 2023. Huawei Technologies Co., Ltd */ 3 + #define _GNU_SOURCE 4 + #include <sched.h> 5 + #include <stdbool.h> 6 + #include <test_progs.h> 7 + #include "htab_reuse.skel.h" 8 + 9 + struct htab_op_ctx { 10 + int fd; 11 + int loop; 12 + bool stop; 13 + }; 14 + 15 + struct htab_val { 16 + unsigned int lock; 17 + unsigned int data; 18 + }; 19 + 20 + static void *htab_lookup_fn(void *arg) 21 + { 22 + struct htab_op_ctx *ctx = arg; 23 + int i = 0; 24 + 25 + while (i++ < ctx->loop && !ctx->stop) { 26 + struct htab_val value; 27 + unsigned int key; 28 + 29 + /* Use BPF_F_LOCK to use spin-lock in map value. */ 30 + key = 7; 31 + bpf_map_lookup_elem_flags(ctx->fd, &key, &value, BPF_F_LOCK); 32 + } 33 + 34 + return NULL; 35 + } 36 + 37 + static void *htab_update_fn(void *arg) 38 + { 39 + struct htab_op_ctx *ctx = arg; 40 + int i = 0; 41 + 42 + while (i++ < ctx->loop && !ctx->stop) { 43 + struct htab_val value; 44 + unsigned int key; 45 + 46 + key = 7; 47 + value.lock = 0; 48 + value.data = key; 49 + bpf_map_update_elem(ctx->fd, &key, &value, BPF_F_LOCK); 50 + bpf_map_delete_elem(ctx->fd, &key); 51 + 52 + key = 24; 53 + value.lock = 0; 54 + value.data = key; 55 + bpf_map_update_elem(ctx->fd, &key, &value, BPF_F_LOCK); 56 + bpf_map_delete_elem(ctx->fd, &key); 57 + } 58 + 59 + return NULL; 60 + } 61 + 62 + void test_htab_reuse(void) 63 + { 64 + unsigned int i, wr_nr = 1, rd_nr = 4; 65 + pthread_t tids[wr_nr + rd_nr]; 66 + struct htab_reuse *skel; 67 + struct htab_op_ctx ctx; 68 + int err; 69 + 70 + skel = htab_reuse__open_and_load(); 71 + if (!ASSERT_OK_PTR(skel, "htab_reuse__open_and_load")) 72 + return; 73 + 74 + ctx.fd = bpf_map__fd(skel->maps.htab); 75 + ctx.loop = 500; 76 + ctx.stop = false; 77 + 78 + memset(tids, 0, sizeof(tids)); 79 + for (i = 0; i < wr_nr; i++) { 80 + err = pthread_create(&tids[i], NULL, htab_update_fn, &ctx); 81 + if (!ASSERT_OK(err, "pthread_create")) { 82 + ctx.stop = true; 83 + goto reap; 84 + } 85 + } 86 + for (i = 0; i < rd_nr; i++) { 87 + err = pthread_create(&tids[i + wr_nr], NULL, htab_lookup_fn, &ctx); 88 + if (!ASSERT_OK(err, "pthread_create")) { 89 + ctx.stop = true; 90 + goto reap; 91 + } 92 + } 93 + 94 + reap: 95 + for (i = 0; i < wr_nr + rd_nr; i++) { 96 + if (!tids[i]) 97 + continue; 98 + pthread_join(tids[i], NULL); 99 + } 100 + htab_reuse__destroy(skel); 101 + }
+19
tools/testing/selftests/bpf/progs/htab_reuse.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (C) 2023. Huawei Technologies Co., Ltd */ 3 + #include <linux/bpf.h> 4 + #include <bpf/bpf_helpers.h> 5 + 6 + char _license[] SEC("license") = "GPL"; 7 + 8 + struct htab_val { 9 + struct bpf_spin_lock lock; 10 + unsigned int data; 11 + }; 12 + 13 + struct { 14 + __uint(type, BPF_MAP_TYPE_HASH); 15 + __uint(max_entries, 64); 16 + __type(key, unsigned int); 17 + __type(value, struct htab_val); 18 + __uint(map_flags, BPF_F_NO_PREALLOC); 19 + } htab SEC(".maps");