aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2017-01-26 04:40:57 -0500
committerIngo Molnar <mingo@kernel.org>2017-02-10 03:08:09 -0500
commit6ce77bfd6cedbff61eabf8837dc0901bb671cc86 (patch)
tree74f328eab379a5c713bbf5c6056313473814216f
parent9ccbfbb157a38921702402281ca7be530b4c3669 (diff)
perf/core: Allow kernel filters on CPU events
While supporting file-based address filters for CPU events requires some extra context switch handling, kernel address filters are easy, since the kernel mapping is preserved across address spaces. It is also useful as it permits tracing scheduling paths of the kernel. This patch allows setting up kernel filters for CPU events. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mathieu Poirier <mathieu.poirier@linaro.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Cc: Will Deacon <will.deacon@arm.com> Cc: vince@deater.net Link: http://lkml.kernel.org/r/20170126094057.13805-4-alexander.shishkin@linux.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/perf_event.h2
-rw-r--r--kernel/events/core.c42
2 files changed, 30 insertions, 14 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 5c58e93c130c..000fdb211c7d 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -482,6 +482,7 @@ struct perf_addr_filter {
482 * @list: list of filters for this event 482 * @list: list of filters for this event
483 * @lock: spinlock that serializes accesses to the @list and event's 483 * @lock: spinlock that serializes accesses to the @list and event's
484 * (and its children's) filter generations. 484 * (and its children's) filter generations.
485 * @nr_file_filters: number of file-based filters
485 * 486 *
486 * A child event will use parent's @list (and therefore @lock), so they are 487 * A child event will use parent's @list (and therefore @lock), so they are
487 * bundled together; see perf_event_addr_filters(). 488 * bundled together; see perf_event_addr_filters().
@@ -489,6 +490,7 @@ struct perf_addr_filter {
489struct perf_addr_filters_head { 490struct perf_addr_filters_head {
490 struct list_head list; 491 struct list_head list;
491 raw_spinlock_t lock; 492 raw_spinlock_t lock;
493 unsigned int nr_file_filters;
492}; 494};
493 495
494/** 496/**
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1730995c31ec..a8664247b3e4 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8090,6 +8090,9 @@ static void perf_event_addr_filters_apply(struct perf_event *event)
8090 if (task == TASK_TOMBSTONE) 8090 if (task == TASK_TOMBSTONE)
8091 return; 8091 return;
8092 8092
8093 if (!ifh->nr_file_filters)
8094 return;
8095
8093 mm = get_task_mm(event->ctx->task); 8096 mm = get_task_mm(event->ctx->task);
8094 if (!mm) 8097 if (!mm)
8095 goto restart; 8098 goto restart;
@@ -8268,6 +8271,18 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
8268 if (!filename) 8271 if (!filename)
8269 goto fail; 8272 goto fail;
8270 8273
8274 /*
8275 * For now, we only support file-based filters
8276 * in per-task events; doing so for CPU-wide
8277 * events requires additional context switching
8278 * trickery, since same object code will be
8279 * mapped at different virtual addresses in
8280 * different processes.
8281 */
8282 ret = -EOPNOTSUPP;
8283 if (!event->ctx->task)
8284 goto fail_free_name;
8285
8271 /* look up the path and grab its inode */ 8286 /* look up the path and grab its inode */
8272 ret = kern_path(filename, LOOKUP_FOLLOW, &path); 8287 ret = kern_path(filename, LOOKUP_FOLLOW, &path);
8273 if (ret) 8288 if (ret)
@@ -8283,6 +8298,8 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
8283 !S_ISREG(filter->inode->i_mode)) 8298 !S_ISREG(filter->inode->i_mode))
8284 /* free_filters_list() will iput() */ 8299 /* free_filters_list() will iput() */
8285 goto fail; 8300 goto fail;
8301
8302 event->addr_filters.nr_file_filters++;
8286 } 8303 }
8287 8304
8288 /* ready to consume more filters */ 8305 /* ready to consume more filters */
@@ -8322,24 +8339,13 @@ perf_event_set_addr_filter(struct perf_event *event, char *filter_str)
8322 if (WARN_ON_ONCE(event->parent)) 8339 if (WARN_ON_ONCE(event->parent))
8323 return -EINVAL; 8340 return -EINVAL;
8324 8341
8325 /*
8326 * For now, we only support filtering in per-task events; doing so
8327 * for CPU-wide events requires additional context switching trickery,
8328 * since same object code will be mapped at different virtual
8329 * addresses in different processes.
8330 */
8331 if (!event->ctx->task)
8332 return -EOPNOTSUPP;
8333
8334 ret = perf_event_parse_addr_filter(event, filter_str, &filters); 8342 ret = perf_event_parse_addr_filter(event, filter_str, &filters);
8335 if (ret) 8343 if (ret)
8336 return ret; 8344 goto fail_clear_files;
8337 8345
8338 ret = event->pmu->addr_filters_validate(&filters); 8346 ret = event->pmu->addr_filters_validate(&filters);
8339 if (ret) { 8347 if (ret)
8340 free_filters_list(&filters); 8348 goto fail_free_filters;
8341 return ret;
8342 }
8343 8349
8344 /* remove existing filters, if any */ 8350 /* remove existing filters, if any */
8345 perf_addr_filters_splice(event, &filters); 8351 perf_addr_filters_splice(event, &filters);
@@ -8348,6 +8354,14 @@ perf_event_set_addr_filter(struct perf_event *event, char *filter_str)
8348 perf_event_for_each_child(event, perf_event_addr_filters_apply); 8354 perf_event_for_each_child(event, perf_event_addr_filters_apply);
8349 8355
8350 return ret; 8356 return ret;
8357
8358fail_free_filters:
8359 free_filters_list(&filters);
8360
8361fail_clear_files:
8362 event->addr_filters.nr_file_filters = 0;
8363
8364 return ret;
8351} 8365}
8352 8366
8353static int perf_event_set_filter(struct perf_event *event, void __user *arg) 8367static int perf_event_set_filter(struct perf_event *event, void __user *arg)