Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Enable close-on-exec flag on perf file descriptor

In commit a21b0b354d4a ('perf: Introduce a flag to enable
close-on-exec in perf_event_open()'), flag PERF_FLAG_FD_CLOEXEC
was added to perf_event_open(2) syscall to allows userspace
to atomically enable close-on-exec behavor when creating
the file descriptor.

This patch makes perf tools use the new flag if supported
by the kernel, so that the event file descriptors got
automatically closed if perf tool exec a sub-command.

Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/n/1404160127-7475-1-git-send-email-ydroneaud@opteya.com
Signed-off-by: Jiri Olsa <jolsa@kernel.org>

authored by

Yann Droneaud and committed by
Jiri Olsa
57480d2c ec6dbcb7

+97 -12
+1
tools/perf/Makefile.perf
··· 376 376 LIB_OBJS += $(OUTPUT)util/srcline.o 377 377 LIB_OBJS += $(OUTPUT)util/data.o 378 378 LIB_OBJS += $(OUTPUT)util/tsc.o 379 + LIB_OBJS += $(OUTPUT)util/cloexec.o 379 380 380 381 LIB_OBJS += $(OUTPUT)ui/setup.o 381 382 LIB_OBJS += $(OUTPUT)ui/helpline.o
+3 -1
tools/perf/bench/mem-memcpy.c
··· 10 10 #include "../util/util.h" 11 11 #include "../util/parse-options.h" 12 12 #include "../util/header.h" 13 + #include "../util/cloexec.h" 13 14 #include "bench.h" 14 15 #include "mem-memcpy-arch.h" 15 16 ··· 84 83 85 84 static void init_cycle(void) 86 85 { 87 - cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 86 + cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 87 + perf_event_open_cloexec_flag()); 88 88 89 89 if (cycle_fd < 0 && errno == ENOSYS) 90 90 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
+3 -1
tools/perf/bench/mem-memset.c
··· 10 10 #include "../util/util.h" 11 11 #include "../util/parse-options.h" 12 12 #include "../util/header.h" 13 + #include "../util/cloexec.h" 13 14 #include "bench.h" 14 15 #include "mem-memset-arch.h" 15 16 ··· 84 83 85 84 static void init_cycle(void) 86 85 { 87 - cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 86 + cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 87 + perf_event_open_cloexec_flag()); 88 88 89 89 if (cycle_fd < 0 && errno == ENOSYS) 90 90 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
+3 -1
tools/perf/builtin-sched.c
··· 10 10 #include "util/header.h" 11 11 #include "util/session.h" 12 12 #include "util/tool.h" 13 + #include "util/cloexec.h" 13 14 14 15 #include "util/parse-options.h" 15 16 #include "util/trace-event.h" ··· 435 434 attr.type = PERF_TYPE_SOFTWARE; 436 435 attr.config = PERF_COUNT_SW_TASK_CLOCK; 437 436 438 - fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 437 + fd = sys_perf_event_open(&attr, 0, -1, -1, 438 + perf_event_open_cloexec_flag()); 439 439 440 440 if (fd < 0) 441 441 pr_err("Error: sys_perf_event_open() syscall returned "
+3 -1
tools/perf/tests/bp_signal.c
··· 25 25 #include "tests.h" 26 26 #include "debug.h" 27 27 #include "perf.h" 28 + #include "cloexec.h" 28 29 29 30 static int fd1; 30 31 static int fd2; ··· 79 78 pe.exclude_kernel = 1; 80 79 pe.exclude_hv = 1; 81 80 82 - fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 81 + fd = sys_perf_event_open(&pe, 0, -1, -1, 82 + perf_event_open_cloexec_flag()); 83 83 if (fd < 0) { 84 84 pr_debug("failed opening event %llx\n", pe.config); 85 85 return TEST_FAIL;
+3 -1
tools/perf/tests/bp_signal_overflow.c
··· 24 24 #include "tests.h" 25 25 #include "debug.h" 26 26 #include "perf.h" 27 + #include "cloexec.h" 27 28 28 29 static int overflows; 29 30 ··· 92 91 pe.exclude_kernel = 1; 93 92 pe.exclude_hv = 1; 94 93 95 - fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 94 + fd = sys_perf_event_open(&pe, 0, -1, -1, 95 + perf_event_open_cloexec_flag()); 96 96 if (fd < 0) { 97 97 pr_debug("failed opening event %llx\n", pe.config); 98 98 return TEST_FAIL;
+3 -1
tools/perf/tests/rdpmc.c
··· 6 6 #include "perf.h" 7 7 #include "debug.h" 8 8 #include "tests.h" 9 + #include "cloexec.h" 9 10 10 11 #if defined(__x86_64__) || defined(__i386__) 11 12 ··· 105 104 sa.sa_sigaction = segfault_handler; 106 105 sigaction(SIGSEGV, &sa, NULL); 107 106 108 - fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 107 + fd = sys_perf_event_open(&attr, 0, -1, -1, 108 + perf_event_open_cloexec_flag()); 109 109 if (fd < 0) { 110 110 pr_err("Error: sys_perf_event_open() syscall returned " 111 111 "with %d (%s)\n", fd, strerror(errno));
+57
tools/perf/util/cloexec.c
··· 1 + #include "util.h" 2 + #include "../perf.h" 3 + #include "cloexec.h" 4 + #include "asm/bug.h" 5 + 6 + static unsigned long flag = PERF_FLAG_FD_CLOEXEC; 7 + 8 + static int perf_flag_probe(void) 9 + { 10 + /* use 'safest' configuration as used in perf_evsel__fallback() */ 11 + struct perf_event_attr attr = { 12 + .type = PERF_COUNT_SW_CPU_CLOCK, 13 + .config = PERF_COUNT_SW_CPU_CLOCK, 14 + }; 15 + int fd; 16 + int err; 17 + 18 + /* check cloexec flag */ 19 + fd = sys_perf_event_open(&attr, 0, -1, -1, 20 + PERF_FLAG_FD_CLOEXEC); 21 + err = errno; 22 + 23 + if (fd >= 0) { 24 + close(fd); 25 + return 1; 26 + } 27 + 28 + WARN_ONCE(err != EINVAL, 29 + "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", 30 + err, strerror(err)); 31 + 32 + /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ 33 + fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 34 + err = errno; 35 + 36 + if (WARN_ONCE(fd < 0, 37 + "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", 38 + err, strerror(err))) 39 + return -1; 40 + 41 + close(fd); 42 + 43 + return 0; 44 + } 45 + 46 + unsigned long perf_event_open_cloexec_flag(void) 47 + { 48 + static bool probed; 49 + 50 + if (!probed) { 51 + if (perf_flag_probe() <= 0) 52 + flag = 0; 53 + probed = true; 54 + } 55 + 56 + return flag; 57 + }
+6
tools/perf/util/cloexec.h
··· 1 + #ifndef __PERF_CLOEXEC_H 2 + #define __PERF_CLOEXEC_H 3 + 4 + unsigned long perf_event_open_cloexec_flag(void); 5 + 6 + #endif /* __PERF_CLOEXEC_H */
+9 -3
tools/perf/util/evsel.c
··· 29 29 bool sample_id_all; 30 30 bool exclude_guest; 31 31 bool mmap2; 32 + bool cloexec; 32 33 } perf_missing_features; 33 34 34 35 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) ··· 995 994 struct thread_map *threads) 996 995 { 997 996 int cpu, thread; 998 - unsigned long flags = 0; 997 + unsigned long flags = PERF_FLAG_FD_CLOEXEC; 999 998 int pid = -1, err; 1000 999 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; 1001 1000 ··· 1004 1003 return -ENOMEM; 1005 1004 1006 1005 if (evsel->cgrp) { 1007 - flags = PERF_FLAG_PID_CGROUP; 1006 + flags |= PERF_FLAG_PID_CGROUP; 1008 1007 pid = evsel->cgrp->fd; 1009 1008 } 1010 1009 1011 1010 fallback_missing_features: 1011 + if (perf_missing_features.cloexec) 1012 + flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; 1012 1013 if (perf_missing_features.mmap2) 1013 1014 evsel->attr.mmap2 = 0; 1014 1015 if (perf_missing_features.exclude_guest) ··· 1079 1076 if (err != -EINVAL || cpu > 0 || thread > 0) 1080 1077 goto out_close; 1081 1078 1082 - if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { 1079 + if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) { 1080 + perf_missing_features.cloexec = true; 1081 + goto fallback_missing_features; 1082 + } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { 1083 1083 perf_missing_features.mmap2 = true; 1084 1084 goto fallback_missing_features; 1085 1085 } else if (!perf_missing_features.exclude_guest &&
+6 -3
tools/perf/util/record.c
··· 4 4 #include "parse-events.h" 5 5 #include <api/fs/fs.h> 6 6 #include "util.h" 7 + #include "cloexec.h" 7 8 8 9 typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 9 10 ··· 12 11 { 13 12 struct perf_evlist *evlist; 14 13 struct perf_evsel *evsel; 14 + unsigned long flags = perf_event_open_cloexec_flag(); 15 15 int err = -EAGAIN, fd; 16 16 17 17 evlist = perf_evlist__new(); ··· 24 22 25 23 evsel = perf_evlist__first(evlist); 26 24 27 - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 25 + fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); 28 26 if (fd < 0) 29 27 goto out_delete; 30 28 close(fd); 31 29 32 30 fn(evsel); 33 31 34 - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 32 + fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); 35 33 if (fd < 0) { 36 34 if (errno == EINVAL) 37 35 err = -EINVAL; ··· 221 219 cpu = evlist->cpus->map[0]; 222 220 } 223 221 224 - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 222 + fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 223 + perf_event_open_cloexec_flag()); 225 224 if (fd >= 0) { 226 225 close(fd); 227 226 ret = true;