Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[sfrench/cifs-2.6.git] / tools / testing / selftests / bpf / prog_tests / send_signal.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include "test_send_signal_kern.skel.h"
4
5 static volatile int sigusr1_received = 0;
6
7 static void sigusr1_handler(int signum)
8 {
9         sigusr1_received++;
10 }
11
12 static void test_send_signal_common(struct perf_event_attr *attr,
13                                     bool signal_thread,
14                                     const char *test_name)
15 {
16         struct test_send_signal_kern *skel;
17         int pipe_c2p[2], pipe_p2c[2];
18         int err = -1, pmu_fd = -1;
19         __u32 duration = 0;
20         char buf[256];
21         pid_t pid;
22
23         if (CHECK(pipe(pipe_c2p), test_name,
24                   "pipe pipe_c2p error: %s\n", strerror(errno)))
25                 return;
26
27         if (CHECK(pipe(pipe_p2c), test_name,
28                   "pipe pipe_p2c error: %s\n", strerror(errno))) {
29                 close(pipe_c2p[0]);
30                 close(pipe_c2p[1]);
31                 return;
32         }
33
34         pid = fork();
35         if (CHECK(pid < 0, test_name, "fork error: %s\n", strerror(errno))) {
36                 close(pipe_c2p[0]);
37                 close(pipe_c2p[1]);
38                 close(pipe_p2c[0]);
39                 close(pipe_p2c[1]);
40                 return;
41         }
42
43         if (pid == 0) {
44                 /* install signal handler and notify parent */
45                 signal(SIGUSR1, sigusr1_handler);
46
47                 close(pipe_c2p[0]); /* close read */
48                 close(pipe_p2c[1]); /* close write */
49
50                 /* notify parent signal handler is installed */
51                 write(pipe_c2p[1], buf, 1);
52
53                 /* make sure parent enabled bpf program to send_signal */
54                 read(pipe_p2c[0], buf, 1);
55
56                 /* wait a little for signal handler */
57                 sleep(1);
58
59                 if (sigusr1_received)
60                         write(pipe_c2p[1], "2", 1);
61                 else
62                         write(pipe_c2p[1], "0", 1);
63
64                 /* wait for parent notification and exit */
65                 read(pipe_p2c[0], buf, 1);
66
67                 close(pipe_c2p[1]);
68                 close(pipe_p2c[0]);
69                 exit(0);
70         }
71
72         close(pipe_c2p[1]); /* close write */
73         close(pipe_p2c[0]); /* close read */
74
75         skel = test_send_signal_kern__open_and_load();
76         if (CHECK(!skel, "skel_open_and_load", "skeleton open_and_load failed\n"))
77                 goto skel_open_load_failure;
78
79         if (!attr) {
80                 err = test_send_signal_kern__attach(skel);
81                 if (CHECK(err, "skel_attach", "skeleton attach failed\n")) {
82                         err = -1;
83                         goto destroy_skel;
84                 }
85         } else {
86                 pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1,
87                                  -1 /* group id */, 0 /* flags */);
88                 if (CHECK(pmu_fd < 0, test_name, "perf_event_open error: %s\n",
89                         strerror(errno))) {
90                         err = -1;
91                         goto destroy_skel;
92                 }
93
94                 skel->links.send_signal_perf =
95                         bpf_program__attach_perf_event(skel->progs.send_signal_perf, pmu_fd);
96                 if (CHECK(IS_ERR(skel->links.send_signal_perf), "attach_perf_event",
97                           "err %ld\n", PTR_ERR(skel->links.send_signal_perf)))
98                         goto disable_pmu;
99         }
100
101         /* wait until child signal handler installed */
102         read(pipe_c2p[0], buf, 1);
103
104         /* trigger the bpf send_signal */
105         skel->bss->pid = pid;
106         skel->bss->sig = SIGUSR1;
107         skel->bss->signal_thread = signal_thread;
108
109         /* notify child that bpf program can send_signal now */
110         write(pipe_p2c[1], buf, 1);
111
112         /* wait for result */
113         err = read(pipe_c2p[0], buf, 1);
114         if (CHECK(err < 0, test_name, "reading pipe error: %s\n", strerror(errno)))
115                 goto disable_pmu;
116         if (CHECK(err == 0, test_name, "reading pipe error: size 0\n")) {
117                 err = -1;
118                 goto disable_pmu;
119         }
120
121         CHECK(buf[0] != '2', test_name, "incorrect result\n");
122
123         /* notify child safe to exit */
124         write(pipe_p2c[1], buf, 1);
125
126 disable_pmu:
127         close(pmu_fd);
128 destroy_skel:
129         test_send_signal_kern__destroy(skel);
130 skel_open_load_failure:
131         close(pipe_c2p[0]);
132         close(pipe_p2c[1]);
133         wait(NULL);
134 }
135
136 static void test_send_signal_tracepoint(bool signal_thread)
137 {
138         test_send_signal_common(NULL, signal_thread, "tracepoint");
139 }
140
141 static void test_send_signal_perf(bool signal_thread)
142 {
143         struct perf_event_attr attr = {
144                 .sample_period = 1,
145                 .type = PERF_TYPE_SOFTWARE,
146                 .config = PERF_COUNT_SW_CPU_CLOCK,
147         };
148
149         test_send_signal_common(&attr, signal_thread, "perf_sw_event");
150 }
151
152 static void test_send_signal_nmi(bool signal_thread)
153 {
154         struct perf_event_attr attr = {
155                 .sample_period = 1,
156                 .type = PERF_TYPE_HARDWARE,
157                 .config = PERF_COUNT_HW_CPU_CYCLES,
158         };
159         int pmu_fd;
160
161         /* Some setups (e.g. virtual machines) might run with hardware
162          * perf events disabled. If this is the case, skip this test.
163          */
164         pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
165                          -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
166         if (pmu_fd == -1) {
167                 if (errno == ENOENT) {
168                         printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
169                                __func__);
170                         test__skip();
171                         return;
172                 }
173                 /* Let the test fail with a more informative message */
174         } else {
175                 close(pmu_fd);
176         }
177
178         test_send_signal_common(&attr, signal_thread, "perf_hw_event");
179 }
180
181 void test_send_signal(void)
182 {
183         if (test__start_subtest("send_signal_tracepoint"))
184                 test_send_signal_tracepoint(false);
185         if (test__start_subtest("send_signal_perf"))
186                 test_send_signal_perf(false);
187         if (test__start_subtest("send_signal_nmi"))
188                 test_send_signal_nmi(false);
189         if (test__start_subtest("send_signal_tracepoint_thread"))
190                 test_send_signal_tracepoint(true);
191         if (test__start_subtest("send_signal_perf_thread"))
192                 test_send_signal_perf(true);
193         if (test__start_subtest("send_signal_nmi_thread"))
194                 test_send_signal_nmi(true);
195 }