aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2016-01-19 10:14:29 -0500
committerIngo Molnar <mingo@kernel.org>2016-01-21 12:54:27 -0500
commit45c815f06b80031659c63d7b93e580015d6024dd (patch)
treec50e9636802f65c2e84b6ee9f7cfd4c806594874 /kernel
parent0e1eb0a1f5530bd751fe5bd2c62caa470aaa9643 (diff)
perf: Synchronously free aux pages in case of allocation failure
We are currently using asynchronous deallocation in the error path in AUX mmap code, which is unnecessary and also presents a problem for users that wish to probe for the biggest possible buffer size they can get: they'll get -EINVAL on all subsequent attemts to allocate a smaller buffer before the asynchronous deallocation callback frees up the pages from the previous unsuccessful attempt. Currently, gdb does that for allocating AUX buffers for Intel PT traces. More specifically, overwrite mode of AUX pmus that don't support hardware sg (some implementations of Intel PT, for instance) is limited to only one contiguous high order allocation for its buffer and there is no way of knowing its size without trying. This patch changes error path freeing to be synchronous as there won't be any contenders for the AUX pages at that point. Reported-by: Markus Metzger <markus.t.metzger@intel.com> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@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> Cc: vince@deater.net Link: http://lkml.kernel.org/r/1453216469-9509-1-git-send-email-alexander.shishkin@linux.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/events/ring_buffer.c40
1 files changed, 20 insertions, 20 deletions
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index adfdc0536117..1faad2cfdb9e 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -459,6 +459,25 @@ static void rb_free_aux_page(struct ring_buffer *rb, int idx)
459 __free_page(page); 459 __free_page(page);
460} 460}
461 461
462static void __rb_free_aux(struct ring_buffer *rb)
463{
464 int pg;
465
466 if (rb->aux_priv) {
467 rb->free_aux(rb->aux_priv);
468 rb->free_aux = NULL;
469 rb->aux_priv = NULL;
470 }
471
472 if (rb->aux_nr_pages) {
473 for (pg = 0; pg < rb->aux_nr_pages; pg++)
474 rb_free_aux_page(rb, pg);
475
476 kfree(rb->aux_pages);
477 rb->aux_nr_pages = 0;
478 }
479}
480
462int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event, 481int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event,
463 pgoff_t pgoff, int nr_pages, long watermark, int flags) 482 pgoff_t pgoff, int nr_pages, long watermark, int flags)
464{ 483{
@@ -547,30 +566,11 @@ out:
547 if (!ret) 566 if (!ret)
548 rb->aux_pgoff = pgoff; 567 rb->aux_pgoff = pgoff;
549 else 568 else
550 rb_free_aux(rb); 569 __rb_free_aux(rb);
551 570
552 return ret; 571 return ret;
553} 572}
554 573
555static void __rb_free_aux(struct ring_buffer *rb)
556{
557 int pg;
558
559 if (rb->aux_priv) {
560 rb->free_aux(rb->aux_priv);
561 rb->free_aux = NULL;
562 rb->aux_priv = NULL;
563 }
564
565 if (rb->aux_nr_pages) {
566 for (pg = 0; pg < rb->aux_nr_pages; pg++)
567 rb_free_aux_page(rb, pg);
568
569 kfree(rb->aux_pages);
570 rb->aux_nr_pages = 0;
571 }
572}
573
574void rb_free_aux(struct ring_buffer *rb) 574void rb_free_aux(struct ring_buffer *rb)
575{ 575{
576 if (atomic_dec_and_test(&rb->aux_refcount)) 576 if (atomic_dec_and_test(&rb->aux_refcount))