aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYann Droneaud <ydroneaud@opteya.com>2014-06-30 16:28:47 -0400
committerJiri Olsa <jolsa@kernel.org>2014-07-18 03:09:34 -0400
commit57480d2cd93579d665e57e144e1e63f7f02ef058 (patch)
treea1c628c2bd65a943461479ad52cd4bec179e51d7
parentec6dbcb7ade2a616675cbe3185cf299ee1615c9f (diff)
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>
-rw-r--r--tools/perf/Makefile.perf1
-rw-r--r--tools/perf/bench/mem-memcpy.c4
-rw-r--r--tools/perf/bench/mem-memset.c4
-rw-r--r--tools/perf/builtin-sched.c4
-rw-r--r--tools/perf/tests/bp_signal.c4
-rw-r--r--tools/perf/tests/bp_signal_overflow.c4
-rw-r--r--tools/perf/tests/rdpmc.c4
-rw-r--r--tools/perf/util/cloexec.c57
-rw-r--r--tools/perf/util/cloexec.h6
-rw-r--r--tools/perf/util/evsel.c12
-rw-r--r--tools/perf/util/record.c9
11 files changed, 97 insertions, 12 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 3308b22a1660..2240974b7745 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -376,6 +376,7 @@ LIB_OBJS += $(OUTPUT)util/record.o
376LIB_OBJS += $(OUTPUT)util/srcline.o 376LIB_OBJS += $(OUTPUT)util/srcline.o
377LIB_OBJS += $(OUTPUT)util/data.o 377LIB_OBJS += $(OUTPUT)util/data.o
378LIB_OBJS += $(OUTPUT)util/tsc.o 378LIB_OBJS += $(OUTPUT)util/tsc.o
379LIB_OBJS += $(OUTPUT)util/cloexec.o
379 380
380LIB_OBJS += $(OUTPUT)ui/setup.o 381LIB_OBJS += $(OUTPUT)ui/setup.o
381LIB_OBJS += $(OUTPUT)ui/helpline.o 382LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index e622c3e96efc..2465141b554b 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -10,6 +10,7 @@
10#include "../util/util.h" 10#include "../util/util.h"
11#include "../util/parse-options.h" 11#include "../util/parse-options.h"
12#include "../util/header.h" 12#include "../util/header.h"
13#include "../util/cloexec.h"
13#include "bench.h" 14#include "bench.h"
14#include "mem-memcpy-arch.h" 15#include "mem-memcpy-arch.h"
15 16
@@ -83,7 +84,8 @@ static struct perf_event_attr cycle_attr = {
83 84
84static void init_cycle(void) 85static void init_cycle(void)
85{ 86{
86 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 87 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
88 perf_event_open_cloexec_flag());
87 89
88 if (cycle_fd < 0 && errno == ENOSYS) 90 if (cycle_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 91 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
index 2a65468619f0..75fc3e65fb2a 100644
--- a/tools/perf/bench/mem-memset.c
+++ b/tools/perf/bench/mem-memset.c
@@ -10,6 +10,7 @@
10#include "../util/util.h" 10#include "../util/util.h"
11#include "../util/parse-options.h" 11#include "../util/parse-options.h"
12#include "../util/header.h" 12#include "../util/header.h"
13#include "../util/cloexec.h"
13#include "bench.h" 14#include "bench.h"
14#include "mem-memset-arch.h" 15#include "mem-memset-arch.h"
15 16
@@ -83,7 +84,8 @@ static struct perf_event_attr cycle_attr = {
83 84
84static void init_cycle(void) 85static void init_cycle(void)
85{ 86{
86 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 87 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
88 perf_event_open_cloexec_flag());
87 89
88 if (cycle_fd < 0 && errno == ENOSYS) 90 if (cycle_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 91 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index b7f555add0c8..f83c08c0dd87 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -10,6 +10,7 @@
10#include "util/header.h" 10#include "util/header.h"
11#include "util/session.h" 11#include "util/session.h"
12#include "util/tool.h" 12#include "util/tool.h"
13#include "util/cloexec.h"
13 14
14#include "util/parse-options.h" 15#include "util/parse-options.h"
15#include "util/trace-event.h" 16#include "util/trace-event.h"
@@ -434,7 +435,8 @@ static int self_open_counters(void)
434 attr.type = PERF_TYPE_SOFTWARE; 435 attr.type = PERF_TYPE_SOFTWARE;
435 attr.config = PERF_COUNT_SW_TASK_CLOCK; 436 attr.config = PERF_COUNT_SW_TASK_CLOCK;
436 437
437 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 438 fd = sys_perf_event_open(&attr, 0, -1, -1,
439 perf_event_open_cloexec_flag());
438 440
439 if (fd < 0) 441 if (fd < 0)
440 pr_err("Error: sys_perf_event_open() syscall returned " 442 pr_err("Error: sys_perf_event_open() syscall returned "
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index aba095489193..a02b035fd5aa 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -25,6 +25,7 @@
25#include "tests.h" 25#include "tests.h"
26#include "debug.h" 26#include "debug.h"
27#include "perf.h" 27#include "perf.h"
28#include "cloexec.h"
28 29
29static int fd1; 30static int fd1;
30static int fd2; 31static int fd2;
@@ -78,7 +79,8 @@ static int bp_event(void *fn, int setup_signal)
78 pe.exclude_kernel = 1; 79 pe.exclude_kernel = 1;
79 pe.exclude_hv = 1; 80 pe.exclude_hv = 1;
80 81
81 fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 82 fd = sys_perf_event_open(&pe, 0, -1, -1,
83 perf_event_open_cloexec_flag());
82 if (fd < 0) { 84 if (fd < 0) {
83 pr_debug("failed opening event %llx\n", pe.config); 85 pr_debug("failed opening event %llx\n", pe.config);
84 return TEST_FAIL; 86 return TEST_FAIL;
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
index 44ac82179708..e76537724491 100644
--- a/tools/perf/tests/bp_signal_overflow.c
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -24,6 +24,7 @@
24#include "tests.h" 24#include "tests.h"
25#include "debug.h" 25#include "debug.h"
26#include "perf.h" 26#include "perf.h"
27#include "cloexec.h"
27 28
28static int overflows; 29static int overflows;
29 30
@@ -91,7 +92,8 @@ int test__bp_signal_overflow(void)
91 pe.exclude_kernel = 1; 92 pe.exclude_kernel = 1;
92 pe.exclude_hv = 1; 93 pe.exclude_hv = 1;
93 94
94 fd = sys_perf_event_open(&pe, 0, -1, -1, 0); 95 fd = sys_perf_event_open(&pe, 0, -1, -1,
96 perf_event_open_cloexec_flag());
95 if (fd < 0) { 97 if (fd < 0) {
96 pr_debug("failed opening event %llx\n", pe.config); 98 pr_debug("failed opening event %llx\n", pe.config);
97 return TEST_FAIL; 99 return TEST_FAIL;
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
index e59143fd9e71..c04d1f268576 100644
--- a/tools/perf/tests/rdpmc.c
+++ b/tools/perf/tests/rdpmc.c
@@ -6,6 +6,7 @@
6#include "perf.h" 6#include "perf.h"
7#include "debug.h" 7#include "debug.h"
8#include "tests.h" 8#include "tests.h"
9#include "cloexec.h"
9 10
10#if defined(__x86_64__) || defined(__i386__) 11#if defined(__x86_64__) || defined(__i386__)
11 12
@@ -104,7 +105,8 @@ static int __test__rdpmc(void)
104 sa.sa_sigaction = segfault_handler; 105 sa.sa_sigaction = segfault_handler;
105 sigaction(SIGSEGV, &sa, NULL); 106 sigaction(SIGSEGV, &sa, NULL);
106 107
107 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 108 fd = sys_perf_event_open(&attr, 0, -1, -1,
109 perf_event_open_cloexec_flag());
108 if (fd < 0) { 110 if (fd < 0) {
109 pr_err("Error: sys_perf_event_open() syscall returned " 111 pr_err("Error: sys_perf_event_open() syscall returned "
110 "with %d (%s)\n", fd, strerror(errno)); 112 "with %d (%s)\n", fd, strerror(errno));
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c
new file mode 100644
index 000000000000..c5d05ec17220
--- /dev/null
+++ b/tools/perf/util/cloexec.c
@@ -0,0 +1,57 @@
1#include "util.h"
2#include "../perf.h"
3#include "cloexec.h"
4#include "asm/bug.h"
5
6static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
7
8static 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
46unsigned 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}
diff --git a/tools/perf/util/cloexec.h b/tools/perf/util/cloexec.h
new file mode 100644
index 000000000000..94a5a7d829d5
--- /dev/null
+++ b/tools/perf/util/cloexec.h
@@ -0,0 +1,6 @@
1#ifndef __PERF_CLOEXEC_H
2#define __PERF_CLOEXEC_H
3
4unsigned long perf_event_open_cloexec_flag(void);
5
6#endif /* __PERF_CLOEXEC_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 90f58cdd0fb0..21a373ebea22 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -29,6 +29,7 @@ static struct {
29 bool sample_id_all; 29 bool sample_id_all;
30 bool exclude_guest; 30 bool exclude_guest;
31 bool mmap2; 31 bool mmap2;
32 bool cloexec;
32} perf_missing_features; 33} perf_missing_features;
33 34
34#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 35#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
@@ -994,7 +995,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
994 struct thread_map *threads) 995 struct thread_map *threads)
995{ 996{
996 int cpu, thread; 997 int cpu, thread;
997 unsigned long flags = 0; 998 unsigned long flags = PERF_FLAG_FD_CLOEXEC;
998 int pid = -1, err; 999 int pid = -1, err;
999 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; 1000 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
1000 1001
@@ -1003,11 +1004,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
1003 return -ENOMEM; 1004 return -ENOMEM;
1004 1005
1005 if (evsel->cgrp) { 1006 if (evsel->cgrp) {
1006 flags = PERF_FLAG_PID_CGROUP; 1007 flags |= PERF_FLAG_PID_CGROUP;
1007 pid = evsel->cgrp->fd; 1008 pid = evsel->cgrp->fd;
1008 } 1009 }
1009 1010
1010fallback_missing_features: 1011fallback_missing_features:
1012 if (perf_missing_features.cloexec)
1013 flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC;
1011 if (perf_missing_features.mmap2) 1014 if (perf_missing_features.mmap2)
1012 evsel->attr.mmap2 = 0; 1015 evsel->attr.mmap2 = 0;
1013 if (perf_missing_features.exclude_guest) 1016 if (perf_missing_features.exclude_guest)
@@ -1076,7 +1079,10 @@ try_fallback:
1076 if (err != -EINVAL || cpu > 0 || thread > 0) 1079 if (err != -EINVAL || cpu > 0 || thread > 0)
1077 goto out_close; 1080 goto out_close;
1078 1081
1079 if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { 1082 if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) {
1083 perf_missing_features.cloexec = true;
1084 goto fallback_missing_features;
1085 } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
1080 perf_missing_features.mmap2 = true; 1086 perf_missing_features.mmap2 = true;
1081 goto fallback_missing_features; 1087 goto fallback_missing_features;
1082 } else if (!perf_missing_features.exclude_guest && 1088 } else if (!perf_missing_features.exclude_guest &&
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 165723152cfb..fe8079edbdc1 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -4,6 +4,7 @@
4#include "parse-events.h" 4#include "parse-events.h"
5#include <api/fs/fs.h> 5#include <api/fs/fs.h>
6#include "util.h" 6#include "util.h"
7#include "cloexec.h"
7 8
8typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 9typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
9 10
@@ -11,6 +12,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
11{ 12{
12 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
13 struct perf_evsel *evsel; 14 struct perf_evsel *evsel;
15 unsigned long flags = perf_event_open_cloexec_flag();
14 int err = -EAGAIN, fd; 16 int err = -EAGAIN, fd;
15 17
16 evlist = perf_evlist__new(); 18 evlist = perf_evlist__new();
@@ -22,14 +24,14 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
22 24
23 evsel = perf_evlist__first(evlist); 25 evsel = perf_evlist__first(evlist);
24 26
25 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 27 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
26 if (fd < 0) 28 if (fd < 0)
27 goto out_delete; 29 goto out_delete;
28 close(fd); 30 close(fd);
29 31
30 fn(evsel); 32 fn(evsel);
31 33
32 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 34 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
33 if (fd < 0) { 35 if (fd < 0) {
34 if (errno == EINVAL) 36 if (errno == EINVAL)
35 err = -EINVAL; 37 err = -EINVAL;
@@ -219,7 +221,8 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
219 cpu = evlist->cpus->map[0]; 221 cpu = evlist->cpus->map[0];
220 } 222 }
221 223
222 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 224 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
225 perf_event_open_cloexec_flag());
223 if (fd >= 0) { 226 if (fd >= 0) {
224 close(fd); 227 close(fd);
225 ret = true; 228 ret = true;