Patch "perf: Fix AUX buffer refcounting" has been added to the 4.1-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
perf: Fix AUX buffer refcounting
to the 4.1-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
perf-fix-aux-buffer-refcounting.patch
and it can be found in the queue-4.1 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
57ffc5ca679f499f4704fd9b6a372916f59930eeMon Sep 17 00:00:00 2001
From: Peter Zijlstra <[email protected]>
Date: Thu, 18 Jun 2015 12:32:49 +0200
Subject: perf: Fix AUX buffer refcounting
From: Peter Zijlstra <[email protected]>
commit 57ffc5ca679f499f4704fd9b6a372916f59930ee upstream.
Its currently possible to drop the last refcount to the aux buffer from NMI context, which results in the expected fireworks.
The refcounting needs a bigger overhaul, but to cure the immediate problem, delay the freeing by using an irq_work.
--- kernel/events/core.c | 8 -------- kernel/events/internal.h | 10 ++++++++++ kernel/events/ring_buffer.c | 27 +++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 10 deletions(-)
kernel/events/core.c +0 -8
@@ -4411,14 +4411,6 @@ static void ring_buffer_wakeup(struct percu_read_unlock (); } -static void rb_free_rcu (struct rcu_head *rcu_head) -{ -struct ring_buffer *rb; - - rb = container_of(rcu_head, struct ring_buffer, rcu_head); -rb_free (rb); -} -struct ring_buffer *ring_buffer_get (struct perf_event *event) {struct ring_buffer *rb;
kernel/events/internal.h +10 -0
@@ -11,6 +11,7 @@struct ring_buffer {atomic_t refcount;struct rcu_head rcu_head; +struct irq_work irq_work;#ifdef CONFIG_PERF_USE_VMALLOC struct work_struct work;int page_order;/* allocation order */
@@ -55,6 +56,15 @@ struct ring_buffer { };extern void rb_free (struct ring_buffer *rb); + +static inline void rb_free_rcu (struct rcu_head *rcu_head) +{ +struct ring_buffer *rb; + + rb = container_of(rcu_head, struct ring_buffer, rcu_head); +rb_free (rb); +} +extern struct ring_buffer *rb_alloc (int nr_pages,long watermark,int cpu,int flags);extern void perf_event_wakeup (struct perf_event *event);
kernel/events/ring_buffer.c +25 -2
@@ -221,6 +221,8 @@ void perf_output_end(struct perf_output_rcu_read_unlock (); } +static void rb_irq_work (struct irq_work *work); +static void ring_buffer_init (struct ring_buffer *rb,long watermark,int flags) {
@@ -241,6 +243,16 @@ ring_buffer_init(struct ring_buffer *rb,INIT_LIST_HEAD (&rb->event_list);spin_lock_init (&rb->event_lock); +init_irq_work (&rb->irq_work, rb_irq_work); +} + +static void ring_buffer_put_async (struct ring_buffer *rb) +{ +if (!atomic_dec_and_test (&rb->refcount)) +return ; + + rb->rcu_head.next = (void *)rb; +irq_work_queue (&rb->irq_work); }/*
@@ -319,7 +331,7 @@ err_put:rb_free_aux (rb); err: -ring_buffer_put (rb); +ring_buffer_put_async (rb); handle->event =NULL ;return NULL ;
@@ -370,7 +382,7 @@ void perf_aux_output_end(struct perf_outlocal_set (&rb->aux_nest,0 );rb_free_aux (rb); -ring_buffer_put (rb); +ring_buffer_put_async (rb); }/*
@@ -559,7 +571,18 @@ static void __rb_free_aux(struct ring_buvoid rb_free_aux (struct ring_buffer *rb) {if (atomic_dec_and_test (&rb->aux_refcount)) +irq_work_queue (&rb->irq_work); +} + +static void rb_irq_work (struct irq_work *work) +{ + struct ring_buffer *rb = container_of(work, struct ring_buffer, irq_work); + +if (!atomic_read (&rb->aux_refcount))__rb_free_aux (rb); + +if (rb->rcu_head.next == (void *)rb) +call_rcu (&rb->rcu_head, rb_free_rcu); }#ifndef CONFIG_PERF_USE_VMALLOC
Patches currently in stable-queue which might be from [email protected] are
queue-4.1/time-fix-timekeeping_freqadjust-s-incorrect-use-of-abs-instead-of-abs64.patch queue-4.1/perf-x86-intel-fix-constraint-access.patch queue-4.1/sched-access-local-runqueue-directly-in-single_task_running.patch queue-4.1/perf-fix-aux-buffer-refcounting.patch