^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include "util.h" // for sched_getcpu()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include "../perf-sys.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include "cloexec.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include "event.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include "asm/bug.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "debug.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sys/syscall.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) int __weak sched_getcpu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #ifdef __NR_getcpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) unsigned cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) int err = syscall(__NR_getcpu, &cpu, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) return cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) errno = ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int perf_flag_probe(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* use 'safest' configuration as used in evsel__fallback() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct perf_event_attr attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .type = PERF_TYPE_SOFTWARE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .config = PERF_COUNT_SW_CPU_CLOCK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .exclude_kernel = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) pid_t pid = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) char sbuf[STRERR_BUFSIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) cpu = sched_getcpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (cpu < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * Using -1 for the pid is a workaround to avoid gratuitous jump label
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * changes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* check cloexec flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) fd = sys_perf_event_open(&attr, pid, cpu, -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) PERF_FLAG_FD_CLOEXEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (fd < 0 && pid == -1 && errno == EACCES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) pid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) err = errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (fd >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) WARN_ONCE(err != EINVAL && err != EBUSY && err != EACCES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) err, str_error_r(err, sbuf, sizeof(sbuf)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (fd < 0 && pid == -1 && errno == EACCES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) pid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) err = errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (fd >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (WARN_ONCE(fd < 0 && err != EBUSY && err != EACCES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) err, str_error_r(err, sbuf, sizeof(sbuf))))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) unsigned long perf_event_open_cloexec_flag(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static bool probed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (!probed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (perf_flag_probe() <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) flag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) probed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }