xref: /linux/tools/perf/util/cloexec.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2a43783aeSArnaldo Carvalho de Melo #include <errno.h>
3f6edb53cSAdrian Hunter #include <sched.h>
4fb71c86cSArnaldo Carvalho de Melo #include "util.h" // for sched_getcpu()
591854f9aSArnaldo Carvalho de Melo #include "../perf-sys.h"
657480d2cSYann Droneaud #include "cloexec.h"
78520a98dSArnaldo 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>
128520a98dSArnaldo Carvalho de Melo #include <linux/string.h>
1357480d2cSYann Droneaud 
1457480d2cSYann Droneaud static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
1557480d2cSYann Droneaud 
perf_flag_probe(void)1657480d2cSYann Droneaud static int perf_flag_probe(void)
1757480d2cSYann Droneaud {
18ae430892SArnaldo Carvalho de Melo 	/* use 'safest' configuration as used in evsel__fallback() */
1957480d2cSYann Droneaud 	struct perf_event_attr attr = {
20038fa0b9SJiri Olsa 		.type = PERF_TYPE_SOFTWARE,
2157480d2cSYann Droneaud 		.config = PERF_COUNT_SW_CPU_CLOCK,
22a5b0153cSAdrian Hunter 		.exclude_kernel = 1,
2357480d2cSYann Droneaud 	};
2457480d2cSYann Droneaud 	int fd;
2557480d2cSYann Droneaud 	int err;
26f6edb53cSAdrian Hunter 	int cpu;
27f6edb53cSAdrian Hunter 	pid_t pid = -1;
286e81c74cSMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
2957480d2cSYann Droneaud 
30f6edb53cSAdrian Hunter 	cpu = sched_getcpu();
31f6edb53cSAdrian Hunter 	if (cpu < 0)
32f6edb53cSAdrian Hunter 		cpu = 0;
33f6edb53cSAdrian Hunter 
3448536c91SAdrian Hunter 	/*
3548536c91SAdrian Hunter 	 * Using -1 for the pid is a workaround to avoid gratuitous jump label
3648536c91SAdrian Hunter 	 * changes.
3748536c91SAdrian Hunter 	 */
38f6edb53cSAdrian Hunter 	while (1) {
3957480d2cSYann Droneaud 		/* check cloexec flag */
40f6edb53cSAdrian Hunter 		fd = sys_perf_event_open(&attr, pid, cpu, -1,
4157480d2cSYann Droneaud 					 PERF_FLAG_FD_CLOEXEC);
42f6edb53cSAdrian Hunter 		if (fd < 0 && pid == -1 && errno == EACCES) {
43f6edb53cSAdrian Hunter 			pid = 0;
44f6edb53cSAdrian Hunter 			continue;
45f6edb53cSAdrian Hunter 		}
46f6edb53cSAdrian Hunter 		break;
47f6edb53cSAdrian Hunter 	}
4857480d2cSYann Droneaud 	err = errno;
4957480d2cSYann Droneaud 
5057480d2cSYann Droneaud 	if (fd >= 0) {
5157480d2cSYann Droneaud 		close(fd);
5257480d2cSYann Droneaud 		return 1;
5357480d2cSYann Droneaud 	}
5457480d2cSYann Droneaud 
55*c1034eb0SAlexey Budankov 	WARN_ONCE(err != EINVAL && err != EBUSY && err != EACCES,
5657480d2cSYann Droneaud 		  "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
57c8b5f2c9SArnaldo Carvalho de Melo 		  err, str_error_r(err, sbuf, sizeof(sbuf)));
5857480d2cSYann Droneaud 
5957480d2cSYann Droneaud 	/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
6048536c91SAdrian Hunter 	while (1) {
61f6edb53cSAdrian Hunter 		fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
6248536c91SAdrian Hunter 		if (fd < 0 && pid == -1 && errno == EACCES) {
6348536c91SAdrian Hunter 			pid = 0;
6448536c91SAdrian Hunter 			continue;
6548536c91SAdrian Hunter 		}
6648536c91SAdrian Hunter 		break;
6748536c91SAdrian Hunter 	}
6857480d2cSYann Droneaud 	err = errno;
6957480d2cSYann Droneaud 
7048536c91SAdrian Hunter 	if (fd >= 0)
7148536c91SAdrian Hunter 		close(fd);
7248536c91SAdrian Hunter 
73*c1034eb0SAlexey Budankov 	if (WARN_ONCE(fd < 0 && err != EBUSY && err != EACCES,
7457480d2cSYann Droneaud 		      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
75c8b5f2c9SArnaldo Carvalho de Melo 		      err, str_error_r(err, sbuf, sizeof(sbuf))))
7657480d2cSYann Droneaud 		return -1;
7757480d2cSYann Droneaud 
7857480d2cSYann Droneaud 	return 0;
7957480d2cSYann Droneaud }
8057480d2cSYann Droneaud 
perf_event_open_cloexec_flag(void)8157480d2cSYann Droneaud unsigned long perf_event_open_cloexec_flag(void)
8257480d2cSYann Droneaud {
8357480d2cSYann Droneaud 	static bool probed;
8457480d2cSYann Droneaud 
8557480d2cSYann Droneaud 	if (!probed) {
8657480d2cSYann Droneaud 		if (perf_flag_probe() <= 0)
8757480d2cSYann Droneaud 			flag = 0;
8857480d2cSYann Droneaud 		probed = true;
8957480d2cSYann Droneaud 	}
9057480d2cSYann Droneaud 
9157480d2cSYann Droneaud 	return flag;
9257480d2cSYann Droneaud }
93