linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv2] perf: Fix vmalloc ring buffer free function
@ 2013-03-01 16:34 Jiri Olsa
  2013-03-06 14:30 ` [tip:perf/urgent] " tip-bot for Jiri Olsa
                   ` (2 more replies)
  0 siblings, 3 replies; 28+ messages in thread
From: Jiri Olsa @ 2013-03-01 16:34 UTC (permalink / raw)
  To: linux-kernel
  Cc: Jiri Olsa, Corey Ashford, Frederic Weisbecker, Ingo Molnar,
	Namhyung Kim, Paul Mackerras, Peter Zijlstra,
	Arnaldo Carvalho de Melo

If we allocate perf ring buffer with the size of single page,
we will get memory corruption when releasing it. It's caused
by rb_free_work function (CONFIG_PERF_USE_VMALLOC option).

For single page sized ring buffer the page_order is -1 (because
nr_pages is 0). This needs to be recognized in the rb_free_work
function to release proper amount of pages.

Introducing page_nr function (CONFIG_PERF_USE_VMALLOC only)
that returns number of allocated pages. Using it in rb_free_work
and perf_mmap_to_page functions.

Also setting rb->nr_pages to 0 in case we have only user page
allocated, which will fail perf_output_begin function and
prevents sample storage.

v2 changes:
 - fixed the perf_output_begin handling of single page buffer

Reported-by: Jan Stancek <jstancek@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 kernel/events/ring_buffer.c | 40 +++++++++++++++++++++++++++++++++-------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 23cb34f..a802151 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -154,7 +154,8 @@ int perf_output_begin(struct perf_output_handle *handle,
 	if (head - local_read(&rb->wakeup) > rb->watermark)
 		local_add(rb->watermark, &rb->wakeup);
 
-	handle->page = offset >> (PAGE_SHIFT + page_order(rb));
+	/* page is allways 0 for CONFIG_PERF_USE_VMALLOC option */
+	handle->page = offset >> PAGE_SHIFT;
 	handle->page &= rb->nr_pages - 1;
 	handle->size = offset & ((PAGE_SIZE << page_order(rb)) - 1);
 	handle->addr = rb->data_pages[handle->page];
@@ -312,11 +313,21 @@ void rb_free(struct ring_buffer *rb)
 }
 
 #else
+/*
+ * Returns the total number of pages allocated
+ * by ring buffer including the user page.
+ */
+static int page_nr(struct ring_buffer *rb)
+{
+	return page_order(rb) == -1 ?
+		1 :                        /* no data, just user page */
+		1 + (1 << page_order(rb)); /* user page + data pages */
+}
 
 struct page *
 perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff)
 {
-	if (pgoff > (1UL << page_order(rb)))
+	if (pgoff > page_nr(rb))
 		return NULL;
 
 	return vmalloc_to_page((void *)rb->user_page + pgoff * PAGE_SIZE);
@@ -336,10 +347,10 @@ static void rb_free_work(struct work_struct *work)
 	int i, nr;
 
 	rb = container_of(work, struct ring_buffer, work);
-	nr = 1 << page_order(rb);
+	nr = page_nr(rb);
 
 	base = rb->user_page;
-	for (i = 0; i < nr + 1; i++)
+	for (i = 0; i < nr; i++)
 		perf_mmap_unmark_page(base + (i * PAGE_SIZE));
 
 	vfree(base);
@@ -371,9 +382,24 @@ struct ring_buffer *rb_alloc(int nr_pages, long watermark, int cpu, int flags)
 		goto fail_all_buf;
 
 	rb->user_page = all_buf;
-	rb->data_pages[0] = all_buf + PAGE_SIZE;
-	rb->page_order = ilog2(nr_pages);
-	rb->nr_pages = 1;
+
+	/*
+	 * For special case nr_pages == 0 we have
+	 * only the user page mmaped plus:
+	 *
+	 *   rb->data_pages[0] = NULL
+	 *   rb->nr_pages      = 0
+	 *   rb->page_order    = -1
+	 *
+	 * The perf_output_begin function is guarded
+	 * by (rb->nr_pages > 0) condition, so no
+	 * output code touches above setup if we
+	 * have only user page allocated.
+	 */
+
+	rb->data_pages[0] = nr_pages ? all_buf + PAGE_SIZE : NULL;
+	rb->nr_pages      = nr_pages ? 1 : 0;
+	rb->page_order    = ilog2(nr_pages);
 
 	ring_buffer_init(rb, watermark, flags);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2013-05-02  7:55 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-01 16:34 [PATCHv2] perf: Fix vmalloc ring buffer free function Jiri Olsa
2013-03-06 14:30 ` [tip:perf/urgent] " tip-bot for Jiri Olsa
2013-03-06 15:20 ` [PATCHv2] " Frederic Weisbecker
2013-03-06 15:37   ` Jiri Olsa
2013-03-06 15:40     ` Frederic Weisbecker
2013-03-11  9:40 ` Peter Zijlstra
2013-03-11 11:21   ` Jiri Olsa
2013-03-11 12:15     ` Ingo Molnar
2013-03-11 16:26     ` Peter Zijlstra
2013-03-11 16:43       ` Jiri Olsa
2013-03-11 17:44         ` Peter Zijlstra
2013-03-11 18:02           ` Jiri Olsa
2013-03-12 10:05             ` [PATCHv3] " Jiri Olsa
2013-03-12 10:27               ` Peter Zijlstra
2013-03-12 10:53                 ` Jiri Olsa
2013-03-12 12:38                   ` Peter Zijlstra
2013-03-12 13:52                 ` Jiri Olsa
2013-03-12 15:26                   ` Peter Zijlstra
2013-03-12 15:36                     ` Jiri Olsa
2013-03-12 16:24                       ` Peter Zijlstra
2013-03-12 17:04                         ` Jiri Olsa
2013-03-13 11:15                           ` Jiri Olsa
2013-03-18 19:05                             ` Jiri Olsa
2013-03-19 11:46                               ` Peter Zijlstra
2013-03-19 14:35                                 ` [PATCHv4] perf: Fix vmalloc ring buffer pages handling Jiri Olsa
2013-04-30 15:36                                   ` Jiri Olsa
2013-05-01 10:34                                     ` Ingo Molnar
2013-05-02  7:54                                   ` [tip:perf/urgent] " tip-bot for Jiri Olsa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).