1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2022. Huawei Technologies Co., Ltd */ 3 #define _GNU_SOURCE 4 #include <sched.h> 5 #include <stdbool.h> 6 #include <test_progs.h> 7 #include "htab_update.skel.h" 8 9 struct htab_update_ctx { 10 int fd; 11 int loop; 12 bool stop; 13 }; 14 15 static void test_reenter_update(void) 16 { 17 struct htab_update *skel; 18 unsigned int key, value; 19 int err; 20 21 skel = htab_update__open(); 22 if (!ASSERT_OK_PTR(skel, "htab_update__open")) 23 return; 24 25 /* lookup_elem_raw() may be inlined and find_kernel_btf_id() will return -ESRCH */ 26 bpf_program__set_autoload(skel->progs.lookup_elem_raw, true); 27 err = htab_update__load(skel); 28 if (!ASSERT_TRUE(!err || err == -ESRCH, "htab_update__load") || err) 29 goto out; 30 31 skel->bss->pid = getpid(); 32 err = htab_update__attach(skel); 33 if (!ASSERT_OK(err, "htab_update__attach")) 34 goto out; 35 36 /* Will trigger the reentrancy of bpf_map_update_elem() */ 37 key = 0; 38 value = 0; 39 err = bpf_map_update_elem(bpf_map__fd(skel->maps.htab), &key, &value, 0); 40 if (!ASSERT_OK(err, "add element")) 41 goto out; 42 43 ASSERT_EQ(skel->bss->update_err, -EBUSY, "no reentrancy"); 44 out: 45 htab_update__destroy(skel); 46 } 47 48 static void *htab_update_thread(void *arg) 49 { 50 struct htab_update_ctx *ctx = arg; 51 cpu_set_t cpus; 52 int i; 53 54 /* Pinned on CPU 0 */ 55 CPU_ZERO(&cpus); 56 CPU_SET(0, &cpus); 57 pthread_setaffinity_np(pthread_self(), sizeof(cpus), &cpus); 58 59 i = 0; 60 while (i++ < ctx->loop && !ctx->stop) { 61 unsigned int key = 0, value = 0; 62 int err; 63 64 err = bpf_map_update_elem(ctx->fd, &key, &value, 0); 65 if (err) { 66 ctx->stop = true; 67 return (void *)(long)err; 68 } 69 } 70 71 return NULL; 72 } 73 74 static void test_concurrent_update(void) 75 { 76 struct htab_update_ctx ctx; 77 struct htab_update *skel; 78 unsigned int i, nr; 79 pthread_t *tids; 80 int err; 81 82 skel = htab_update__open_and_load(); 83 if (!ASSERT_OK_PTR(skel, "htab_update__open_and_load")) 84 return; 85 86 ctx.fd = bpf_map__fd(skel->maps.htab); 87 ctx.loop = 1000; 88 ctx.stop = false; 89 90 nr = 4; 91 tids = calloc(nr, sizeof(*tids)); 92 if (!ASSERT_NEQ(tids, NULL, "no mem")) 93 goto out; 94 95 for (i = 0; i < nr; i++) { 96 err = pthread_create(&tids[i], NULL, htab_update_thread, &ctx); 97 if (!ASSERT_OK(err, "pthread_create")) { 98 unsigned int j; 99 100 ctx.stop = true; 101 for (j = 0; j < i; j++) 102 pthread_join(tids[j], NULL); 103 goto out; 104 } 105 } 106 107 for (i = 0; i < nr; i++) { 108 void *thread_err = NULL; 109 110 pthread_join(tids[i], &thread_err); 111 ASSERT_EQ(thread_err, NULL, "update error"); 112 } 113 114 out: 115 if (tids) 116 free(tids); 117 htab_update__destroy(skel); 118 } 119 120 void test_htab_update(void) 121 { 122 if (test__start_subtest("reenter_update")) 123 test_reenter_update(); 124 if (test__start_subtest("concurrent_update")) 125 test_concurrent_update(); 126 } 127