From: Peter Zijlstra <peterz@infradead.org>
To: mingo@kernel.org
Cc: acme@kernel.org, namhyung@kernel.org, mark.rutland@arm.com,
alexander.shishkin@linux.intel.com, jolsa@kernel.org,
irogers@google.com, adrian.hunter@intel.com,
james.clark@linaro.org, linux-perf-users@vger.kernel.org,
linux-kernel@vger.kernel.org, suzuki.poulose@arm.com,
mike.leach@arm.com, leo.yan@arm.com
Subject: [RFC][PATCH] perf: Fix perf_addr_filters_afjust()
Date: Mon, 22 Jun 2026 14:32:45 +0200 [thread overview]
Message-ID: <20260622123245.GS48970@noisy.programming.kicks-ass.net> (raw)
- adjust lock order; since perf_event_addr_filters_apply() takes mmap_lock
inside child_mutex.
- note that perf_event_mmap() is called by the thread doing the
mmap()/mprotect()/.. operation, but not the other threads in the address
space that might have inherited the same event.
- have perf_addr_filters_adjust() iterate the child_list to find all other
events for tasks that have the same mm.
- since this can now adjust addr_filter_ranges[] for remote events, make sure
to adjust things while holding ctx->lock; local_irq_disable() as implied by
the ifh->lock is no longer suffient to serialize against event scheduling.
- per the previous locking order; perf_event_mmap(), which is called holding
mmap_lock, cannot take child_mutex, as such, make child_list RCU protected
and iterate under RCU.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
kernel/events/core.c | 69 ++++++++++++++++++++++++++++++++++++---------------
1 file changed, 49 insertions(+), 20 deletions(-)
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1454,10 +1454,11 @@ static void put_ctx(struct perf_event_co
* perf_event_context::mutex
* perf_event::child_mutex;
* perf_event_context::lock
- * mmap_lock
- * perf_event::mmap_mutex
- * perf_buffer::aux_mutex
- * perf_addr_filters_head::lock
+ * perf_addr_filters_head::lock
+ * mmap_lock
+ * perf_event::mmap_mutex
+ * perf_buffer::aux_mutex
+ * perf_addr_filters_head::lock
*
* cpu_hotplug_lock
* pmus_lock
@@ -2429,7 +2430,7 @@ static void perf_child_detach(struct per
lockdep_assert_held(&parent_event->child_mutex);
*/
- list_del_init(&event->child_list);
+ list_del_rcu(&event->child_list);
}
static bool is_orphaned_event(struct perf_event *event)
@@ -9902,35 +9903,64 @@ static bool perf_addr_filter_vma_adjust(
return true;
}
-static void __perf_addr_filters_adjust(struct perf_event *event, void *data)
+static int perf_child_addr_filters_adjust(struct perf_event *event,
+ struct vm_area_struct *vma)
{
struct perf_addr_filters_head *ifh = perf_event_addr_filters(event);
- struct vm_area_struct *vma = data;
- struct perf_addr_filter *filter;
unsigned int restart = 0, count = 0;
- unsigned long flags;
-
- if (!has_addr_filter(event))
- return;
+ struct perf_addr_filter *filter;
- if (!vma->vm_file)
- return;
+ guard(raw_spinlock)(&ifh->lock);
- raw_spin_lock_irqsave(&ifh->lock, flags);
list_for_each_entry(filter, &ifh->list, entry) {
if (perf_addr_filter_vma_adjust(filter, vma,
&event->addr_filter_ranges[count]))
restart++;
count++;
+
}
if (restart)
event->addr_filters_gen++;
- raw_spin_unlock_irqrestore(&ifh->lock, flags);
- if (restart)
- perf_event_stop(event, 1);
+ return restart;
+}
+
+static void __perf_addr_filters_adjust(struct perf_event *event, void *data)
+{
+ struct perf_event *child, *parent = event->parent ?: event;
+ struct vm_area_struct *vma = data;
+
+ if (!has_addr_filter(event))
+ return;
+
+ if (!vma->vm_file)
+ return;
+
+ list_for_each_entry_rcu(child, &parent->child_list, child_list) {
+ struct perf_event_context *ctx;
+ struct task_struct *task;
+ int restart = 0;
+
+again:
+ ctx = READ_ONCE(child->ctx);
+ scoped_guard (raw_spinlock_irqsave, &ctx->lock) {
+ if (child->ctx != ctx)
+ goto again;
+
+ task = ctx->task;
+ if (!task || task == TASK_TOMBSTONE)
+ continue;
+
+ if (vma->vm_mm != task->mm)
+ continue;
+
+ restart = perf_child_addr_filters_adjust(child, vma);
+ }
+ if (restart)
+ perf_event_stop(child, 1);
+ }
}
/*
@@ -9947,11 +9977,10 @@ static void perf_addr_filters_adjust(str
if (!(vma->vm_flags & VM_EXEC))
return;
- rcu_read_lock();
+ guard(rcu)();
ctx = rcu_dereference(current->perf_event_ctxp);
if (ctx)
perf_iterate_ctx(ctx, __perf_addr_filters_adjust, vma, true);
- rcu_read_unlock();
}
void perf_event_mmap(struct vm_area_struct *vma)
next reply other threads:[~2026-06-22 12:32 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-22 12:32 Peter Zijlstra [this message]
2026-06-22 12:53 ` [RFC][PATCH] perf: Fix perf_addr_filters_afjust() sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260622123245.GS48970@noisy.programming.kicks-ass.net \
--to=peterz@infradead.org \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=leo.yan@arm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mike.leach@arm.com \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
--cc=suzuki.poulose@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.