1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2a43783aeSArnaldo Carvalho de Melo #include <errno.h> 3f6edb53cSAdrian Hunter #include <sched.h> 457480d2cSYann Droneaud #include "util.h" 591854f9aSArnaldo Carvalho de Melo #include "../perf-sys.h" 657480d2cSYann Droneaud #include "cloexec.h" 7*8520a98dSArnaldo Carvalho de Melo #include "event.h" 857480d2cSYann Droneaud #include "asm/bug.h" 96e81c74cSMasami Hiramatsu #include "debug.h" 10c7007e98SArnaldo Carvalho de Melo #include <unistd.h> 11c7007e98SArnaldo Carvalho de Melo #include <sys/syscall.h> 12*8520a98dSArnaldo Carvalho de Melo #include <linux/string.h> 1357480d2cSYann Droneaud 1457480d2cSYann Droneaud static unsigned long flag = PERF_FLAG_FD_CLOEXEC; 1557480d2cSYann Droneaud 16e1e455f4SVinson Lee int __weak sched_getcpu(void) 17e1e455f4SVinson Lee { 18c7007e98SArnaldo Carvalho de Melo #ifdef __NR_getcpu 19c7007e98SArnaldo Carvalho de Melo unsigned cpu; 20c7007e98SArnaldo Carvalho de Melo int err = syscall(__NR_getcpu, &cpu, NULL, NULL); 21c7007e98SArnaldo Carvalho de Melo if (!err) 22c7007e98SArnaldo Carvalho de Melo return cpu; 23c7007e98SArnaldo Carvalho de Melo #else 24e1e455f4SVinson Lee errno = ENOSYS; 25c7007e98SArnaldo Carvalho de Melo #endif 26e1e455f4SVinson Lee return -1; 27e1e455f4SVinson Lee } 28e1e455f4SVinson Lee 2957480d2cSYann Droneaud static int perf_flag_probe(void) 3057480d2cSYann Droneaud { 3157480d2cSYann Droneaud /* use 'safest' configuration as used in perf_evsel__fallback() */ 3257480d2cSYann Droneaud struct perf_event_attr attr = { 33038fa0b9SJiri Olsa .type = PERF_TYPE_SOFTWARE, 3457480d2cSYann Droneaud .config = PERF_COUNT_SW_CPU_CLOCK, 35a5b0153cSAdrian Hunter .exclude_kernel = 1, 3657480d2cSYann Droneaud }; 3757480d2cSYann Droneaud int fd; 3857480d2cSYann Droneaud int err; 39f6edb53cSAdrian Hunter int cpu; 40f6edb53cSAdrian Hunter pid_t pid = -1; 416e81c74cSMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 4257480d2cSYann Droneaud 43f6edb53cSAdrian Hunter cpu = sched_getcpu(); 44f6edb53cSAdrian Hunter if (cpu < 0) 45f6edb53cSAdrian Hunter cpu = 0; 46f6edb53cSAdrian Hunter 4748536c91SAdrian Hunter /* 4848536c91SAdrian Hunter * Using -1 for the pid is a workaround to avoid gratuitous jump label 4948536c91SAdrian Hunter * changes. 5048536c91SAdrian Hunter */ 51f6edb53cSAdrian Hunter while (1) { 5257480d2cSYann Droneaud /* check cloexec flag */ 53f6edb53cSAdrian Hunter fd = sys_perf_event_open(&attr, pid, cpu, -1, 5457480d2cSYann Droneaud PERF_FLAG_FD_CLOEXEC); 55f6edb53cSAdrian Hunter if (fd < 0 && pid == -1 && errno == EACCES) { 56f6edb53cSAdrian Hunter pid = 0; 57f6edb53cSAdrian Hunter continue; 58f6edb53cSAdrian Hunter } 59f6edb53cSAdrian Hunter break; 60f6edb53cSAdrian Hunter } 6157480d2cSYann Droneaud err = errno; 6257480d2cSYann Droneaud 6357480d2cSYann Droneaud if (fd >= 0) { 6457480d2cSYann Droneaud close(fd); 6557480d2cSYann Droneaud return 1; 6657480d2cSYann Droneaud } 6757480d2cSYann Droneaud 6863914acaSJiri Olsa WARN_ONCE(err != EINVAL && err != EBUSY, 6957480d2cSYann Droneaud "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", 70c8b5f2c9SArnaldo Carvalho de Melo err, str_error_r(err, sbuf, sizeof(sbuf))); 7157480d2cSYann Droneaud 7257480d2cSYann Droneaud /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ 7348536c91SAdrian Hunter while (1) { 74f6edb53cSAdrian Hunter fd = sys_perf_event_open(&attr, pid, cpu, -1, 0); 7548536c91SAdrian Hunter if (fd < 0 && pid == -1 && errno == EACCES) { 7648536c91SAdrian Hunter pid = 0; 7748536c91SAdrian Hunter continue; 7848536c91SAdrian Hunter } 7948536c91SAdrian Hunter break; 8048536c91SAdrian Hunter } 8157480d2cSYann Droneaud err = errno; 8257480d2cSYann Droneaud 8348536c91SAdrian Hunter if (fd >= 0) 8448536c91SAdrian Hunter close(fd); 8548536c91SAdrian Hunter 8663914acaSJiri Olsa if (WARN_ONCE(fd < 0 && err != EBUSY, 8757480d2cSYann Droneaud "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", 88c8b5f2c9SArnaldo Carvalho de Melo err, str_error_r(err, sbuf, sizeof(sbuf)))) 8957480d2cSYann Droneaud return -1; 9057480d2cSYann Droneaud 9157480d2cSYann Droneaud return 0; 9257480d2cSYann Droneaud } 9357480d2cSYann Droneaud 9457480d2cSYann Droneaud unsigned long perf_event_open_cloexec_flag(void) 9557480d2cSYann Droneaud { 9657480d2cSYann Droneaud static bool probed; 9757480d2cSYann Droneaud 9857480d2cSYann Droneaud if (!probed) { 9957480d2cSYann Droneaud if (perf_flag_probe() <= 0) 10057480d2cSYann Droneaud flag = 0; 10157480d2cSYann Droneaud probed = true; 10257480d2cSYann Droneaud } 10357480d2cSYann Droneaud 10457480d2cSYann Droneaud return flag; 10557480d2cSYann Droneaud } 106