lkml.org 
[lkml]   [2017]   [Jan]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH 3/3] perf: Allow kernel filters on cpu events
    On Thu, Jan 26, 2017 at 11:40:57AM +0200, Alexander Shishkin wrote:
    > 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>
    > Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
    > ---
    > include/linux/perf_event.h | 2 ++
    > kernel/events/core.c | 42 ++++++++++++++++++++++++++++--------------
    > 2 files changed, 30 insertions(+), 14 deletions(-)
    >
    > diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
    > index fcb37c81ca..f4ea0600b2 100644
    > --- a/include/linux/perf_event.h
    > +++ b/include/linux/perf_event.h
    > @@ -486,6 +486,7 @@ struct perf_addr_filter {
    > * @list: list of filters for this event
    > * @lock: spinlock that serializes accesses to the @list and event's
    > * (and its children's) filter generations.
    > + * @nr_file_filters: number of file-based filters
    > *
    > * A child event will use parent's @list (and therefore @lock), so they are
    > * bundled together; see perf_event_addr_filters().
    > @@ -493,6 +494,7 @@ struct perf_addr_filter {
    > struct perf_addr_filters_head {
    > struct list_head list;
    > raw_spinlock_t lock;
    > + unsigned int nr_file_filters;
    > };
    >
    > /**
    > diff --git a/kernel/events/core.c b/kernel/events/core.c
    > index 36770a13ef..2eeb8fec2f 100644
    > --- a/kernel/events/core.c
    > +++ b/kernel/events/core.c
    > @@ -8093,6 +8093,9 @@ static void perf_event_addr_filters_apply(struct perf_event *event)
    > if (task == TASK_TOMBSTONE)
    > return;
    >
    > + if (!ifh->nr_file_filters)
    > + return;

    Is this mandatory or an optimisation to avoid circling through a list of filters
    that don't included user space files?

    > +
    > mm = get_task_mm(event->ctx->task);
    > if (!mm)
    > goto restart;
    > @@ -8269,6 +8272,18 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
    > if (!filename)
    > goto fail;
    >
    > + /*
    > + * For now, we only support file-based filters
    > + * in per-task events; doing so for CPU-wide
    > + * events requires additional context switching
    > + * trickery, since same object code will be
    > + * mapped at different virtual addresses in
    > + * different processes.
    > + */
    > + ret = -EOPNOTSUPP;
    > + if (!event->ctx->task)
    > + goto fail_free_name;
    > +
    > /* look up the path and grab its inode */
    > ret = kern_path(filename, LOOKUP_FOLLOW, &path);
    > if (ret)
    > @@ -8284,6 +8299,8 @@ perf_event_parse_addr_filter(struct perf_event *event, char *fstr,
    > !S_ISREG(filter->inode->i_mode))
    > /* free_filters_list() will iput() */
    > goto fail;
    > +
    > + event->addr_filters.nr_file_filters++;
    > }
    >
    > /* ready to consume more filters */
    > @@ -8323,24 +8340,13 @@ perf_event_set_addr_filter(struct perf_event *event, char *filter_str)
    > if (WARN_ON_ONCE(event->parent))
    > return -EINVAL;
    >
    > - /*
    > - * For now, we only support filtering in per-task events; doing so
    > - * for CPU-wide events requires additional context switching trickery,
    > - * since same object code will be mapped at different virtual
    > - * addresses in different processes.
    > - */
    > - if (!event->ctx->task)
    > - return -EOPNOTSUPP;
    > -
    > ret = perf_event_parse_addr_filter(event, filter_str, &filters);
    > if (ret)
    > - return ret;
    > + goto fail_clear_files;
    >
    > ret = event->pmu->addr_filters_validate(&filters);
    > - if (ret) {
    > - free_filters_list(&filters);
    > - return ret;
    > - }
    > + if (ret)
    > + goto fail_free_filters;
    >
    > /* remove existing filters, if any */
    > perf_addr_filters_splice(event, &filters);
    > @@ -8349,6 +8355,14 @@ perf_event_set_addr_filter(struct perf_event *event, char *filter_str)
    > perf_event_for_each_child(event, perf_event_addr_filters_apply);
    >
    > return ret;
    > +
    > +fail_free_filters:
    > + free_filters_list(&filters);
    > +
    > +fail_clear_files:
    > + event->addr_filters.nr_file_filters = 0;
    > +
    > + return ret;
    > }
    >
    > static int perf_event_set_filter(struct perf_event *event, void __user *arg)
    > --
    > 2.11.0
    >

    \
     
     \ /
      Last update: 2017-01-26 22:40    [W:4.412 / U:0.264 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site