116f0efc3SYonghong Song // SPDX-License-Identifier: GPL-2.0 216f0efc3SYonghong Song #include <test_progs.h> 316f0efc3SYonghong Song 416f0efc3SYonghong Song static volatile int sigusr1_received = 0; 516f0efc3SYonghong Song 616f0efc3SYonghong Song static void sigusr1_handler(int signum) 716f0efc3SYonghong Song { 816f0efc3SYonghong Song sigusr1_received++; 916f0efc3SYonghong Song } 1016f0efc3SYonghong Song 1116f0efc3SYonghong Song static int test_send_signal_common(struct perf_event_attr *attr, 1216f0efc3SYonghong Song int prog_type, 1316f0efc3SYonghong Song const char *test_name) 1416f0efc3SYonghong Song { 1516f0efc3SYonghong Song int err = -1, pmu_fd, prog_fd, info_map_fd, status_map_fd; 1616f0efc3SYonghong Song const char *file = "./test_send_signal_kern.o"; 1716f0efc3SYonghong Song struct bpf_object *obj = NULL; 1816f0efc3SYonghong Song int pipe_c2p[2], pipe_p2c[2]; 1916f0efc3SYonghong Song __u32 key = 0, duration = 0; 2016f0efc3SYonghong Song char buf[256]; 2116f0efc3SYonghong Song pid_t pid; 2216f0efc3SYonghong Song __u64 val; 2316f0efc3SYonghong Song 2416f0efc3SYonghong Song if (CHECK(pipe(pipe_c2p), test_name, 2516f0efc3SYonghong Song "pipe pipe_c2p error: %s\n", strerror(errno))) 2616f0efc3SYonghong Song goto no_fork_done; 2716f0efc3SYonghong Song 2816f0efc3SYonghong Song if (CHECK(pipe(pipe_p2c), test_name, 2916f0efc3SYonghong Song "pipe pipe_p2c error: %s\n", strerror(errno))) { 3016f0efc3SYonghong Song close(pipe_c2p[0]); 3116f0efc3SYonghong Song close(pipe_c2p[1]); 3216f0efc3SYonghong Song goto no_fork_done; 3316f0efc3SYonghong Song } 3416f0efc3SYonghong Song 3516f0efc3SYonghong Song pid = fork(); 3616f0efc3SYonghong Song if (CHECK(pid < 0, test_name, "fork error: %s\n", strerror(errno))) { 3716f0efc3SYonghong Song close(pipe_c2p[0]); 3816f0efc3SYonghong Song close(pipe_c2p[1]); 3916f0efc3SYonghong Song close(pipe_p2c[0]); 4016f0efc3SYonghong Song close(pipe_p2c[1]); 4116f0efc3SYonghong Song goto no_fork_done; 4216f0efc3SYonghong Song } 4316f0efc3SYonghong Song 4416f0efc3SYonghong Song if (pid == 0) { 4516f0efc3SYonghong Song /* install signal handler and notify parent */ 4616f0efc3SYonghong Song signal(SIGUSR1, sigusr1_handler); 4716f0efc3SYonghong Song 4816f0efc3SYonghong Song close(pipe_c2p[0]); /* close read */ 4916f0efc3SYonghong Song close(pipe_p2c[1]); /* close write */ 5016f0efc3SYonghong Song 5116f0efc3SYonghong Song /* notify parent signal handler is installed */ 5216f0efc3SYonghong Song write(pipe_c2p[1], buf, 1); 5316f0efc3SYonghong Song 5416f0efc3SYonghong Song /* make sure parent enabled bpf program to send_signal */ 5516f0efc3SYonghong Song read(pipe_p2c[0], buf, 1); 5616f0efc3SYonghong Song 5716f0efc3SYonghong Song /* wait a little for signal handler */ 5816f0efc3SYonghong Song sleep(1); 5916f0efc3SYonghong Song 6016f0efc3SYonghong Song if (sigusr1_received) 6116f0efc3SYonghong Song write(pipe_c2p[1], "2", 1); 6216f0efc3SYonghong Song else 6316f0efc3SYonghong Song write(pipe_c2p[1], "0", 1); 6416f0efc3SYonghong Song 6516f0efc3SYonghong Song /* wait for parent notification and exit */ 6616f0efc3SYonghong Song read(pipe_p2c[0], buf, 1); 6716f0efc3SYonghong Song 6816f0efc3SYonghong Song close(pipe_c2p[1]); 6916f0efc3SYonghong Song close(pipe_p2c[0]); 7016f0efc3SYonghong Song exit(0); 7116f0efc3SYonghong Song } 7216f0efc3SYonghong Song 7316f0efc3SYonghong Song close(pipe_c2p[1]); /* close write */ 7416f0efc3SYonghong Song close(pipe_p2c[0]); /* close read */ 7516f0efc3SYonghong Song 7616f0efc3SYonghong Song err = bpf_prog_load(file, prog_type, &obj, &prog_fd); 7716f0efc3SYonghong Song if (CHECK(err < 0, test_name, "bpf_prog_load error: %s\n", 7816f0efc3SYonghong Song strerror(errno))) 7916f0efc3SYonghong Song goto prog_load_failure; 8016f0efc3SYonghong Song 8116f0efc3SYonghong Song pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1, 8216f0efc3SYonghong Song -1 /* group id */, 0 /* flags */); 8316f0efc3SYonghong Song if (CHECK(pmu_fd < 0, test_name, "perf_event_open error: %s\n", 8416f0efc3SYonghong Song strerror(errno))) { 8516f0efc3SYonghong Song err = -1; 8616f0efc3SYonghong Song goto close_prog; 8716f0efc3SYonghong Song } 8816f0efc3SYonghong Song 8916f0efc3SYonghong Song err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0); 9016f0efc3SYonghong Song if (CHECK(err < 0, test_name, "ioctl perf_event_ioc_enable error: %s\n", 9116f0efc3SYonghong Song strerror(errno))) 9216f0efc3SYonghong Song goto disable_pmu; 9316f0efc3SYonghong Song 9416f0efc3SYonghong Song err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); 9516f0efc3SYonghong Song if (CHECK(err < 0, test_name, "ioctl perf_event_ioc_set_bpf error: %s\n", 9616f0efc3SYonghong Song strerror(errno))) 9716f0efc3SYonghong Song goto disable_pmu; 9816f0efc3SYonghong Song 9916f0efc3SYonghong Song err = -1; 10016f0efc3SYonghong Song info_map_fd = bpf_object__find_map_fd_by_name(obj, "info_map"); 10116f0efc3SYonghong Song if (CHECK(info_map_fd < 0, test_name, "find map %s error\n", "info_map")) 10216f0efc3SYonghong Song goto disable_pmu; 10316f0efc3SYonghong Song 10416f0efc3SYonghong Song status_map_fd = bpf_object__find_map_fd_by_name(obj, "status_map"); 10516f0efc3SYonghong Song if (CHECK(status_map_fd < 0, test_name, "find map %s error\n", "status_map")) 10616f0efc3SYonghong Song goto disable_pmu; 10716f0efc3SYonghong Song 10816f0efc3SYonghong Song /* wait until child signal handler installed */ 10916f0efc3SYonghong Song read(pipe_c2p[0], buf, 1); 11016f0efc3SYonghong Song 11116f0efc3SYonghong Song /* trigger the bpf send_signal */ 11216f0efc3SYonghong Song key = 0; 11316f0efc3SYonghong Song val = (((__u64)(SIGUSR1)) << 32) | pid; 11416f0efc3SYonghong Song bpf_map_update_elem(info_map_fd, &key, &val, 0); 11516f0efc3SYonghong Song 11616f0efc3SYonghong Song /* notify child that bpf program can send_signal now */ 11716f0efc3SYonghong Song write(pipe_p2c[1], buf, 1); 11816f0efc3SYonghong Song 11916f0efc3SYonghong Song /* wait for result */ 12016f0efc3SYonghong Song err = read(pipe_c2p[0], buf, 1); 12116f0efc3SYonghong Song if (CHECK(err < 0, test_name, "reading pipe error: %s\n", strerror(errno))) 12216f0efc3SYonghong Song goto disable_pmu; 12316f0efc3SYonghong Song if (CHECK(err == 0, test_name, "reading pipe error: size 0\n")) { 12416f0efc3SYonghong Song err = -1; 12516f0efc3SYonghong Song goto disable_pmu; 12616f0efc3SYonghong Song } 12716f0efc3SYonghong Song 12816f0efc3SYonghong Song err = CHECK(buf[0] != '2', test_name, "incorrect result\n"); 12916f0efc3SYonghong Song 13016f0efc3SYonghong Song /* notify child safe to exit */ 13116f0efc3SYonghong Song write(pipe_p2c[1], buf, 1); 13216f0efc3SYonghong Song 13316f0efc3SYonghong Song disable_pmu: 13416f0efc3SYonghong Song close(pmu_fd); 13516f0efc3SYonghong Song close_prog: 13616f0efc3SYonghong Song bpf_object__close(obj); 13716f0efc3SYonghong Song prog_load_failure: 13816f0efc3SYonghong Song close(pipe_c2p[0]); 13916f0efc3SYonghong Song close(pipe_p2c[1]); 14016f0efc3SYonghong Song wait(NULL); 14116f0efc3SYonghong Song no_fork_done: 14216f0efc3SYonghong Song return err; 14316f0efc3SYonghong Song } 14416f0efc3SYonghong Song 14516f0efc3SYonghong Song static int test_send_signal_tracepoint(void) 14616f0efc3SYonghong Song { 14716f0efc3SYonghong Song const char *id_path = "/sys/kernel/debug/tracing/events/syscalls/sys_enter_nanosleep/id"; 14816f0efc3SYonghong Song struct perf_event_attr attr = { 14916f0efc3SYonghong Song .type = PERF_TYPE_TRACEPOINT, 15016f0efc3SYonghong Song .sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN, 15116f0efc3SYonghong Song .sample_period = 1, 15216f0efc3SYonghong Song .wakeup_events = 1, 15316f0efc3SYonghong Song }; 15416f0efc3SYonghong Song __u32 duration = 0; 15516f0efc3SYonghong Song int bytes, efd; 15616f0efc3SYonghong Song char buf[256]; 15716f0efc3SYonghong Song 15816f0efc3SYonghong Song efd = open(id_path, O_RDONLY, 0); 15916f0efc3SYonghong Song if (CHECK(efd < 0, "tracepoint", 16016f0efc3SYonghong Song "open syscalls/sys_enter_nanosleep/id failure: %s\n", 16116f0efc3SYonghong Song strerror(errno))) 16216f0efc3SYonghong Song return -1; 16316f0efc3SYonghong Song 16416f0efc3SYonghong Song bytes = read(efd, buf, sizeof(buf)); 16516f0efc3SYonghong Song close(efd); 16616f0efc3SYonghong Song if (CHECK(bytes <= 0 || bytes >= sizeof(buf), "tracepoint", 16716f0efc3SYonghong Song "read syscalls/sys_enter_nanosleep/id failure: %s\n", 16816f0efc3SYonghong Song strerror(errno))) 16916f0efc3SYonghong Song return -1; 17016f0efc3SYonghong Song 17116f0efc3SYonghong Song attr.config = strtol(buf, NULL, 0); 17216f0efc3SYonghong Song 17316f0efc3SYonghong Song return test_send_signal_common(&attr, BPF_PROG_TYPE_TRACEPOINT, "tracepoint"); 17416f0efc3SYonghong Song } 17516f0efc3SYonghong Song 17616f0efc3SYonghong Song static int test_send_signal_nmi(void) 17716f0efc3SYonghong Song { 17816f0efc3SYonghong Song struct perf_event_attr attr = { 17916f0efc3SYonghong Song .sample_freq = 50, 18016f0efc3SYonghong Song .freq = 1, 18116f0efc3SYonghong Song .type = PERF_TYPE_HARDWARE, 18216f0efc3SYonghong Song .config = PERF_COUNT_HW_CPU_CYCLES, 18316f0efc3SYonghong Song }; 18416f0efc3SYonghong Song 18516f0efc3SYonghong Song return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT, "perf_event"); 18616f0efc3SYonghong Song } 18716f0efc3SYonghong Song 18816f0efc3SYonghong Song void test_send_signal(void) 18916f0efc3SYonghong Song { 19016f0efc3SYonghong Song int ret = 0; 19116f0efc3SYonghong Song 19216f0efc3SYonghong Song ret |= test_send_signal_tracepoint(); 19316f0efc3SYonghong Song ret |= test_send_signal_nmi(); 19416f0efc3SYonghong Song if (!ret) 19516f0efc3SYonghong Song printf("test_send_signal:OK\n"); 19616f0efc3SYonghong Song else 19716f0efc3SYonghong Song printf("test_send_signal:FAIL\n"); 19816f0efc3SYonghong Song } 199