* [PATCH RFC 0/2] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
@ 2026-04-17 14:56 André Almeida
2026-04-17 14:56 ` [PATCH RFC 1/2] arm64: vdso: Prepare for robust futex unlock support André Almeida
2026-04-17 14:56 ` [PATCH RFC 2/2] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
0 siblings, 2 replies; 4+ messages in thread
From: André Almeida @ 2026-04-17 14:56 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Florian Weimer, Rich Felker, Torvald Riegel,
Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
Liam R . Howlett, Uros Bizjak, Thomas Weißschuh
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
Hi folks,
This is my take on implementing the new vDSO for unlocking a robust futex in
arm64. If you don't know what's that, Thomas wrote a good summary,
including the motivation for this work and the x86 implementation:
https://lore.kernel.org/lkml/878qb89g7b.ffs@tglx/
There are some loose ends in my patchset so I'm sending as a RFC to ask
some questions:
- I haven't managed to expose the assembly labels correctly, the linker can't
find it and the compilation fails, more info in patch 1/2
- If the process is interrupted between the labels, we need to check the
conditional flags and clear the op_pending address from the register. Using
objdump I see that op_pending addr is being stored at x2, but I suspect that
this isn't stable, so I need to figure out how to make sure that the address
will always be stored in the same register.
- So far I have implemented only the LL/SC version to make review easier, but I
can do the LSE version as well.
This patchset works fine with the tests proposed at
https://lore.kernel.org/lkml/20260330120118.012924430@kernel.org/ (but of course
without the labels the complete mechanism doesn't work properly).
---
André Almeida (2):
arm64: vdso: Prepare for robust futex unlock support
arm64: vdso: Implement __vdso_futex_robust_try_unlock()
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/futex_robust.h | 35 +++++++++++++
arch/arm64/include/asm/vdso.h | 4 ++
arch/arm64/kernel/vdso.c | 29 +++++++++++
arch/arm64/kernel/vdso/Makefile | 9 +++-
arch/arm64/kernel/vdso/vdso.lds.S | 4 ++
.../kernel/vdso/vfutex_robust_list_try_unlock.c | 59 ++++++++++++++++++++++
7 files changed, 140 insertions(+), 1 deletion(-)
---
base-commit: 0e8896e9899b607bb168c1cce340596b8c2e3e2b
change-id: 20260416-tonyk-robust_arm-54ff77d2c4e4
Best regards,
--
André Almeida <andrealmeid@igalia.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH RFC 1/2] arm64: vdso: Prepare for robust futex unlock support
2026-04-17 14:56 [PATCH RFC 0/2] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
@ 2026-04-17 14:56 ` André Almeida
2026-04-17 15:08 ` Florian Weimer
2026-04-17 14:56 ` [PATCH RFC 2/2] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
1 sibling, 1 reply; 4+ messages in thread
From: André Almeida @ 2026-04-17 14:56 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Florian Weimer, Rich Felker, Torvald Riegel,
Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
Liam R . Howlett, Uros Bizjak, Thomas Weißschuh
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
There will be a VDSO function to unlock non-contended robust futexes in
user space. The unlock sequence is racy vs. clearing the list_pending_op
pointer in the task's robust list head. To plug this race the kernel needs
to know the critical section window so it can clear the pointer when the
task is interrupted within that race window. The window is determined by
labels in the inline assembly.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
RFC: Those symbols can't be found by the linker after patch 2/2, it fails with:
ld: arch/arm64/kernel/vdso.o: in function `vdso_futex_robust_unlock_update_ips':
arch/arm64/kernel/vdso.c:72:(.text+0x200): undefined reference to `__futex_list64_try_unlock_cs_success'
ld: arch/arm64/kernel/vdso.o: relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol `__futex_list64_try_unlock_cs_success' which may bind externally can not be used when making a shared object; recompile with -fPIC
arch/arm64/kernel/vdso.c:72:(.text+0x200): dangerous relocation: unsupported relocation
---
arch/arm64/include/asm/vdso.h | 4 ++++
arch/arm64/kernel/vdso.c | 29 +++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 232b46969088..182fde1df3dd 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -18,6 +18,10 @@
extern char vdso_start[], vdso_end[];
extern char vdso32_start[], vdso32_end[];
+extern char __futex_list64_try_unlock_cs_success[], __futex_list64_try_unlock_cs_end[];
+#ifdef CONFIG_COMPAT
+extern char __futex_list32_try_unlock_cs_success[], __futex_list32_try_unlock_cs_end[];
+#endif
#endif /* !__ASSEMBLER__ */
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 592dd8668de4..42a82e73a774 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -11,6 +11,7 @@
#include <linux/clocksource.h>
#include <linux/elf.h>
#include <linux/err.h>
+#include <linux/futex.h>
#include <linux/errno.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
@@ -57,6 +58,32 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
#endif /* CONFIG_COMPAT_VDSO */
};
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+static void vdso_futex_robust_unlock_update_ips(enum vdso_abi abi, struct mm_struct *mm)
+{
+ unsigned long vdso = (unsigned long) mm->context.vdso;
+ struct futex_mm_data *fd = &mm->futex;
+
+ /*
+ * RFC: won't compile due to undefined reference to `__futex_list64_try_unlock_cs_...`
+
+ if (abi == VDSO_ABI_AA64) {
+ futex_set_vdso_cs_range(fd, 0, vdso, (uintptr_t) __futex_list64_try_unlock_cs_success,
+ (uintptr_t) __futex_list64_try_unlock_cs_end, false);
+ }
+
+#ifdef CONFIG_COMPAT
+ if (abi == VDSO_ABI_AA32) {
+ futex_set_vdso_cs_range(fd, 1, vdso, (uintptr_t) __futex_list32_try_unlock_cs_success,
+ (uintptr_t) __futex_list32_try_unlock_cs_end, true);
+ }
+#endif
+ */
+}
+#else
+static inline void vdso_futex_robust_unlock_update_ips(enum vdso_abi abi, struct mm_struct *mm) { }
+#endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
+
static int vdso_mremap(const struct vm_special_mapping *sm,
struct vm_area_struct *new_vma)
{
@@ -134,6 +161,8 @@ static int __setup_additional_pages(enum vdso_abi abi,
if (IS_ERR(ret))
goto up_fail;
+ vdso_futex_robust_unlock_update_ips(abi, mm);
+
return 0;
up_fail:
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH RFC 2/2] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
2026-04-17 14:56 [PATCH RFC 0/2] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
2026-04-17 14:56 ` [PATCH RFC 1/2] arm64: vdso: Prepare for robust futex unlock support André Almeida
@ 2026-04-17 14:56 ` André Almeida
1 sibling, 0 replies; 4+ messages in thread
From: André Almeida @ 2026-04-17 14:56 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Florian Weimer, Rich Felker, Torvald Riegel,
Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
Liam R . Howlett, Uros Bizjak, Thomas Weißschuh
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
Based on the x86 implementation, implement the vDSO function for unlocking
a robust futex correctly.
Commit xxxxxxxxxxxx ("x86/vdso: Implement __vdso_futex_robust_try_unlock()") has
the full explanation about why this mechanism is needed.
The unlock assembly sequence for arm64 is:
__futex_list64_try_unlock_cs_start:
ldxr x3, [x0] // Load the value at *futex
cmp x1, x3 // Compare with TID
b.ne __futex_list64_try_unlock_cs_end
stlxr w1, xzr, [x0] // Try to clear *futex
cbnz w1, __futex_list64_try_unlock_cs_start
__futex_list64_try_unlock_cs_success:
str xzr, [x2] // After clearing *futex, clear *op_pending
__futex_list64_try_unlock_cs_end:
The decision regarding if the pointer should be cleared or not lies on checking
the condition flag zero:
return (regs->user_regs.pstate & PSR_Z_BIT) ?
(void __user *) regs->user_regs.regs[2] : NULL;
If it's not zero, that means that the comparassion worked and the kernel should
clear op_pending (if userspace didn't managed to) stored at x2.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
RFC:
- Should I duplicate the explanation found in the x86 commit or can I just
point to it?
- Only LL/SC for now but I can add LSE later if this looks good
- It the objdump I see that op_pending is store at x2. But how stable is this,
how can I write it in a way that's always x2?
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/futex_robust.h | 35 +++++++++++++
arch/arm64/kernel/vdso/Makefile | 9 +++-
arch/arm64/kernel/vdso/vdso.lds.S | 4 ++
.../kernel/vdso/vfutex_robust_list_try_unlock.c | 59 ++++++++++++++++++++++
5 files changed, 107 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 427151a9db7f..e10cb97a51c7 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -249,6 +249,7 @@ config ARM64
select HAVE_RELIABLE_STACKTRACE
select HAVE_POSIX_CPU_TIMERS_TASK_WORK
select HAVE_FUNCTION_ARG_ACCESS_API
+ select HAVE_FUTEX_ROBUST_UNLOCK
select MMU_GATHER_RCU_TABLE_FREE
select HAVE_RSEQ
select HAVE_RUST if RUSTC_SUPPORTS_ARM64
diff --git a/arch/arm64/include/asm/futex_robust.h b/arch/arm64/include/asm/futex_robust.h
new file mode 100644
index 000000000000..f2b7a2b15cb5
--- /dev/null
+++ b/arch/arm64/include/asm/futex_robust.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_FUTEX_ROBUST_H
+#define _ASM_ARM64_FUTEX_ROBUST_H
+
+#include <asm/ptrace.h>
+
+static __always_inline void __user *arm64_futex_robust_unlock_get_pop(struct pt_regs *regs)
+{
+ /*
+ * RFC: According to the objdump bellow, x2 is the address of
+ * op_pending. How stable is this?
+
+ <__futex_list64_try_unlock_cs_start>:
+ ldxr x3, [x0]
+ cmp x1, x3
+ b.ne d7c <__futex_list64_try_unlock_cs_end> // b.any
+ stlxr w1, xzr, [x0]
+ cbnz w1, d64 <__futex_list64_try_unlock_cs_start>
+
+ <__futex_list64_try_unlock_cs_success>:
+ str xzr, [x2]
+
+ <__futex_list64_try_unlock_cs_end>:
+ mov w0, w3
+ ret
+ */
+
+ return (regs->user_regs.pstate & PSR_Z_BIT) ? NULL
+ : (void __user *) regs->user_regs.regs[2];
+}
+
+#define arch_futex_robust_unlock_get_pop(regs) \
+ arm64_futex_robust_unlock_get_pop(regs)
+
+#endif /* _ASM_ARM64_FUTEX_ROBUST_H */
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index 7dec05dd33b7..a65893d8100e 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -9,7 +9,8 @@
# Include the generic Makefile to check the built vdso.
include $(srctree)/lib/vdso/Makefile.include
-obj-vdso := vgettimeofday.o note.o sigreturn.o vgetrandom.o vgetrandom-chacha.o
+obj-vdso := vgettimeofday.o note.o sigreturn.o vgetrandom.o vgetrandom-chacha.o \
+ vfutex_robust_list_try_unlock.o
# Build rules
targets := $(obj-vdso) vdso.so vdso.so.dbg
@@ -45,9 +46,11 @@ CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
+CFLAGS_REMOVE_vfutex_robust_list_try_unlock.o = $(CC_FLAGS_REMOVE_VDSO)
CFLAGS_vgettimeofday.o = $(CC_FLAGS_ADD_VDSO)
CFLAGS_vgetrandom.o = $(CC_FLAGS_ADD_VDSO)
+CFLAGS_vfutex_robust_list_try_unlock.o = $(CC_FLAGS_ADD_VDSO)
ifneq ($(c-gettimeofday-y),)
CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)
@@ -57,6 +60,10 @@ ifneq ($(c-getrandom-y),)
CFLAGS_vgetrandom.o += -include $(c-getrandom-y)
endif
+ifneq ($(c-vfutex_robust_list_try_unlock-y),)
+ CFLAGS_vfutex_robust_list_try_unlock.o += -include $(c-vfutex_robust_list_try_unlock-y)
+endif
+
targets += vdso.lds
CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
index 52314be29191..33ce58516580 100644
--- a/arch/arm64/kernel/vdso/vdso.lds.S
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -104,6 +104,10 @@ VERSION
__kernel_clock_gettime;
__kernel_clock_getres;
__kernel_getrandom;
+ __vdso_futex_robust_list64_try_unlock;
+#ifdef CONFIG_COMPAT
+ __vdso_futex_robust_list32_try_unlock;
+#endif
local: *;
};
}
diff --git a/arch/arm64/kernel/vdso/vfutex_robust_list_try_unlock.c b/arch/arm64/kernel/vdso/vfutex_robust_list_try_unlock.c
new file mode 100644
index 000000000000..a9089d3cacfc
--- /dev/null
+++ b/arch/arm64/kernel/vdso/vfutex_robust_list_try_unlock.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <vdso/futex.h>
+#include <linux/stringify.h>
+
+#define LABEL(name, sz) __stringify(__futex_list##sz##_try_unlock_cs_##name)
+
+#define GLOBLS(sz) ".globl " LABEL(start, sz) ", " LABEL(success, sz) ", " LABEL(end, sz) "\n"
+
+__u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop)
+{
+ __u32 val, result;
+
+ asm volatile (
+ GLOBLS(64)
+ " prfm pstl1strm, %[lock] \n"
+ LABEL(start, 64)": \n"
+ " ldxr %[val], %[lock] \n"
+ " cmp %[tid], %[val] \n"
+ " bne " LABEL(end, 64)" \n"
+ " stlxr %w[result], xzr, %[lock] \n"
+ " cbnz %w[result], " LABEL(start, 64)" \n"
+ LABEL(success, 64)": \n"
+ " str xzr, %[pop] \n"
+ LABEL(end, 64)": \n"
+
+ : [val] "=&r" (val), [result] "=r" (result)
+ : [tid] "r" (tid), [lock] "Q" (*lock), [pop] "Q" (*pop)
+ : "memory"
+ );
+
+ return val;
+}
+
+#ifdef CONFIG_COMPAT
+__u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
+{
+ __u32 val, result;
+
+ asm volatile (
+ GLOBLS(32)
+ " prfm pstl1strm, %[lock] \n"
+ LABEL(start, 32)": \n"
+ " ldxr %w[val], %[lock] \n"
+ " cmp %w[tid], %w[val] \n"
+ " bne " LABEL(end, 32)" \n"
+ " stlxr %w[result], wzr, %w[lock] \n"
+ " cbnz %w[result], " LABEL(start, 32)" \n"
+ LABEL(success, 32)": \n"
+ " str wzr, %w[pop] \n"
+ LABEL(end, 32)": \n"
+
+ : [val] "=&r" (val), [result] "=r" (result)
+ : [tid] "r" (tid), [lock] "Q" (*lock), [pop] "Q" (*pop)
+ : "memory"
+ );
+
+ return val;
+}
+#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH RFC 1/2] arm64: vdso: Prepare for robust futex unlock support
2026-04-17 14:56 ` [PATCH RFC 1/2] arm64: vdso: Prepare for robust futex unlock support André Almeida
@ 2026-04-17 15:08 ` Florian Weimer
0 siblings, 0 replies; 4+ messages in thread
From: Florian Weimer @ 2026-04-17 15:08 UTC (permalink / raw)
To: André Almeida
Cc: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Rich Felker, Torvald Riegel, Darren Hart,
Ingo Molnar, Davidlohr Bueso, Arnd Bergmann, Liam R . Howlett,
Uros Bizjak, Thomas Weißschuh, linux-arm-kernel,
linux-kernel, linux-arch, kernel-dev
* André Almeida:
> There will be a VDSO function to unlock non-contended robust futexes in
> user space. The unlock sequence is racy vs. clearing the list_pending_op
> pointer in the task's robust list head. To plug this race the kernel needs
> to know the critical section window so it can clear the pointer when the
> task is interrupted within that race window. The window is determined by
> labels in the inline assembly.
>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> ---
> RFC: Those symbols can't be found by the linker after patch 2/2, it fails with:
>
> ld: arch/arm64/kernel/vdso.o: in function `vdso_futex_robust_unlock_update_ips':
> arch/arm64/kernel/vdso.c:72:(.text+0x200): undefined reference to `__futex_list64_try_unlock_cs_success'
> ld: arch/arm64/kernel/vdso.o: relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol `__futex_list64_try_unlock_cs_success' which may bind externally can not be used when making a shared object; recompile with -fPIC
> arch/arm64/kernel/vdso.c:72:(.text+0x200): dangerous relocation: unsupported relocation
I think your GLOBLS definition adds a 64 suffix. That shouldn't be
necessary on AArch64. It's not reflected in the references, so you end
up with an undefined symbol error.
Thanks,
Florian
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-04-17 15:08 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-17 14:56 [PATCH RFC 0/2] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
2026-04-17 14:56 ` [PATCH RFC 1/2] arm64: vdso: Prepare for robust futex unlock support André Almeida
2026-04-17 15:08 ` Florian Weimer
2026-04-17 14:56 ` [PATCH RFC 2/2] arm64: vdso: Implement __vdso_futex_robust_try_unlock() André Almeida
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox