[PATCH v3 17/23] perf: Add rb_{alloc,free}_kernel api

Alexander Shishkin
2014-08-11T05:32:13Z

Events that generate AUX data can also be created by the kernel. In this
case, some in-kernel infrastructure is needed to store and copy this data.

This patch adds api for ring buffer (de-)allocation that can be used by the
kernel code.

Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
kernel/events/internal.h | 3 +++
kernel/events/ring_buffer.c | 33 +++++++++++++++++++++++++++++++++
2 files changed, 36 insertions(+)

diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index 4f99987bc3..f4cfa4cabb 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -59,6 +59,9 @@ extern void perf_event_wakeup(struct perf_event *event);
extern int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event,
pgoff_t pgoff, int nr_pages, long watermark, int flags);
extern void rb_free_aux(struct ring_buffer *rb, struct perf_event *event);
+extern struct ring_buffer *
+rb_alloc_kernel(struct perf_event *event, int nr_pages, int aux_nr_pages);
+extern void rb_free_kernel(struct ring_buffer *rb, struct perf_event *event);
extern struct ring_buffer *ring_buffer_get(struct perf_event *event);
extern void ring_buffer_put(struct ring_buffer *rb);

diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 85858d201c..43c4cc1892 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -467,6 +467,39 @@ void rb_free_aux(struct ring_buffer *rb, struct perf_event *event)
rb->aux_nr_pages = 0;
}

+struct ring_buffer *
+rb_alloc_kernel(struct perf_event *event, int nr_pages, int aux_nr_pages)
+{
+ struct ring_buffer *rb;
+ int ret, pgoff = nr_pages + 1;
+
+ rb = rb_alloc(nr_pages, 0, event->cpu, 0);
+ if (!rb)
+ return NULL;
+
+ ret = rb_alloc_aux(rb, event, pgoff, aux_nr_pages, 0, 0);
+ if (ret) {
+ rb_free(rb);
+ return NULL;
+ }
+
+ /*
+ * Kernel counters don't need ring buffer wakeups, therefore we don't
+ * use ring_buffer_attach() here and event->rb_entry stays empty
+ */
+ rcu_assign_pointer(event->rb, rb);
+
+ return rb;
+}
+
+void rb_free_kernel(struct ring_buffer *rb, struct perf_event *event)
+{
+ BUG_ON(atomic_read(&rb->refcount) != 1);
+ rcu_assign_pointer(event->rb, NULL);
+ rb_free_aux(rb, event);
+ rb_free(rb);
+}
+
#ifndef CONFIG_PERF_USE_VMALLOC

/*
--
2.1.0.rc1