diff options
author | Peter Zijlstra <peterz@infradead.org> | 2016-01-26 06:30:14 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-01-29 02:35:31 -0500 |
commit | f47c02c0c8403963fbb8c3484e285727305d0f73 (patch) | |
tree | 3672f498ef05670f261a8bfbfd66925eca852879 | |
parent | 6e801e016917989ab8a7ddfc4229a15a5621622a (diff) |
perf: Robustify event->owner usage and SMP ordering
Use smp_store_release() to clear event->owner and
lockless_dereference() to observe it. Further use READ_ONCE() for all
lockless reads.
This changes perf_remove_from_owner() to leave event->owner cleared.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Namhyung Kim <namhyung@kernel.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>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | kernel/events/core.c | 20 |
1 files changed, 10 insertions, 10 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index d84374fa44e5..5f055de90c6d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -152,7 +152,7 @@ static void perf_ctx_unlock(struct perf_cpu_context *cpuctx, | |||
152 | 152 | ||
153 | static bool is_kernel_event(struct perf_event *event) | 153 | static bool is_kernel_event(struct perf_event *event) |
154 | { | 154 | { |
155 | return event->owner == TASK_TOMBSTONE; | 155 | return READ_ONCE(event->owner) == TASK_TOMBSTONE; |
156 | } | 156 | } |
157 | 157 | ||
158 | /* | 158 | /* |
@@ -1651,7 +1651,7 @@ out: | |||
1651 | */ | 1651 | */ |
1652 | static bool is_orphaned_event(struct perf_event *event) | 1652 | static bool is_orphaned_event(struct perf_event *event) |
1653 | { | 1653 | { |
1654 | return event && !is_kernel_event(event) && !event->owner; | 1654 | return event && !is_kernel_event(event) && !READ_ONCE(event->owner); |
1655 | } | 1655 | } |
1656 | 1656 | ||
1657 | /* | 1657 | /* |
@@ -3733,14 +3733,13 @@ static void perf_remove_from_owner(struct perf_event *event) | |||
3733 | struct task_struct *owner; | 3733 | struct task_struct *owner; |
3734 | 3734 | ||
3735 | rcu_read_lock(); | 3735 | rcu_read_lock(); |
3736 | owner = ACCESS_ONCE(event->owner); | ||
3737 | /* | 3736 | /* |
3738 | * Matches the smp_wmb() in perf_event_exit_task(). If we observe | 3737 | * Matches the smp_store_release() in perf_event_exit_task(). If we |
3739 | * !owner it means the list deletion is complete and we can indeed | 3738 | * observe !owner it means the list deletion is complete and we can |
3740 | * free this event, otherwise we need to serialize on | 3739 | * indeed free this event, otherwise we need to serialize on |
3741 | * owner->perf_event_mutex. | 3740 | * owner->perf_event_mutex. |
3742 | */ | 3741 | */ |
3743 | smp_read_barrier_depends(); | 3742 | owner = lockless_dereference(event->owner); |
3744 | if (owner) { | 3743 | if (owner) { |
3745 | /* | 3744 | /* |
3746 | * Since delayed_put_task_struct() also drops the last | 3745 | * Since delayed_put_task_struct() also drops the last |
@@ -3768,8 +3767,10 @@ static void perf_remove_from_owner(struct perf_event *event) | |||
3768 | * ensured they're done, and we can proceed with freeing the | 3767 | * ensured they're done, and we can proceed with freeing the |
3769 | * event. | 3768 | * event. |
3770 | */ | 3769 | */ |
3771 | if (event->owner) | 3770 | if (event->owner) { |
3772 | list_del_init(&event->owner_entry); | 3771 | list_del_init(&event->owner_entry); |
3772 | smp_store_release(&event->owner, NULL); | ||
3773 | } | ||
3773 | mutex_unlock(&owner->perf_event_mutex); | 3774 | mutex_unlock(&owner->perf_event_mutex); |
3774 | put_task_struct(owner); | 3775 | put_task_struct(owner); |
3775 | } | 3776 | } |
@@ -8829,8 +8830,7 @@ void perf_event_exit_task(struct task_struct *child) | |||
8829 | * the owner, closes a race against perf_release() where | 8830 | * the owner, closes a race against perf_release() where |
8830 | * we need to serialize on the owner->perf_event_mutex. | 8831 | * we need to serialize on the owner->perf_event_mutex. |
8831 | */ | 8832 | */ |
8832 | smp_wmb(); | 8833 | smp_store_release(&event->owner, NULL); |
8833 | event->owner = NULL; | ||
8834 | } | 8834 | } |
8835 | mutex_unlock(&child->perf_event_mutex); | 8835 | mutex_unlock(&child->perf_event_mutex); |
8836 | 8836 | ||