| From 0231bb5336758426b44ccd798ccd3c5419c95d58 Mon Sep 17 00:00:00 2001 |
| From: Jiri Olsa <jolsa@redhat.com> |
| Date: Fri, 1 Feb 2013 11:23:45 +0100 |
| Subject: perf: Fix event group context move |
| |
| From: Jiri Olsa <jolsa@redhat.com> |
| |
| commit 0231bb5336758426b44ccd798ccd3c5419c95d58 upstream. |
| |
| When we have group with mixed events (hw/sw) we want to end up |
| with group leader being in hw context. So if group leader is |
| initialy sw event, we move all the events under hw context. |
| |
| The move is done for each event by removing it from its context |
| and adding it back into proper one. As a part of the removal the |
| event is automatically disabled, which is not what we want at |
| this stage of creating groups. |
| |
| The fix is to initialize event state after removal from sw |
| context. |
| |
| This fix resulted from the following discussion: |
| |
| http://thread.gmane.org/gmane.linux.kernel.perf.user/1144 |
| |
| Reported-by: Andreas Hollmann <hollmann@in.tum.de> |
| Signed-off-by: Jiri Olsa <jolsa@redhat.com> |
| Cc: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Cc: Namhyung Kim <namhyung@kernel.org> |
| Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> |
| Cc: Frederic Weisbecker <fweisbec@gmail.com> |
| Cc: Paul Mackerras <paulus@samba.org> |
| Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> |
| Cc: Stephane Eranian <eranian@google.com> |
| Cc: Vince Weaver <vince@deater.net> |
| Link: http://lkml.kernel.org/r/1359714225-4231-1-git-send-email-jolsa@redhat.com |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Cc: Li Zefan <lizefan@huawei.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/events/core.c | 20 ++++++++++++++++++-- |
| 1 file changed, 18 insertions(+), 2 deletions(-) |
| |
| --- a/kernel/events/core.c |
| +++ b/kernel/events/core.c |
| @@ -839,6 +839,15 @@ list_add_event(struct perf_event *event, |
| } |
| |
| /* |
| + * Initialize event state based on the perf_event_attr::disabled. |
| + */ |
| +static inline void perf_event__state_init(struct perf_event *event) |
| +{ |
| + event->state = event->attr.disabled ? PERF_EVENT_STATE_OFF : |
| + PERF_EVENT_STATE_INACTIVE; |
| +} |
| + |
| +/* |
| * Called at perf_event creation and when events are attached/detached from a |
| * group. |
| */ |
| @@ -6241,8 +6250,7 @@ perf_event_alloc(struct perf_event_attr |
| |
| event->overflow_handler = overflow_handler; |
| |
| - if (attr->disabled) |
| - event->state = PERF_EVENT_STATE_OFF; |
| + perf_event__state_init(event); |
| |
| pmu = NULL; |
| |
| @@ -6616,9 +6624,17 @@ SYSCALL_DEFINE5(perf_event_open, |
| |
| mutex_lock(&gctx->mutex); |
| perf_remove_from_context(group_leader); |
| + |
| + /* |
| + * Removing from the context ends up with disabled |
| + * event. What we want here is event in the initial |
| + * startup state, ready to be add into new context. |
| + */ |
| + perf_event__state_init(group_leader); |
| list_for_each_entry(sibling, &group_leader->sibling_list, |
| group_entry) { |
| perf_remove_from_context(sibling); |
| + perf_event__state_init(sibling); |
| put_ctx(gctx); |
| } |
| mutex_unlock(&gctx->mutex); |