[tip:perf/core] perf core: Per event callchain limit

2016-06-02 Thread tip-bot for Arnaldo Carvalho de Melo
Commit-ID:  97c79a38cd454602645f0470ffb444b3b75ce574
Gitweb: http://git.kernel.org/tip/97c79a38cd454602645f0470ffb444b3b75ce574
Author: Arnaldo Carvalho de Melo 
AuthorDate: Thu, 28 Apr 2016 13:16:33 -0300
Committer:  Arnaldo Carvalho de Melo 
CommitDate: Mon, 30 May 2016 12:41:44 -0300

perf core: Per event callchain limit

Additionally to being able to control the system wide maximum depth via
/proc/sys/kernel/perf_event_max_stack, now we are able to ask for
different depths per event, using perf_event_attr.sample_max_stack for
that.

This uses an u16 hole at the end of perf_event_attr, that, when
perf_event_attr.sample_type has the PERF_SAMPLE_CALLCHAIN, if
sample_max_stack is zero, means use perf_event_max_stack, otherwise
it'll be bounds checked under callchain_mutex.

Cc: Adrian Hunter 
Cc: Alexander Shishkin 
Cc: Alexei Starovoitov 
Cc: Brendan Gregg 
Cc: David Ahern 
Cc: Frederic Weisbecker 
Cc: He Kuang 
Cc: Jiri Olsa 
Cc: Linus Torvalds 
Cc: Masami Hiramatsu 
Cc: Milian Wolff 
Cc: Namhyung Kim 
Cc: Peter Zijlstra 
Cc: Stephane Eranian 
Cc: Thomas Gleixner 
Cc: Vince Weaver 
Cc: Wang Nan 
Cc: Zefan Li 
Link: http://lkml.kernel.org/n/tip-kolmn1yo40p7jhswxwrc7...@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo 
---
 include/linux/perf_event.h  |  2 +-
 include/uapi/linux/perf_event.h |  6 +-
 kernel/bpf/stackmap.c   |  2 +-
 kernel/events/callchain.c   | 14 --
 kernel/events/core.c|  5 -
 5 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 6b87be9..0e43355 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1076,7 +1076,7 @@ extern void perf_callchain_kernel(struct 
perf_callchain_entry_ctx *entry, struct
 extern struct perf_callchain_entry *
 get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
   u32 max_stack, bool crosstask, bool add_mark);
