xref: /linux/tools/testing/selftests/bpf/prog_tests/res_spin_lock.c (revision b676ac484f847bbe5c7d29603f41475b64fefe55)
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 
7 #include "res_spin_lock.skel.h"
8 #include "res_spin_lock_fail.skel.h"
9 
test_res_spin_lock_failure(void)10 void test_res_spin_lock_failure(void)
11 {
12 	RUN_TESTS(res_spin_lock_fail);
13 }
14 
15 static volatile int skip;
16 
spin_lock_thread(void * arg)17 static void *spin_lock_thread(void *arg)
18 {
19 	int err, prog_fd = *(u32 *) arg;
20 	LIBBPF_OPTS(bpf_test_run_opts, topts,
21 		.data_in = &pkt_v4,
22 		.data_size_in = sizeof(pkt_v4),
23 		.repeat = 10000,
24 	);
25 
26 	while (!READ_ONCE(skip)) {
27 		err = bpf_prog_test_run_opts(prog_fd, &topts);
28 		if (err || topts.retval) {
29 			ASSERT_OK(err, "test_run");
30 			ASSERT_OK(topts.retval, "test_run retval");
31 			break;
32 		}
33 	}
34 	pthread_exit(arg);
35 }
36 
test_res_spin_lock_success(void)37 void test_res_spin_lock_success(void)
38 {
39 	LIBBPF_OPTS(bpf_test_run_opts, topts,
40 		.data_in = &pkt_v4,
41 		.data_size_in = sizeof(pkt_v4),
42 		.repeat = 1,
43 	);
44 	struct res_spin_lock *skel;
45 	pthread_t thread_id[16];
46 	int prog_fd, i, err;
47 	void *ret;
48 
49 	if (get_nprocs() < 2) {
50 		test__skip();
51 		return;
52 	}
53 
54 	skel = res_spin_lock__open_and_load();
55 	if (!ASSERT_OK_PTR(skel, "res_spin_lock__open_and_load"))
56 		return;
57 	/* AA deadlock */
58 	prog_fd = bpf_program__fd(skel->progs.res_spin_lock_test);
59 	err = bpf_prog_test_run_opts(prog_fd, &topts);
60 	ASSERT_OK(err, "error");
61 	ASSERT_OK(topts.retval, "retval");
62 
63 	prog_fd = bpf_program__fd(skel->progs.res_spin_lock_test_held_lock_max);
64 	err = bpf_prog_test_run_opts(prog_fd, &topts);
65 	ASSERT_OK(err, "error");
66 	ASSERT_OK(topts.retval, "retval");
67 
68 	/* Multi-threaded ABBA deadlock. */
69 
70 	prog_fd = bpf_program__fd(skel->progs.res_spin_lock_test_AB);
71 	for (i = 0; i < 16; i++) {
72 		int err;
73 
74 		err = pthread_create(&thread_id[i], NULL, &spin_lock_thread, &prog_fd);
75 		if (!ASSERT_OK(err, "pthread_create"))
76 			goto end;
77 	}
78 
79 	topts.retval = 0;
80 	topts.repeat = 1000;
81 	int fd = bpf_program__fd(skel->progs.res_spin_lock_test_BA);
82 	while (!topts.retval && !err && !READ_ONCE(skel->bss->err)) {
83 		err = bpf_prog_test_run_opts(fd, &topts);
84 	}
85 
86 	WRITE_ONCE(skip, true);
87 
88 	for (i = 0; i < 16; i++) {
89 		if (!ASSERT_OK(pthread_join(thread_id[i], &ret), "pthread_join"))
90 			goto end;
91 		if (!ASSERT_EQ(ret, &prog_fd, "ret == prog_fd"))
92 			goto end;
93 	}
94 
95 	ASSERT_EQ(READ_ONCE(skel->bss->err), -EDEADLK, "timeout err");
96 	ASSERT_OK(err, "err");
97 	ASSERT_EQ(topts.retval, -EDEADLK, "timeout");
98 end:
99 	res_spin_lock__destroy(skel);
100 	return;
101 }
102