1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2024-2025 Meta Platforms, Inc. and affiliates. */ 3 #include <test_progs.h> 4 #include <network_helpers.h> 5 #include <sys/sysinfo.h> 6 #include <sys/syscall.h> 7 #include <linux/perf_event.h> 8 9 #include "res_spin_lock.skel.h" 10 #include "res_spin_lock_fail.skel.h" 11 12 void test_res_spin_lock_failure(void) 13 { 14 RUN_TESTS(res_spin_lock_fail); 15 } 16 17 static volatile int skip; 18 19 static void *spin_lock_thread(void *arg) 20 { 21 int err, prog_fd = *(u32 *) arg; 22 LIBBPF_OPTS(bpf_test_run_opts, topts, 23 .data_in = &pkt_v4, 24 .data_size_in = sizeof(pkt_v4), 25 .repeat = 10000, 26 ); 27 28 while (!READ_ONCE(skip)) { 29 err = bpf_prog_test_run_opts(prog_fd, &topts); 30 if (err || topts.retval) { 31 ASSERT_OK(err, "test_run"); 32 ASSERT_OK(topts.retval, "test_run retval"); 33 break; 34 } 35 } 36 pthread_exit(arg); 37 } 38 39 void test_res_spin_lock_success(void) 40 { 41 LIBBPF_OPTS(bpf_test_run_opts, topts, 42 .data_in = &pkt_v4, 43 .data_size_in = sizeof(pkt_v4), 44 .repeat = 1, 45 ); 46 struct res_spin_lock *skel; 47 pthread_t thread_id[16]; 48 int prog_fd, i, err; 49 void *ret; 50 51 if (get_nprocs() < 2) { 52 test__skip(); 53 return; 54 } 55 56 skel = res_spin_lock__open_and_load(); 57 if (!ASSERT_OK_PTR(skel, "res_spin_lock__open_and_load")) 58 return; 59 /* AA deadlock */ 60 prog_fd = bpf_program__fd(skel->progs.res_spin_lock_test); 61 err = bpf_prog_test_run_opts(prog_fd, &topts); 62 ASSERT_OK(err, "error"); 63 ASSERT_OK(topts.retval, "retval"); 64 65 prog_fd = bpf_program__fd(skel->progs.res_spin_lock_test_held_lock_max); 66 err = bpf_prog_test_run_opts(prog_fd, &topts); 67 ASSERT_OK(err, "error"); 68 ASSERT_OK(topts.retval, "retval"); 69 70 /* Multi-threaded ABBA deadlock. */ 71 72 prog_fd = bpf_program__fd(skel->progs.res_spin_lock_test_AB); 73 for (i = 0; i < 16; i++) { 74 int err; 75 76 err = pthread_create(&thread_id[i], NULL, &spin_lock_thread, &prog_fd); 77 if (!ASSERT_OK(err, "pthread_create")) 78 goto end; 79 } 80 81 topts.retval = 0; 82 topts.repeat = 1000; 83 int fd = bpf_program__fd(skel->progs.res_spin_lock_test_BA); 84 while (!topts.retval && !err && !READ_ONCE(skel->bss->err)) { 85 err = bpf_prog_test_run_opts(fd, &topts); 86 } 87 88 WRITE_ONCE(skip, true); 89 90 for (i = 0; i < 16; i++) { 91 if (!ASSERT_OK(pthread_join(thread_id[i], &ret), "pthread_join")) 92 goto end; 93 if (!ASSERT_EQ(ret, &prog_fd, "ret == prog_fd")) 94 goto end; 95 } 96 97 ASSERT_EQ(READ_ONCE(skel->bss->err), -EDEADLK, "timeout err"); 98 ASSERT_OK(err, "err"); 99 ASSERT_EQ(topts.retval, -EDEADLK, "timeout"); 100 end: 101 res_spin_lock__destroy(skel); 102 return; 103 } 104 105 void serial_test_res_spin_lock_stress(void) 106 { 107 struct perf_event_attr attr = { 108 .size = sizeof(attr), 109 .type = PERF_TYPE_HARDWARE, 110 .config = PERF_COUNT_HW_CPU_CYCLES, 111 }; 112 int pmu_fd; 113 114 if (libbpf_num_possible_cpus() < 3) { 115 test__skip(); 116 return; 117 } 118 119 pmu_fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 120 if (pmu_fd < 0) { 121 if (errno == ENOENT || errno == EOPNOTSUPP) { 122 test__skip(); 123 return; 124 } 125 ASSERT_OK(-errno, "perf_event_open pmu probe"); 126 return; 127 } 128 close(pmu_fd); 129 130 ASSERT_OK(load_module("bpf_test_rqspinlock.ko", false), "load module AA"); 131 sleep(5); 132 unload_module("bpf_test_rqspinlock", false); 133 /* 134 * Insert bpf_test_rqspinlock.ko manually with test_mode=[1|2] to test 135 * other cases (ABBA, ABBCCA). 136 */ 137 } 138