mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] sparc64: vdso: Flush the D-cache after updating the time data
@ 2026-09-17  8:25 Stian Halseth
  2026-09-25  7:55 ` Thomas Weißschuh
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Stian Halseth @ 2026-09-17  8:25 UTC (permalink / raw)
  To: davem, Andreas Larsson
  Cc: Thomas Weißschuh, Thomas Gleixner, sparclinux, linux-kernel,
	Stian Halseth

The vDSO time data page is written through the kernel linear mapping
and read through a user mapping placed without colour alignment.  On
sun4u the L1 D-cache is virtually indexed, so when the two differ in
colour the timekeeping CPU's stores leave stale lines behind the user
alias in its own D-cache.  The seqcount does not catch this: the line
holding seq and the lines holding the clock data are refreshed
independently, so a reader sees an even, unchanged seq together with a
mix of old and new fields.

On a Sun Fire V240 (UltraSPARC IIIi, clocksource stick) this makes
clock_gettime(CLOCK_MONOTONIC) via the vDSO wrong for most calls on
the tick CPU, by multiples of the 10 ms tick and up to a second, in
about half of all processes: those that drew the other colour at exec.
The syscall is correct, so a deadline derived from the vDSO can already
be in the past when handed to the kernel; MySQL's InnoDB
log_files_governor thread spun at ~24000 futex calls/s on ETIMEDOUT
this way.

Flush the page after every update, as arm does.  The helper lives in
vma.c because asm/vdso/vsyscall.h is also compiled into the vDSO, where
asm/cacheflush.h is unavailable.  On sun4v flush_dcache_folio() is a
no-op, the caches there being physically indexed.

The sparc-specific vDSO that v7.1-rc1 replaced had the same defect
(reproduced on 6.18), so the bug is as old as the sparc vDSO, but this
fix relies on __arch_sync_vdso_time_data() and applies from v7.1-rc1.

Verified on 7.2.6: 32 probe runs across mapping colours show no vDSO
deviation, and MySQL's governor idles at 0.2% CPU across five restarts
of an unpatched build.

Fixes: 9a08862a5d2e ("vDSO for sparc")
Closes: https://github.com/sparclinux/issues/issues/94
Signed-off-by: Stian Halseth <stian@itx.no>
---
 arch/sparc/include/asm/vdso/vsyscall.h | 10 ++++++++++
 arch/sparc/vdso/vma.c                  |  6 ++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/sparc/include/asm/vdso/vsyscall.h b/arch/sparc/include/asm/vdso/vsyscall.h
index 8bfe703fedc5..4852f122ce47 100644
--- a/arch/sparc/include/asm/vdso/vsyscall.h
+++ b/arch/sparc/include/asm/vdso/vsyscall.h
@@ -5,6 +5,16 @@
 
 #define __VDSO_PAGES 4
 
+#ifndef __ASSEMBLER__
+
+/* The user mapping may alias the kernel one in the VIPT D-cache. */
+struct vdso_time_data;
+void __arch_sync_vdso_time_data(struct vdso_time_data *vdata);
+#define __arch_sync_vdso_time_data __arch_sync_vdso_time_data
+
+#endif /* !__ASSEMBLER__ */
+
+/* The asm-generic header needs to be included after the definitions above */
 #include <asm-generic/vdso/vsyscall.h>
 
 #endif /* _ASM_SPARC_VDSO_VSYSCALL_H */
diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c
index 60029d60f4d3..fe6a47af6b05 100644
--- a/arch/sparc/vdso/vma.c
+++ b/arch/sparc/vdso/vma.c
@@ -27,6 +27,12 @@
 
 unsigned int __read_mostly vdso_enabled = 1;
 
+/* Called by the timekeeping code after every update of the vDSO data. */
+void __arch_sync_vdso_time_data(struct vdso_time_data *vdata)
+{
+	flush_dcache_page(virt_to_page(vdata));
+}
+
 #ifdef	CONFIG_SPARC64
 static struct vm_special_mapping vdso_mapping64 = {
 	.name = "[vdso]"
-- 
2.43.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] sparc64: vdso: Flush the D-cache after updating the time data
  2026-09-17  8:25 [PATCH] sparc64: vdso: Flush the D-cache after updating the time data Stian Halseth
@ 2026-09-25  7:55 ` Thomas Weißschuh
  2026-09-25  8:02 ` [PATCH v2] " Stian Halseth
  2026-09-27 20:49 ` [PATCH] " Imre Kaloz
  2 siblings, 0 replies; 4+ messages in thread
