From: Thaumy Cheng <thaumy.love@gmail.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Namhyung Kim <namhyung@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
James Clark <james.clark@linaro.org>
Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org,
Thaumy Cheng <thaumy.love@gmail.com>
Subject: [PATCH] perf/core: Strengthen userpage update ordering
Date: Sun, 6 Sep 2026 20:23:50 +0800 [thread overview]
Message-ID: <20260906122350.24305-1-thaumy.love@gmail.com> (raw)
The perf event mmap userpage uses a sequence counter to let userspace
obtain a consistent snapshot of its data. The existing compiler
barriers reflect the original self-monitoring use case, where the
counter was updated and consumed on the same CPU.
Some consumers also use the userpage only for time conversion and may
read it from a CPU other than the one updating the event. For example,
perf_read_tsc_conversion() reads the time conversion fields
without constraining the caller to the event's CPU.
Make the publication ordering explicit for such readers by replacing the
compiler barriers around the userpage payload update with smp_wmb().
Document that cross-CPU readers of the time conversion fields must use
read memory barriers and reject odd or changed sequence values.
This does not change the UAPI layout or the values exposed to
userspace. It strengthens the ordering guarantee for cross-CPU readers
on weakly ordered architectures.
Signed-off-by: Thaumy Cheng <thaumy.love@gmail.com>
---
include/uapi/linux/perf_event.h | 6 ++++--
kernel/events/core.c | 6 ++++--
tools/include/uapi/linux/perf_event.h | 6 ++++--
tools/perf/design.txt | 6 ++++--
4 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index fd10aa8d697f..a7db00b9b455 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -629,8 +629,10 @@ struct perf_event_mmap_page {
* barrier();
* } while (pc->lock != seq);
*
- * NOTE: for obvious reason this only works on self-monitoring
- * processes.
+ * NOTE: Reading the hardware counter as shown above only works for
+ * self-monitoring processes. A reader on another CPU may snapshot
+ * the time conversion fields, but must use rmb() around the field
+ * reads and retry if lock is odd or changes.
*/
__u32 lock; /* seqlock for synchronization */
__u32 index; /* hardware event identifier */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 89b40e439717..72605776273f 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6852,7 +6852,8 @@ void perf_event_update_userpage(struct perf_event *event)
userpg = rb->user_page;
++userpg->lock;
- barrier();
+ /* Publish the odd lock value before updating the payload. */
+ smp_wmb();
userpg->index = perf_event_index(event);
userpg->offset = perf_event_count(event, false);
if (userpg->index)
@@ -6866,7 +6867,8 @@ void perf_event_update_userpage(struct perf_event *event)
arch_perf_update_userpage(event, userpg, now);
- barrier();
+ /* Publish the payload before the final lock update. */
+ smp_wmb();
++userpg->lock;
preempt_enable();
unlock:
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index fd10aa8d697f..a7db00b9b455 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -629,8 +629,10 @@ struct perf_event_mmap_page {
* barrier();
* } while (pc->lock != seq);
*
- * NOTE: for obvious reason this only works on self-monitoring
- * processes.
+ * NOTE: Reading the hardware counter as shown above only works for
+ * self-monitoring processes. A reader on another CPU may snapshot
+ * the time conversion fields, but must use rmb() around the field
+ * reads and retry if lock is odd or changes.
*/
__u32 lock; /* seqlock for synchronization */
__u32 index; /* hardware event identifier */
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index aa8cfeabb743..111afc90c442 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -316,8 +316,10 @@ struct perf_event_mmap_page {
* barrier();
* } while (pc->lock != seq);
*
- * NOTE: for obvious reason this only works on self-monitoring
- * processes.
+ * NOTE: Reading the hardware counter as shown above only works for
+ * self-monitoring processes. A reader on another CPU may snapshot
+ * the time conversion fields, but must use rmb() around the field
+ * reads and retry if lock is odd or changes.
*/
__u32 lock; /* seqlock for synchronization */
__u32 index; /* hardware counter identifier */
--
2.55.0
next reply other threads:[~2026-09-06 12:23 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-06 12:23 Thaumy Cheng [this message]
2026-09-06 12:33 ` [PATCH] perf/core: Strengthen userpage update ordering 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=20260906122350.24305-1-thaumy.love@gmail.com \
--to=thaumy.love@gmail.com \
--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=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox