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 1764e59afbbSIlya Leoshkevich static int test_send_signal_perf(void) 1774e59afbbSIlya Leoshkevich { 1784e59afbbSIlya Leoshkevich struct perf_event_attr attr = { 1794e59afbbSIlya Leoshkevich .sample_period = 1, 1804e59afbbSIlya Leoshkevich .type = PERF_TYPE_SOFTWARE, 1814e59afbbSIlya Leoshkevich .config = PERF_COUNT_SW_CPU_CLOCK, 1824e59afbbSIlya Leoshkevich }; 1834e59afbbSIlya Leoshkevich 1844e59afbbSIlya Leoshkevich return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT, 1854e59afbbSIlya Leoshkevich "perf_sw_event"); 1864e59afbbSIlya Leoshkevich } 1874e59afbbSIlya Leoshkevich 18816f0efc3SYonghong Song static int test_send_signal_nmi(void) 18916f0efc3SYonghong Song { 19016f0efc3SYonghong Song struct perf_event_attr attr = { 19116f0efc3SYonghong Song .sample_freq = 50, 19216f0efc3SYonghong Song .freq = 1, 19316f0efc3SYonghong Song .type = PERF_TYPE_HARDWARE, 19416f0efc3SYonghong Song .config = PERF_COUNT_HW_CPU_CYCLES, 19516f0efc3SYonghong Song }; 1964e59afbbSIlya Leoshkevich int pmu_fd; 19716f0efc3SYonghong Song 1984e59afbbSIlya Leoshkevich /* Some setups (e.g. virtual machines) might run with hardware 1994e59afbbSIlya Leoshkevich * perf events disabled. If this is the case, skip this test. 2004e59afbbSIlya Leoshkevich */ 2014e59afbbSIlya Leoshkevich pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, 2024e59afbbSIlya Leoshkevich -1 /* cpu */, -1 /* group_fd */, 0 /* flags */); 2034e59afbbSIlya Leoshkevich if (pmu_fd == -1) { 2044e59afbbSIlya Leoshkevich if (errno == ENOENT) { 20566bd2ec1SStanislav Fomichev printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n", 2064e59afbbSIlya Leoshkevich __func__); 207cd9c21d7SStanislav Fomichev test__skip(); 2084e59afbbSIlya Leoshkevich return 0; 2094e59afbbSIlya Leoshkevich } 2104e59afbbSIlya Leoshkevich /* Let the test fail with a more informative message */ 2114e59afbbSIlya Leoshkevich } else { 2124e59afbbSIlya Leoshkevich close(pmu_fd); 2134e59afbbSIlya Leoshkevich } 2144e59afbbSIlya Leoshkevich 2154e59afbbSIlya Leoshkevich return test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT, 2164e59afbbSIlya Leoshkevich "perf_hw_event"); 21716f0efc3SYonghong Song } 21816f0efc3SYonghong Song 21916f0efc3SYonghong Song void test_send_signal(void) 22016f0efc3SYonghong Song { 22116f0efc3SYonghong Song int ret = 0; 22216f0efc3SYonghong Song 223b207edfeSAndrii Nakryiko if (test__start_subtest("send_signal_tracepoint")) 22416f0efc3SYonghong Song ret |= test_send_signal_tracepoint(); 225b207edfeSAndrii Nakryiko if (test__start_subtest("send_signal_perf")) 2264e59afbbSIlya Leoshkevich ret |= test_send_signal_perf(); 227b207edfeSAndrii Nakryiko if (test__start_subtest("send_signal_nmi")) 22816f0efc3SYonghong Song ret |= test_send_signal_nmi(); 22916f0efc3SYonghong Song } 230