From: Thomas Weißschuh @ 2026-09-25  7:55 UTC (permalink / raw)
  To: Stian Halseth
  Cc: davem, Andreas Larsson, Thomas Gleixner, sparclinux, linux-kernel

On Thu, Sep 17, 2026 at 10:25:47AM +0200, Stian Halseth wrote:
> The vDSO time data page is written through the kernel linear mapping
> and read through a user mapping placed without colour alignment.  On
> sun4u the L1 D-cache is virtually indexed, so when the two differ in
> colour the timekeeping CPU's stores leave stale lines behind the user
> alias in its own D-cache.  The seqcount does not catch this: the line
> holding seq and the lines holding the clock data are refreshed
> independently, so a reader sees an even, unchanged seq together with a
> mix of old and new fields.

(...)

> Fixes: 9a08862a5d2e ("vDSO for sparc")

I'd like to *also* have a fixes tag for the migration to the generic
infrastructure here:

Fixes: 7c5fc16c7a56 ("sparc64: vdso: Switch to the generic vDSO library")

While it was broken before, the diff is against that commit.

> Closes: https://github.com/sparclinux/issues/issues/94
> Signed-off-by: Stian Halseth <stian@itx.no>

Reviewed-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>

> ---
>  arch/sparc/include/asm/vdso/vsyscall.h | 10 ++++++++++
>  arch/sparc/vdso/vma.c                  |  6 ++++++
>  2 files changed, 16 insertions(+)

