Move the RB buffer allocation branch into its own function.
Originally-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
kernel/events/core.c | 145 +++++++++++++++++++++++++--------------------------
1 file changed, 73 insertions(+), 72 deletions(-)
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6970,6 +6970,75 @@ static void perf_mmap_account(struct vm_
atomic64_add(extra, &vma->vm_mm->pinned_vm);
}
+static int perf_mmap_rb(struct vm_area_struct *vma, struct perf_event *event,
+ unsigned long nr_pages)
+{
+ long extra = 0, user_extra = nr_pages;
+ struct perf_buffer *rb;
+ int rb_flags = 0;
+
+ nr_pages -= 1;
+
+ /*
+ * If we have rb pages ensure they're a power-of-two number, so we
+ * can do bitmasks instead of modulo.
+ */
+ if (nr_pages != 0 && !is_power_of_2(nr_pages))
+ return -EINVAL;
+
+ WARN_ON_ONCE(event->ctx->parent_ctx);
+
+ if (event->rb) {
+ if (data_page_nr(event->rb) != nr_pages)
+ return -EINVAL;
+
+ if (atomic_inc_not_zero(&event->rb->mmap_count)) {
+ /*
+ * Success -- managed to mmap() the same buffer
+ * multiple times.
+ */
+ perf_mmap_account(vma, user_extra, extra);
+ atomic_inc(&event->mmap_count);
+ return 0;
+ }
+
+ /*
+ * Raced against perf_mmap_close()'s
+ * atomic_dec_and_mutex_lock() remove the
+ * event and continue as if !event->rb
+ */
+ ring_buffer_attach(event, NULL);
+ }
+
+ if (!perf_mmap_calc_limits(vma, &user_extra, &extra))
+ return -EPERM;
+
+ if (vma->vm_flags & VM_WRITE)
+ rb_flags |= RING_BUFFER_WRITABLE;
+
+ rb = rb_alloc(nr_pages,
+ event->attr.watermark ? event->attr.wakeup_watermark : 0,
+ event->cpu, rb_flags);
+
+ if (!rb)
+ return -ENOMEM;
+
+ atomic_set(&rb->mmap_count, 1);
+ rb->mmap_user = get_current_user();
+ rb->mmap_locked = extra;
+
+ ring_buffer_attach(event, rb);
+
+ perf_event_update_time(event);
+ perf_event_init_userpage(event);
+ perf_event_update_userpage(event);
+
+ perf_mmap_account(vma, user_extra, extra);
+ atomic_inc(&event->mmap_count);
+
+ return 0;
+}
+
static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event,
unsigned long nr_pages)
{
@@ -7050,10 +7119,8 @@ static int perf_mmap(struct file *file,
{
struct perf_event *event = file->private_data;
unsigned long vma_size, nr_pages;
- long user_extra = 0, extra = 0;
- struct perf_buffer *rb = NULL;
- int ret, flags = 0;
mapped_f mapped;
+ int ret;
/*
* Don't allow mmap() of inherited per-task counters. This would
@@ -7079,8 +7146,6 @@ static int perf_mmap(struct file *file,
if (vma_size != PAGE_SIZE * nr_pages)
return -EINVAL;
- user_extra = nr_pages;
-
mutex_lock(&event->mmap_mutex);
ret = -EINVAL;
@@ -7094,74 +7159,10 @@ static int perf_mmap(struct file *file,
goto unlock;
}
- if (vma->vm_pgoff == 0) {
- nr_pages -= 1;
-
- /*
- * If we have rb pages ensure they're a power-of-two number, so we
- * can do bitmasks instead of modulo.
- */
- if (nr_pages != 0 && !is_power_of_2(nr_pages))
- goto unlock;
-
- WARN_ON_ONCE(event->ctx->parent_ctx);
-
- if (event->rb) {
- if (data_page_nr(event->rb) != nr_pages)
- goto unlock;
-
- if (atomic_inc_not_zero(&event->rb->mmap_count)) {
- /*
- * Success -- managed to mmap() the same buffer
- * multiple times.
- */
- ret = 0;
- perf_mmap_account(vma, user_extra, extra);
- atomic_inc(&event->mmap_count);
- goto unlock;
- }
-
- /*
- * Raced against perf_mmap_close()'s
- * atomic_dec_and_mutex_lock() remove the
- * event and continue as if !event->rb
- */
- ring_buffer_attach(event, NULL);
- }
-
- if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) {
- ret = -EPERM;
- goto unlock;
- }
-
- if (vma->vm_flags & VM_WRITE)
- flags |= RING_BUFFER_WRITABLE;
-
- rb = rb_alloc(nr_pages,
- event->attr.watermark ? event->attr.wakeup_watermark : 0,
- event->cpu, flags);
-
- if (!rb) {
- ret = -ENOMEM;
- goto unlock;
- }
-
- atomic_set(&rb->mmap_count, 1);
- rb->mmap_user = get_current_user();
- rb->mmap_locked = extra;
-
- ring_buffer_attach(event, rb);
-
- perf_event_update_time(event);
- perf_event_init_userpage(event);
- perf_event_update_userpage(event);
- ret = 0;
-
- perf_mmap_account(vma, user_extra, extra);
- atomic_inc(&event->mmap_count);
- } else {
+ if (vma->vm_pgoff == 0)
+ ret = perf_mmap_rb(vma, event, nr_pages);
+ else
ret = perf_mmap_aux(vma, event, nr_pages);
- }
unlock:
mutex_unlock(&event->mmap_mutex);
On Tue, Aug 12, 2025 at 12:39:10PM +0200, Peter Zijlstra wrote:
> Move the RB buffer allocation branch into its own function.
>
> Originally-by: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Ah yes of course, the very next patch :)
One nit below about ret assignment, though I wonder if you address later?
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
> kernel/events/core.c | 145 +++++++++++++++++++++++++--------------------------
> 1 file changed, 73 insertions(+), 72 deletions(-)
>
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -6970,6 +6970,75 @@ static void perf_mmap_account(struct vm_
> atomic64_add(extra, &vma->vm_mm->pinned_vm);
> }
>
> +static int perf_mmap_rb(struct vm_area_struct *vma, struct perf_event *event,
> + unsigned long nr_pages)
> +{
> + long extra = 0, user_extra = nr_pages;
> + struct perf_buffer *rb;
> + int rb_flags = 0;
> +
> + nr_pages -= 1;
> +
> + /*
> + * If we have rb pages ensure they're a power-of-two number, so we
> + * can do bitmasks instead of modulo.
> + */
> + if (nr_pages != 0 && !is_power_of_2(nr_pages))
> + return -EINVAL;
> +
> + WARN_ON_ONCE(event->ctx->parent_ctx);
> +
> + if (event->rb) {
> + if (data_page_nr(event->rb) != nr_pages)
> + return -EINVAL;
> +
> + if (atomic_inc_not_zero(&event->rb->mmap_count)) {
> + /*
> + * Success -- managed to mmap() the same buffer
> + * multiple times.
> + */
> + perf_mmap_account(vma, user_extra, extra);
> + atomic_inc(&event->mmap_count);
> + return 0;
> + }
> +
> + /*
> + * Raced against perf_mmap_close()'s
> + * atomic_dec_and_mutex_lock() remove the
> + * event and continue as if !event->rb
> + */
> + ring_buffer_attach(event, NULL);
> + }
> +
> + if (!perf_mmap_calc_limits(vma, &user_extra, &extra))
> + return -EPERM;
> +
> + if (vma->vm_flags & VM_WRITE)
> + rb_flags |= RING_BUFFER_WRITABLE;
> +
I hadn't noticed before actually, but it's really nice that we only assign
rb from below for the newly allocated rb, and refer to the prior one via
event->rb above.
Which neatly addressed my prior review feedback on this, very nice, cheers!
> + rb = rb_alloc(nr_pages,
> + event->attr.watermark ? event->attr.wakeup_watermark : 0,
> + event->cpu, rb_flags);
> +
> + if (!rb)
> + return -ENOMEM;
> +
> + atomic_set(&rb->mmap_count, 1);
> + rb->mmap_user = get_current_user();
> + rb->mmap_locked = extra;
> +
> + ring_buffer_attach(event, rb);
> +
> + perf_event_update_time(event);
> + perf_event_init_userpage(event);
> + perf_event_update_userpage(event);
> +
> + perf_mmap_account(vma, user_extra, extra);
> + atomic_inc(&event->mmap_count);
> +
> + return 0;
> +}
> +
> static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event,
> unsigned long nr_pages)
> {
> @@ -7050,10 +7119,8 @@ static int perf_mmap(struct file *file,
> {
> struct perf_event *event = file->private_data;
> unsigned long vma_size, nr_pages;
> - long user_extra = 0, extra = 0;
> - struct perf_buffer *rb = NULL;
> - int ret, flags = 0;
> mapped_f mapped;
> + int ret;
>
> /*
> * Don't allow mmap() of inherited per-task counters. This would
> @@ -7079,8 +7146,6 @@ static int perf_mmap(struct file *file,
> if (vma_size != PAGE_SIZE * nr_pages)
> return -EINVAL;
>
> - user_extra = nr_pages;
> -
> mutex_lock(&event->mmap_mutex);
> ret = -EINVAL;
This ret assignment is redundant now, since in all cases you assign ret
below.
I wonder if you get rid of this in a later patch though?
>
> @@ -7094,74 +7159,10 @@ static int perf_mmap(struct file *file,
> goto unlock;
> }
>
> - if (vma->vm_pgoff == 0) {
> - nr_pages -= 1;
> -
> - /*
> - * If we have rb pages ensure they're a power-of-two number, so we
> - * can do bitmasks instead of modulo.
> - */
> - if (nr_pages != 0 && !is_power_of_2(nr_pages))
> - goto unlock;
> -
> - WARN_ON_ONCE(event->ctx->parent_ctx);
> -
> - if (event->rb) {
> - if (data_page_nr(event->rb) != nr_pages)
> - goto unlock;
> -
> - if (atomic_inc_not_zero(&event->rb->mmap_count)) {
> - /*
> - * Success -- managed to mmap() the same buffer
> - * multiple times.
> - */
> - ret = 0;
> - perf_mmap_account(vma, user_extra, extra);
> - atomic_inc(&event->mmap_count);
> - goto unlock;
> - }
> -
> - /*
> - * Raced against perf_mmap_close()'s
> - * atomic_dec_and_mutex_lock() remove the
> - * event and continue as if !event->rb
> - */
> - ring_buffer_attach(event, NULL);
> - }
> -
> - if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) {
> - ret = -EPERM;
> - goto unlock;
> - }
> -
> - if (vma->vm_flags & VM_WRITE)
> - flags |= RING_BUFFER_WRITABLE;
> -
> - rb = rb_alloc(nr_pages,
> - event->attr.watermark ? event->attr.wakeup_watermark : 0,
> - event->cpu, flags);
> -
> - if (!rb) {
> - ret = -ENOMEM;
> - goto unlock;
> - }
> -
> - atomic_set(&rb->mmap_count, 1);
> - rb->mmap_user = get_current_user();
> - rb->mmap_locked = extra;
> -
> - ring_buffer_attach(event, rb);
> -
> - perf_event_update_time(event);
> - perf_event_init_userpage(event);
> - perf_event_update_userpage(event);
> - ret = 0;
> -
> - perf_mmap_account(vma, user_extra, extra);
> - atomic_inc(&event->mmap_count);
> - } else {
> + if (vma->vm_pgoff == 0)
> + ret = perf_mmap_rb(vma, event, nr_pages);
> + else
> ret = perf_mmap_aux(vma, event, nr_pages);
> - }
>
> unlock:
> mutex_unlock(&event->mmap_mutex);
>
>
The following commit has been merged into the perf/core branch of tip:
Commit-ID: 5d299897f1e36025400ca84fd36c15925a383b03
Gitweb: https://git.kernel.org/tip/5d299897f1e36025400ca84fd36c15925a383b03
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Tue, 12 Aug 2025 12:39:10 +02:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 15 Aug 2025 13:13:01 +02:00
perf: Split out the RB allocation
Move the RB buffer allocation branch into its own function.
Originally-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Link: https://lore.kernel.org/r/20250812104019.722214699@infradead.org
---
kernel/events/core.c | 145 +++++++++++++++++++++---------------------
1 file changed, 73 insertions(+), 72 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 875c27b..3a5fd2b 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6970,6 +6970,75 @@ static void perf_mmap_account(struct vm_area_struct *vma, long user_extra, long
atomic64_add(extra, &vma->vm_mm->pinned_vm);
}
+static int perf_mmap_rb(struct vm_area_struct *vma, struct perf_event *event,
+ unsigned long nr_pages)
+{
+ long extra = 0, user_extra = nr_pages;
+ struct perf_buffer *rb;
+ int rb_flags = 0;
+
+ nr_pages -= 1;
+
+ /*
+ * If we have rb pages ensure they're a power-of-two number, so we
+ * can do bitmasks instead of modulo.
+ */
+ if (nr_pages != 0 && !is_power_of_2(nr_pages))
+ return -EINVAL;
+
+ WARN_ON_ONCE(event->ctx->parent_ctx);
+
+ if (event->rb) {
+ if (data_page_nr(event->rb) != nr_pages)
+ return -EINVAL;
+
+ if (atomic_inc_not_zero(&event->rb->mmap_count)) {
+ /*
+ * Success -- managed to mmap() the same buffer
+ * multiple times.
+ */
+ perf_mmap_account(vma, user_extra, extra);
+ atomic_inc(&event->mmap_count);
+ return 0;
+ }
+
+ /*
+ * Raced against perf_mmap_close()'s
+ * atomic_dec_and_mutex_lock() remove the
+ * event and continue as if !event->rb
+ */
+ ring_buffer_attach(event, NULL);
+ }
+
+ if (!perf_mmap_calc_limits(vma, &user_extra, &extra))
+ return -EPERM;
+
+ if (vma->vm_flags & VM_WRITE)
+ rb_flags |= RING_BUFFER_WRITABLE;
+
+ rb = rb_alloc(nr_pages,
+ event->attr.watermark ? event->attr.wakeup_watermark : 0,
+ event->cpu, rb_flags);
+
+ if (!rb)
+ return -ENOMEM;
+
+ atomic_set(&rb->mmap_count, 1);
+ rb->mmap_user = get_current_user();
+ rb->mmap_locked = extra;
+
+ ring_buffer_attach(event, rb);
+
+ perf_event_update_time(event);
+ perf_event_init_userpage(event);
+ perf_event_update_userpage(event);
+
+ perf_mmap_account(vma, user_extra, extra);
+ atomic_inc(&event->mmap_count);
+
+ return 0;
+}
+
static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event,
unsigned long nr_pages)
{
@@ -7050,10 +7119,8 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
{
struct perf_event *event = file->private_data;
unsigned long vma_size, nr_pages;
- long user_extra = 0, extra = 0;
- struct perf_buffer *rb = NULL;
- int ret, flags = 0;
mapped_f mapped;
+ int ret;
/*
* Don't allow mmap() of inherited per-task counters. This would
@@ -7079,8 +7146,6 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
if (vma_size != PAGE_SIZE * nr_pages)
return -EINVAL;
- user_extra = nr_pages;
-
mutex_lock(&event->mmap_mutex);
ret = -EINVAL;
@@ -7094,74 +7159,10 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
goto unlock;
}
- if (vma->vm_pgoff == 0) {
- nr_pages -= 1;
-
- /*
- * If we have rb pages ensure they're a power-of-two number, so we
- * can do bitmasks instead of modulo.
- */
- if (nr_pages != 0 && !is_power_of_2(nr_pages))
- goto unlock;
-
- WARN_ON_ONCE(event->ctx->parent_ctx);
-
- if (event->rb) {
- if (data_page_nr(event->rb) != nr_pages)
- goto unlock;
-
- if (atomic_inc_not_zero(&event->rb->mmap_count)) {
- /*
- * Success -- managed to mmap() the same buffer
- * multiple times.
- */
- ret = 0;
- perf_mmap_account(vma, user_extra, extra);
- atomic_inc(&event->mmap_count);
- goto unlock;
- }
-
- /*
- * Raced against perf_mmap_close()'s
- * atomic_dec_and_mutex_lock() remove the
- * event and continue as if !event->rb
- */
- ring_buffer_attach(event, NULL);
- }
-
- if (!perf_mmap_calc_limits(vma, &user_extra, &extra)) {
- ret = -EPERM;
- goto unlock;
- }
-
- if (vma->vm_flags & VM_WRITE)
- flags |= RING_BUFFER_WRITABLE;
-
- rb = rb_alloc(nr_pages,
- event->attr.watermark ? event->attr.wakeup_watermark : 0,
- event->cpu, flags);
-
- if (!rb) {
- ret = -ENOMEM;
- goto unlock;
- }
-
- atomic_set(&rb->mmap_count, 1);
- rb->mmap_user = get_current_user();
- rb->mmap_locked = extra;
-
- ring_buffer_attach(event, rb);
-
- perf_event_update_time(event);
- perf_event_init_userpage(event);
- perf_event_update_userpage(event);
- ret = 0;
-
- perf_mmap_account(vma, user_extra, extra);
- atomic_inc(&event->mmap_count);
- } else {
+ if (vma->vm_pgoff == 0)
+ ret = perf_mmap_rb(vma, event, nr_pages);
+ else
ret = perf_mmap_aux(vma, event, nr_pages);
- }
unlock:
mutex_unlock(&event->mmap_mutex);
© 2016 - 2026 Red Hat, Inc.