Skip to content

Commit 6ce77bf

Browse files
virtuosoIngo Molnar
authored andcommitted
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 <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mathieu Poirier <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vince Weaver <[email protected]> Cc: Will Deacon <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 9ccbfbb commit 6ce77bf

File tree

2 files changed

+30
-14
lines changed

2 files changed

+30
-14
lines changed

include/linux/perf_event.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,13 +482,15 @@ struct perf_addr_filter {
482482
* @list: list of filters for this event
483483
* @lock: spinlock that serializes accesses to the @list and event's
484484
* (and its children's) filter generations.
485+
* @nr_file_filters: number of file-based filters
485486
*
486487
* A child event will use parent's @list (and therefore @lock), so they are
487488
* bundled together; see perf_event_addr_filters().
488489
*/
489490
struct perf_addr_filters_head {
490491
struct list_head list;
491492
raw_spinlock_t lock;
493+
unsigned int nr_file_filters;
492494
};
493495

494496
/**

kernel/events/core.c

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8090,6 +8090,9 @@ static void perf_event_addr_filters_apply(struct perf_event *event)
80908090
if (task == TASK_TOMBSTONE)
80918091
return;
80928092

8093+
if (!ifh->nr_file_filters)
8094+
return;
8095+
80938096
mm = get_task_mm(event->ctx->task);
80948097
if (!mm)
80958098
goto restart;
@@ -8268,6 +8271,18 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
82688271
if (!filename)
82698272
goto fail;
82708273

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+
82718286
/* look up the path and grab its inode */
82728287
ret = kern_path(filename, LOOKUP_FOLLOW, &path);
82738288
if (ret)
@@ -8283,6 +8298,8 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
82838298
!S_ISREG(filter->inode->i_mode))
82848299
/* free_filters_list() will iput() */
82858300
goto fail;
8301+
8302+
event->addr_filters.nr_file_filters++;
82868303
}
82878304

82888305
/* ready to consume more filters */
@@ -8322,31 +8339,28 @@ perf_event_set_addr_filter(struct perf_event *event, char *filter_str)
83228339
if (WARN_ON_ONCE(event->parent))
83238340
return -EINVAL;
83248341

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-
83348342
ret = perf_event_parse_addr_filter(event, filter_str, &filters);
83358343
if (ret)
8336-
return ret;
8344+
goto fail_clear_files;
83378345

83388346
ret = event->pmu->addr_filters_validate(&filters);
8339-
if (ret) {
8340-
free_filters_list(&filters);
8341-
return ret;
8342-
}
8347+
if (ret)
8348+
goto fail_free_filters;
83438349

83448350
/* remove existing filters, if any */
83458351
perf_addr_filters_splice(event, &filters);
83468352

83478353
/* install new filters */
83488354
perf_event_for_each_child(event, perf_event_addr_filters_apply);
83498355

8356+
return ret;
8357+
8358+
fail_free_filters:
8359+
free_filters_list(&filters);
8360+
8361+
fail_clear_files:
8362+
event->addr_filters.nr_file_filters = 0;
8363+
83508364
return ret;
83518365
}
83528366

0 commit comments

Comments
 (0)