xref: /linux/tools/perf/util/cloexec.c (revision 8520a98dbab61e9e340cdfb72dd17ccc8a98961e)
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