[patch v2 08/11] futex: Add robust futex unlock IP range

From: Thomas Gleixner

Date: Thu Mar 19 2026 - 19:33:50 EST


There will be a VDSO function to unlock robust futexes in user space. The
unlock sequence is racy vs. clearing the list_pending_op pointer in the
tasks robust list head. To plug this race the kernel needs to know the
instruction window. As the VDSO is per MM the addresses are stored in
mm_struct::futex.

Architectures which implement support for this have to update these
addresses when the VDSO is (re)mapped and indicate the pending op pointer
size which is matching the IP.

Arguably this could be resolved by chasing mm->context->vdso->image, but
that's architecture specific and requires to touch quite some cache
lines. Having it in mm::futex reduces the cache line impact and avoids
having yet another set of architecture specific functionality.

To support multi size robust list applications (gaming) this provides two
ranges.

Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
---
V2: Store ranges in a struct with size information and allow up to two ranges.
---
include/linux/futex_types.h | 22 ++++++++++++++++++++++
include/linux/mm_types.h | 1 +
init/Kconfig | 6 ++++++
3 files changed, 29 insertions(+)

--- a/include/linux/futex_types.h
+++ b/include/linux/futex_types.h
@@ -31,6 +31,20 @@ struct futex_sched_data {
};

/**
+ * struct futex_unlock_cs_range - Range for the VDSO unlock critical section
+ * @start_ip: The start IP of the robust futex unlock critical section (inclusive)
+ * @end_ip: The end IP of the robust futex unlock critical section (exclusive)
+ * @pop_size32: Pending OP pointer size indicator. 0 == 64-bit, 1 == 32-bit
+ */
+struct futex_unlock_cs_range {
+ unsigned long start_ip;
+ unsigned long end_ip;
+ unsigned int pop_size32;
+};
+
+#define FUTEX_ROBUST_MAX_CS_RANGES 2
+
+/**
* struct futex_mm_data - Futex related per MM data
* @phash_lock: Mutex to protect the private hash operations
* @phash: RCU managed pointer to the private hash
@@ -39,6 +53,10 @@ struct futex_sched_data {
* @phash_rcu: RCU head for call_rcu()
* @phash_atomic: Aggregate value for @phash_ref
* @phash_ref: Per CPU reference counter for a private hash
+ *
+ * @unlock_cs_num_ranges: The number of critical section ranges for VDSO assisted unlock
+ * of robust futexes.
+ * @unlock_cs_ranges: The critical section ranges for VDSO assisted unlock
*/
struct futex_mm_data {
#ifdef CONFIG_FUTEX_PRIVATE_HASH
@@ -50,6 +68,10 @@ struct futex_mm_data {
atomic_long_t phash_atomic;
unsigned int __percpu *phash_ref;
#endif
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+ unsigned int unlock_cs_num_ranges;
+ struct futex_unlock_cs_range unlock_cs_ranges[FUTEX_ROBUST_MAX_CS_RANGES];
+#endif
};

#else
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <linux/rseq_types.h>
#include <linux/bitmap.h>
+#include <linux/futex_types.h>

#include <asm/mmu.h>

--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1822,6 +1822,12 @@ config FUTEX_MPOL
depends on FUTEX && NUMA
default y

+config HAVE_FUTEX_ROBUST_UNLOCK
+ bool
+
+config FUTEX_ROBUST_UNLOCK
+ def_bool FUTEX && HAVE_GENERIC_VDSO && GENERIC_IRQ_ENTRY && RSEQ && HAVE_FUTEX_ROBUST_UNLOCK
+
config EPOLL
bool "Enable eventpoll support" if EXPERT
default y