-extern int get_callchain_buffers(void);
+extern int get_callchain_buffers(int max_stack);
 extern void put_callchain_buffers(void);
 
 extern int sysctl_perf_event_max_stack;
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 36ce552..c66a485 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -276,6 +276,9 @@ enum perf_event_read_format {
 
 /*
  * Hardware event_id to monitor via a performance monitoring event:
+ *
+ * @sample_max_stack: Max number of frame pointers in a callchain,
+ *   should be < /proc/sys/kernel/perf_event_max_stack
  */
 struct perf_event_attr {
 
@@ -385,7 +388,8 @@ struct perf_event_attr {
 * Wakeup watermark for AUX area
 */
__u32   aux_watermark;
-   __u32   __reserved_2;   /* align to __u64 */
+   __u16   sample_max_stack;
+   __u16   __reserved_2;   /* align to __u64 */
 };
 
 #define perf_flags(attr)   (*(&(attr)->read_format + 1))
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index a82d760..f1de5c1 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -99,7 +99,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
if (err)
goto free_smap;
 
-   err = get_callchain_buffers();
+   err = get_callchain_buffers(sysctl_perf_event_max_stack);
if (err)
goto free_smap;
 
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index 179ef46..e9fdb52 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -104,7 +104,7 @@ fail:
return -ENOMEM;
 }
 
-int get_callchain_buffers(void)
+int get_callchain_buffers(int event_max_stack)
 {
int err = 0;
int count;
@@ -121,6 +121,15 @@ int get_callchain_buffers(void)
/* If the allocation failed, give up */
if (!callchain_cpus_entries)
err = -ENOMEM;
+   /*
+* If requesting per event more than the global cap,
+* return a different error to help userspace figure
+* this out.
+*
+* And also do it here so that we have _mutex held.
+*/
+   if (event_max_stack > sysctl_perf_event_max_stack)
+   err = -EOVERFLOW;
goto exit;
}
 
@@ -174,11 +183,12 @@ perf_callchain(struct perf_event *event, struct pt_regs 
*regs)
bool user   = !event->attr.exclude_callchain_user;
  

[tip:perf/core] perf core: Per event callchain limit

2016-06-02 Thread tip-bot for Arnaldo Carvalho de Melo
Commit-ID:  97c79a38cd454602645f0470ffb444b3b75ce574
Gitweb: http://git.kernel.org/tip/97c79a38cd454602645f0470ffb444b3b75ce574
Author: Arnaldo Carvalho de Melo 
AuthorDate: Thu, 28 Apr 2016 13:16:33 -0300
Committer:  Arnaldo Carvalho de Melo 
CommitDate: Mon, 30 May 2016 12:41:44 -0300

perf core: Per event callchain limit

Additionally to being able to control the system wide maximum depth via
/proc/sys/kernel/perf_event_max_stack, now we are able to ask for
different depths per event, using perf_event_attr.sample_max_stack for
that.

This uses an u16 hole at the end of perf_event_attr, that, when
perf_event_attr.sample_type has the PERF_SAMPLE_CALLCHAIN, if
sample_max_stack is zero, means use perf_event_max_stack, otherwise
it'll be bounds checked under callchain_mutex.

Cc: Adrian Hunter 
Cc: Alexander Shishkin 
Cc: Alexei Starovoitov 
Cc: Brendan Gregg 
Cc: David Ahern 
Cc: Frederic Weisbecker 
Cc: He Kuang 
Cc: Jiri Olsa 
Cc: Linus Torvalds 
Cc: Masami Hiramatsu 
Cc: Milian Wolff 
Cc: Namhyung Kim 
Cc: Peter Zijlstra 
Cc: Stephane Eranian 
Cc: Thomas Gleixner 
Cc: Vince Weaver 
Cc: Wang Nan 
Cc: Zefan Li 
Link: http://lkml.kernel.org/n/tip-kolmn1yo40p7jhswxwrc7...@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo 
---
 include/linux/perf_event.h  |  2 +-
 include/uapi/linux/perf_event.h |  6 +-
 kernel/bpf/stackmap.c   |  2 +-
 kernel/events/callchain.c   | 14 --
 kernel/events/core.c|  5 -
 5 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 6b87be9..0e43355 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1076,7 +1076,7 @@ extern void perf_callchain_kernel(struct 
perf_callchain_entry_ctx *entry, struct
 extern struct perf_callchain_entry *
 get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
   u32 max_stack, bool crosstask, bool add_mark);
-extern int get_callchain_buffers(void);
+extern int get_callchain_buffers(int max_stack);
 extern void put_callchain_buffers(void);
 
 extern int sysctl_perf_event_max_stack;
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 36ce552..c66a485 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -276,6 +276,9 @@ enum perf_event_read_format {
 
 /*
  * Hardware event_id to monitor via a performance monitoring event:
+ *
+ * @sample_max_stack: Max number of frame pointers in a callchain,
+ *   should be < /proc/sys/kernel/perf_event_max_stack
  */
 struct perf_event_attr {
 
@@ -385,7 +388,8 @@ struct perf_event_attr {
 * Wakeup watermark for AUX area
 */
__u32   aux_watermark;
-   __u32   __reserved_2;   /* align to __u64 */
+   __u16   sample_max_stack;
+   __u16   __reserved_2;   /* align to __u64 */
 };
 
 #define perf_flags(attr)   (*(&(attr)->read_format + 1))
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index a82d760..f1de5c1 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -99,7 +99,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
if (err)
goto free_smap;
 
-   err = get_callchain_buffers();
+   err = get_callchain_buffers(sysctl_perf_event_max_stack);
if (err)
goto free_smap;
 
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index 179ef46..e9fdb52 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -104,7 +104,7 @@ fail:
return -ENOMEM;
 }
 
-int get_callchain_buffers(void)
+int get_callchain_buffers(int event_max_stack)
 {
int err = 0;
int count;
@@ -121,6 +121,15 @@ int get_callchain_buffers(void)
/* If the allocation failed, give up */
if (!callchain_cpus_entries)
err = -ENOMEM;
+   /*
+* If requesting per event more than the global cap,
+* return a different error to help userspace figure
+* this out.
+*
+* And also do it here so that we have _mutex held.
+*/
+   if (event_max_stack > sysctl_perf_event_max_stack)
+   err = -EOVERFLOW;
goto exit;
}
 
@@ -174,11 +183,12 @@ perf_callchain(struct perf_event *event, struct pt_regs 
*regs)
bool user   = !event->attr.exclude_callchain_user;
/* Disallow cross-task user callchains. */
bool crosstask = event->ctx->task && event->ctx->task != current;
+   const u32 max_stack = event->attr.sample_max_stack;
 
if (!kernel && !user)
return NULL;
 
-   return get_perf_callchain(regs, 0, kernel, user, 
sysctl_perf_event_max_stack, crosstask, true);
+   return get_perf_callchain(regs, 0, kernel, user, max_stack, crosstask, 
true);
 }
 
 struct