(...)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2] sparc64: vdso: Flush the D-cache after updating the time data
  2026-09-17  8:25 [PATCH] sparc64: vdso: Flush the D-cache after updating the time data Stian Halseth
  2026-09-25  7:55 ` Thomas Weißschuh
@ 2026-09-25  8:02 ` Stian Halseth
  2026-09-27 20:49 ` [PATCH] " Imre Kaloz
  2 siblings, 0 replies; 4+ messages in thread
From: Stian Halseth @ 2026-09-25  8:02 UTC (permalink / raw)
  To: davem, Andreas Larsson
  Cc: Thomas Weißschuh, Thomas Gleixner, sparclinux, linux-kernel,
	Stian Halseth

The vDSO time data page is written through the kernel linear mapping
and read through a user mapping placed without colour alignment.  On
sun4u the L1 D-cache is virtually indexed, so when the two differ in
colour the timekeeping CPU's stores leave stale lines behind the user
alias in its own D-cache.  The seqcount does not catch this: the line
holding seq and the lines holding the clock data are refreshed
independently, so a reader sees an even, unchanged seq together with a
mix of old and new fields.

On a Sun Fire V240 (UltraSPARC IIIi, clocksource stick) this makes
clock_gettime(CLOCK_MONOTONIC) via the vDSO wrong for most calls on
the tick CPU, by multiples of the 10 ms tick and up to a second, in
about half of all processes: those that drew the other colour at exec.
The syscall is correct, so a deadline derived from the vDSO can already
be in the past when handed to the kernel; MySQL's InnoDB
log_files_governor thread spun at ~24000 futex calls/s on ETIMEDOUT
this way.

Flush the page after every update, as arm does.  The helper lives in
vma.c because asm/vdso/vsyscall.h is also compiled into the vDSO, where
asm/cacheflush.h is unavailable.  On sun4v flush_dcache_folio() is a
no-op, the caches there being physically indexed.

The sparc-specific vDSO that v7.1-rc1 replaced had the same defect
(reproduced on 6.18), so the bug is as old as the sparc vDSO, but this
fix relies on __arch_sync_vdso_time_data() and applies from v7.1-rc1.

Verified on 7.2.6: 32 probe runs across mapping colours show no vDSO
deviation, and MySQL's governor idles at 0.2% CPU across five restarts
of an unpatched build.

Fixes: 9a08862a5d2e ("vDSO for sparc")
Fixes: 7c5fc16c7a56 ("sparc64: vdso: Switch to the generic vDSO library")
Closes: https://github.com/sparclinux/issues/issues/94
Signed-off-by: Stian Halseth <stian@itx.no>
Reviewed-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
v2: add the Fixes: tag for the switch to the generic vDSO library, as
    the diff is against that code (Thomas); collect Reviewed-by.

 arch/sparc/include/asm/vdso/vsyscall.h | 10 ++++++++++
 arch/sparc/vdso/vma.c                  |  6 ++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/sparc/include/asm/vdso/vsyscall.h b/arch/sparc/include/asm/vdso/vsyscall.h
index 8bfe703fedc5..4852f122ce47 100644
--- a/arch/sparc/include/asm/vdso/vsyscall.h
+++ b/arch/sparc/include/asm/vdso/vsyscall.h
@@ -5,6 +5,16 @@
 
 #define __VDSO_PAGES 4
 
+#ifndef __ASSEMBLER__
+
+/* The user mapping may alias the kernel one in the VIPT D-cache. */
+struct vdso_time_data;
+void __arch_sync_vdso_time_data(struct vdso_time_data *vdata);
+#define __arch_sync_vdso_time_data __arch_sync_vdso_time_data
+
+#endif /* !__ASSEMBLER__ */
+
+/* The asm-generic header needs to be included after the definitions above */
 #include <asm-generic/vdso/vsyscall.h>
 
 #endif /* _ASM_SPARC_VDSO_VSYSCALL_H */
diff --git a/arch/sparc/vdso/vma.c b/arch/sparc/vdso/vma.c
index 60029d60f4d3..fe6a47af6b05 100644
--- a/arch/sparc/vdso/vma.c
+++ b/arch/sparc/vdso/vma.c
@@ -27,6 +27,12 @@
 
 unsigned int __read_mostly vdso_enabled = 1;
 
+/* Called by the timekeeping code after every update of the vDSO data. */
+void __arch_sync_vdso_time_data(struct vdso_time_data *vdata)
+{
+	flush_dcache_page(virt_to_page(vdata));
+}
+
 #ifdef	CONFIG_SPARC64
 static struct vm_special_mapping vdso_mapping64 = {
 	.name = "[vdso]"
-- 
2.43.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] sparc64: vdso: Flush the D-cache after updating the time data
  2026-09-17  8:25 [PATCH] sparc64: vdso: Flush the D-cache after updating the time data Stian Halseth
  2026-09-25  7:55 ` Thomas Weißschuh
  2026-09-25  8:02 ` [PATCH v2] " Stian Halseth
@ 2026-09-27 20:49 ` Imre Kaloz
  2 siblings, 0 replies; 4+ messages in thread
From: Imre Kaloz @ 2026-09-27 20:49 UTC (permalink / raw)
  To: Stian Halseth
  Cc: davem, Andreas Larsson, Thomas Weissschuh, Thomas Gleixner,
	sparclinux, linux-kernel

On Thu, 17 Sep 2026 10:25:47 +0200
Stian Halseth <stian@itx.no> wrote:

> On a Sun Fire V240 (UltraSPARC IIIi, clocksource stick) this makes
> clock_gettime(CLOCK_MONOTONIC) via the vDSO wrong for most calls on
> the tick CPU, by multiples of the 10 ms tick and up to a second, in
> about half of all processes: those that drew the other colour at
> exec.

Hi Stian,

Confirmed on a Sun Ultra 45 (UltraSPARC IIIi, SMP). The unpatched
kernel's vDSO clock_gettime() went stale on 3 out of 3 boots, up to
85% of CLOCK_MONOTONIC/CLOCK_REALTIME reads on the affected CPU, with
a lag up to 1492 ms. A kernel carrying this patch showed 0% stale
reads on 3 out of 3 boots.

Tested-by: Imre Kaloz <kaloz@kernel.org>


Best,
Imre

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-27 20:50 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-17  8:25 [PATCH] sparc64: vdso: Flush the D-cache after updating the time data Stian Halseth
2026-09-25  7:55 ` Thomas Weißschuh
2026-09-25  8:02 ` [PATCH v2] " Stian Halseth
2026-09-27 20:49 ` [PATCH] " Imre Kaloz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®