* [PATCH v8 01/10] futex: Skip test_futex_robust_unlock() if not supported
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 17:31 ` [PATCH v8 02/10] futex: Use explicit sizes for compat_robust_list structs André Almeida
` (8 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
Skip test_futex_robust_unlock() if FUTEX_ROBUST_UNLOCK operation is not
supported.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
tools/testing/selftests/futex/functional/robust_list.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
index 87217c549361..ddb610149857 100644
--- a/tools/testing/selftests/futex/functional/robust_list.c
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -792,6 +792,9 @@ TEST_F(futex_op, test_futex_robust_unlock)
ret = sys_futex_robust_unlock(futex, FUTEX_ROBUST_UNLOCK | variant->op, tid,
&head.list_op_pending, variant->val3);
+ if (ret == -1 && errno == ENOSYS)
+ SKIP(return, "No support for FUTEX_ROBUST_UNLOCK");
+
ASSERT_EQ(ret, 0);
ASSERT_EQ(*futex, 0);
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 02/10] futex: Use explicit sizes for compat_robust_list structs
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
2026-11-15 17:31 ` [PATCH v8 01/10] futex: Skip test_futex_robust_unlock() if not supported André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 17:31 ` [PATCH v8 03/10] futex: Make exit_robust_list32() unconditionally available for 64-bit kernels André Almeida
` (7 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
There are two functions for handling robust lists during a task exit:
exit_robust_list() and compat_exit_robust_list(). The first one handles
either 64-bit or 32-bit lists, depending on the kernel bitness.
compat_exit_robust_list() exists only in 64-bit kernels that supports
32-bit syscalls entry points (also known as compat entry points).
The new syscall set_robust_list2() needs to handle both 64-bit and
32-bit robust lists, regardless of compat entry being enabled, so it
needs to have both functions always available.
In preparation for this, use explicit size for struct members of
compat_robust_list and compat_robust_list_head. Rename the structs and
compat_exit_robust_list() to make clear which bitness it handles.
Keep exit_robust_list() as it is: used to handle the native bit size of
the kernel.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
include/linux/compat.h | 13 +++----------
include/linux/futex.h | 4 ++++
include/linux/futex_types.h | 5 ++---
include/uapi/linux/futex.h | 10 ++++++++++
kernel/futex/core.c | 33 +++++++++++++++++----------------
kernel/futex/syscalls.c | 9 +++++----
6 files changed, 41 insertions(+), 33 deletions(-)
diff --git a/include/linux/compat.h b/include/linux/compat.h
index ad37ca617e65..77bfef1b3bd2 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -390,15 +390,8 @@ struct compat_ifconf {
compat_caddr_t ifcbuf;
};
-struct compat_robust_list {
- compat_uptr_t next;
-};
-
-struct compat_robust_list_head {
- struct compat_robust_list list;
- compat_long_t futex_offset;
- compat_uptr_t list_op_pending;
-};
+struct robust_list32;
+struct robust_list_head32;
#ifdef CONFIG_COMPAT_OLD_SIGACTION
struct compat_old_sigaction {
@@ -677,7 +670,7 @@ asmlinkage long compat_sys_waitid(int, compat_pid_t,
struct compat_siginfo __user *, int,
struct compat_rusage __user *);
asmlinkage long
-compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
+compat_sys_set_robust_list(struct robust_list_head32 __user *head,
compat_size_t len);
asmlinkage long
compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
diff --git a/include/linux/futex.h b/include/linux/futex.h
index a895d8c69d66..93316876a4ee 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -72,6 +72,10 @@ static inline void futex_init_task(struct task_struct *tsk)
INIT_LIST_HEAD(&tsk->futex.pi_state_list);
tsk->futex.state = FUTEX_STATE_OK;
mutex_init(&tsk->futex.exit_mutex);
+ tsk->futex.robust_list = NULL;
+#ifdef CONFIG_COMPAT
+ tsk->futex.robust_list32 = NULL;
+#endif
}
void futex_exit_recursive(struct task_struct *tsk);
diff --git a/include/linux/futex_types.h b/include/linux/futex_types.h
index 34b16f2828e7..f58616d7e20b 100644
--- a/include/linux/futex_types.h
+++ b/include/linux/futex_types.h
@@ -7,14 +7,13 @@
#include <linux/mutex_types.h>
#include <linux/types.h>
-struct compat_robust_list_head;
struct futex_pi_state;
struct robust_list_head;
/**
* struct futex_sched_data - Futex related per task data
* @robust_list: User space registered robust list pointer
- * @compat_robust_list: User space registered robust list pointer for compat tasks
+ * @robust_list32: User space registered robust list pointer for compat tasks
* @pi_state_list: List head for Priority Inheritance (PI) state management
* @pi_state_cache: Pointer to cache one PI state object per task
* @exit_mutex: Mutex for serializing exit
@@ -23,7 +22,7 @@ struct robust_list_head;
struct futex_sched_data {
struct robust_list_head __user *robust_list;
#ifdef CONFIG_COMPAT
- struct compat_robust_list_head __user *compat_robust_list;
+ struct robust_list_head32 __user *robust_list32;
#endif
struct list_head pi_state_list;
struct futex_pi_state *pi_state_cache;
diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
index 10a36c551675..b39f8a23a84b 100644
--- a/include/uapi/linux/futex.h
+++ b/include/uapi/linux/futex.h
@@ -179,6 +179,16 @@ struct robust_list_head {
struct robust_list __user *list_op_pending;
};
+struct robust_list32 {
+ __u32 next;
+};
+
+struct robust_list_head32 {
+ struct robust_list32 list;
+ __s32 futex_offset;
+ __u32 list_op_pending;
+};
+
/*
* Are there any waiters for this robust futex:
*/
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index a240638f69e5..28a6ad4a8da4 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -1243,9 +1243,10 @@ static void __user *futex_uaddr(struct robust_list __user *entry,
/*
* Fetch a robust-list pointer. Bit 0 signals PI futexes:
*/
-static inline int
-compat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
- compat_uptr_t __user *head, unsigned int *pflags)
+static inline int fetch_robust_entry32(compat_uptr_t *uentry,
+ struct robust_list __user **entry,
+ compat_uptr_t __user *head,
+ unsigned int *pflags)
{
if (get_user(*uentry, head))
return -EFAULT;
@@ -1262,9 +1263,9 @@ compat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **ent
*
* We silently return on any sign of list-walking problem.
*/
-static void compat_exit_robust_list(struct task_struct *curr)
+static void exit_robust_list32(struct task_struct *curr)
{
- struct compat_robust_list_head __user *head = current->futex.compat_robust_list;
+ struct robust_list_head32 __user *head = curr->futex.robust_list32;
unsigned int limit = ROBUST_LIST_LIMIT, cur_mod, next_mod, pend_mod;
struct robust_list __user *entry, *next_entry, *pending;
compat_uptr_t uentry, next_uentry, upending;
@@ -1275,7 +1276,7 @@ static void compat_exit_robust_list(struct task_struct *curr)
* Fetch the list head (which was registered earlier, via
* sys_set_robust_list()):
*/
- if (compat_fetch_robust_entry(&uentry, &entry, &head->list.next, &cur_mod))
+ if (fetch_robust_entry32(&uentry, &entry, &head->list.next, &cur_mod))
return;
/*
* Fetch the relative futex offset:
@@ -1286,7 +1287,7 @@ static void compat_exit_robust_list(struct task_struct *curr)
* Fetch any possibly pending lock-add first, and handle it
* if it exists:
*/
- if (compat_fetch_robust_entry(&upending, &pending, &head->list_op_pending, &pend_mod))
+ if (fetch_robust_entry32(&upending, &pending, &head->list_op_pending, &pend_mod))
return;
next_entry = NULL; /* avoid warning with gcc */
@@ -1295,7 +1296,7 @@ static void compat_exit_robust_list(struct task_struct *curr)
* Fetch the next entry in the list before calling
* handle_futex_death:
*/
- rc = compat_fetch_robust_entry(&next_uentry, &next_entry,
+ rc = fetch_robust_entry32(&next_uentry, &next_entry,
(compat_uptr_t __user *)&entry->next, &next_mod);
/*
* A pending lock might already be on the list, so
@@ -1327,20 +1328,20 @@ static void compat_exit_robust_list(struct task_struct *curr)
}
}
-static bool compat_robust_list_clear_pending(u32 __user *pop)
+static bool robust_list_clear_pending32(u32 __user *pop)
{
- struct compat_robust_list_head __user *head = current->futex.compat_robust_list;
+ struct robust_list_head32 __user *head = current->futex.robust_list32;
if (!put_user(0U, pop))
return true;
/* See comment in robust_list_clear_pending(). */
if (pop == &head->list_op_pending)
- current->futex.compat_robust_list = NULL;
+ current->futex.robust_list32 = NULL;
return false;
}
#else
-static bool compat_robust_list_clear_pending(u32 __user *pop_addr) { return false; }
+static bool robust_list_clear_pending32(u32 __user *pop_addr) { return false; }
#endif
#ifdef CONFIG_FUTEX_PI
@@ -1443,7 +1444,7 @@ bool futex_robust_list_clear_pending(void __user *pop, unsigned int flags)
return false;
if (IS_ENABLED(CONFIG_64BIT) && size32bit)
- return compat_robust_list_clear_pending(pop);
+ return robust_list_clear_pending32(pop);
return robust_list_clear_pending(pop);
}
@@ -1472,9 +1473,9 @@ static void futex_cleanup(struct task_struct *tsk)
}
#ifdef CONFIG_COMPAT
- if (unlikely(tsk->futex.compat_robust_list)) {
- compat_exit_robust_list(tsk);
- tsk->futex.compat_robust_list = NULL;
+ if (unlikely(tsk->futex.robust_list32)) {
+ exit_robust_list32(tsk);
+ tsk->futex.robust_list32 = NULL;
}
#endif
diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c
index 2fa19d9d008d..4a45bace75fc 100644
--- a/kernel/futex/syscalls.c
+++ b/kernel/futex/syscalls.c
@@ -39,7 +39,7 @@ static inline void __user *futex_task_robust_list(struct task_struct *p, bool co
{
#ifdef CONFIG_COMPAT
if (compat)
- return p->futex.compat_robust_list;
+ return p->futex.robust_list32;
#endif
return p->futex.robust_list;
}
@@ -478,13 +478,14 @@ SYSCALL_DEFINE4(futex_requeue,
}
#ifdef CONFIG_COMPAT
-COMPAT_SYSCALL_DEFINE2(set_robust_list, struct compat_robust_list_head __user *, head,
+COMPAT_SYSCALL_DEFINE2(set_robust_list, struct robust_list_head32 __user *, head,
compat_size_t, len)
{
if (unlikely(len != sizeof(*head)))
return -EINVAL;
- current->futex.compat_robust_list = head;
+ current->futex.robust_list32 = head;
+
return 0;
}
@@ -492,7 +493,7 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
compat_uptr_t __user *, head_ptr,
compat_size_t __user *, len_ptr)
{
- struct compat_robust_list_head __user *head = futex_get_robust_list_common(pid, true);
+ struct robust_list_head32 __user *head = futex_get_robust_list_common(pid, true);
if (IS_ERR(head))
return PTR_ERR(head);
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 03/10] futex: Make exit_robust_list32() unconditionally available for 64-bit kernels
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
2026-11-15 17:31 ` [PATCH v8 01/10] futex: Skip test_futex_robust_unlock() if not supported André Almeida
2026-11-15 17:31 ` [PATCH v8 02/10] futex: Use explicit sizes for compat_robust_list structs André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 17:31 ` [PATCH v8 04/10] futex: Create set_robust_list2() syscall André Almeida
` (6 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
The new syscall set_robust_list2() needs to handle both 64-bit and
32-bit robust lists, but not every 64-bit platform have compat entry
points. Make exit_robust_list32() unconditionally available for 64-bit
kernels regardless of having a compat configuration.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
kernel/futex/core.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index 28a6ad4a8da4..6fce97012015 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -1230,12 +1230,12 @@ static bool robust_list_clear_pending(unsigned long __user *pop)
return false;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_64BIT
static void __user *futex_uaddr(struct robust_list __user *entry,
compat_long_t futex_offset)
{
- compat_uptr_t base = ptr_to_compat(entry);
- void __user *uaddr = compat_ptr(base + futex_offset);
+ u32 base = (u32)(unsigned long)(entry);
+ void __user *uaddr = (void __user *)(unsigned long)(base + futex_offset);
return uaddr;
}
@@ -1268,8 +1268,8 @@ static void exit_robust_list32(struct task_struct *curr)
struct robust_list_head32 __user *head = curr->futex.robust_list32;
unsigned int limit = ROBUST_LIST_LIMIT, cur_mod, next_mod, pend_mod;
struct robust_list __user *entry, *next_entry, *pending;
- compat_uptr_t uentry, next_uentry, upending;
- compat_long_t futex_offset;
+ u32 uentry, next_uentry, upending;
+ s32 futex_offset;
int rc;
/*
@@ -1472,7 +1472,7 @@ static void futex_cleanup(struct task_struct *tsk)
tsk->futex.robust_list = NULL;
}
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_64BIT
if (unlikely(tsk->futex.robust_list32)) {
exit_robust_list32(tsk);
tsk->futex.robust_list32 = NULL;
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 04/10] futex: Create set_robust_list2() syscall
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
` (2 preceding siblings ...)
2026-11-15 17:31 ` [PATCH v8 03/10] futex: Make exit_robust_list32() unconditionally available for 64-bit kernels André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 17:31 ` [PATCH v8 05/10] futex: Create get_robust_list2() syscall André Almeida
` (5 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
Emulators (like FEX-Emu, to run x86 apps on top of Aarch64) have two
special needs about robust lists: to be able to register more than one
robust list, one of the app being emulated and one list for the emulator
itself; and to be able to walk on 32-bit robusts lists on a 64-bit
platform without compat entry points.
The current syscall allows for one robust list per task (on x86-64, it
can have two if compat is enabled) and on Aarch64 there's no way to
parse a 32-bit robust list. The current syscall cannot be expanded to
solve both needs, so create a new syscall, set_robust_list2() with the
following signature:
sys_set_robust_list2(struct robust_list_head *head, unsigned int cmd,
unsigned int flags)
The new syscall allows to set multiple lists per task, of 64-bit or
32-bit types.
- `*head` is the same structure used in the current syscall.
- `cmd` defines the operation to perform:
- `FUTEX_ROBUST_LIST_CMD_CREATE_{32, 64}` sets a new robust list head,
the kernel returns the index of the list. User can choose between 32 or
64 bit for pointer size of the list head.
- FUTEX_ROBUST_LIST_CMD_MODIFY_{32, 64}` change the `*head` value of a
list. Setting it to NULL destroys an index and let it free to be
allocated by other CREATE caller.
- `FUTEX_ROBUST_LIST_CMD_LIST_LIMIT` gets the limit of lists per task
- `flag` is unused now but can be used to expand the interface
The array of lists is dynamically allocated in the first use, but has a
fixed size determined by the kernel. 8 slots are more than enough to
cover the target use case and allows for more use cases. The command for
getting the list limit allows to userspace check if the kernel ever
expands this list. The first two slots are reserved for the kernel, to
store the original syscall robust_list_head's.
The array of lists is destroyed only during task exit.
The `FUTEX_ROBUST_LIST_CMD_CREATE_64` operation is only available for
64-bit kernels. In such kernels, lists created with
`FUTEX_ROBUST_LIST_CMD_SET_32` are marked with
`FUTEX_ROBUST_LIST_ENTRY_32BIT` and the kernel handles it with a special
function exit_robust_list32() to be able to walk in a list of 32-bit
pointers.
For 32-bit kernels, there's no special function available as every user
list and list handling functions will all have the same bitness.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
include/linux/futex.h | 24 ++++++++
include/linux/futex_types.h | 2 +
include/uapi/linux/futex.h | 18 ++++++
kernel/futex/core.c | 138 +++++++++++++++++++++++++++++++++++++++++---
kernel/futex/futex.h | 5 ++
kernel/futex/syscalls.c | 55 ++++++++++++++++++
kernel/sys_ni.c | 1 +
7 files changed, 236 insertions(+), 7 deletions(-)
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 93316876a4ee..03a3973a7068 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -5,6 +5,7 @@
#include <linux/sched.h>
#include <linux/ktime.h>
#include <linux/mm_types.h>
+#include <linux/compat.h>
#include <uapi/linux/futex.h>
@@ -66,6 +67,28 @@ enum {
FUTEX_STATE_DEAD,
};
+#define FUTEX_ROBUST_LIST_NATIVE_IDX 0
+#define FUTEX_ROBUST_LIST_COMPAT_IDX 1
+#define FUTEX_ROBUST_LIST2_IDX 2
+#define FUTEX_ROBUST_LISTS_PER_USER 8
+#define FUTEX_ROBUST_LIST2_MAX_IDX (FUTEX_ROBUST_LIST2_IDX + FUTEX_ROBUST_LISTS_PER_USER)
+
+/*
+ * List entries without _32BIT flag are using the native machine size
+ */
+#define FUTEX_ROBUST_LIST_ENTRY_INUSE 0x1UL
+#define FUTEX_ROBUST_LIST_ENTRY_32BIT 0x2UL
+#define FUTEX_ROBUST_LIST_ENTRY_MASK (~0x3UL)
+
+static inline bool futex_in_32bit_syscall(void)
+{
+#ifdef CONFIG_X86
+ return !IS_ENABLED(CONFIG_64BIT) || in_32bit_syscall();
+#else
+ return !IS_ENABLED(CONFIG_64BIT);
+#endif
+}
+
static inline void futex_init_task(struct task_struct *tsk)
{
memset(&tsk->futex, 0, sizeof(tsk->futex));
@@ -76,6 +99,7 @@ static inline void futex_init_task(struct task_struct *tsk)
#ifdef CONFIG_COMPAT
tsk->futex.robust_list32 = NULL;
#endif
+ tsk->futex.robust_lists = NULL;
}
void futex_exit_recursive(struct task_struct *tsk);
diff --git a/include/linux/futex_types.h b/include/linux/futex_types.h
index f58616d7e20b..58321314ecab 100644
--- a/include/linux/futex_types.h
+++ b/include/linux/futex_types.h
@@ -18,6 +18,7 @@ struct robust_list_head;
* @pi_state_cache: Pointer to cache one PI state object per task
* @exit_mutex: Mutex for serializing exit
* @state: Futex handling state to handle exit races correctly
+ * @robust_lists: List of robust lists heads
*/
struct futex_sched_data {
struct robust_list_head __user *robust_list;
@@ -28,6 +29,7 @@ struct futex_sched_data {
struct futex_pi_state *pi_state_cache;
struct mutex exit_mutex;
unsigned int state;
+ uintptr_t *robust_lists;
};
#ifdef CONFIG_FUTEX_PRIVATE_HASH
diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
index b39f8a23a84b..becf43230df4 100644
--- a/include/uapi/linux/futex.h
+++ b/include/uapi/linux/futex.h
@@ -189,6 +189,24 @@ struct robust_list_head32 {
__u32 list_op_pending;
};
+/*
+ * Commands for set_robust_list2 syscall
+ */
+enum robust_list2_cmd {
+ FUTEX_ROBUST_LIST_CMD_CREATE_64,
+ FUTEX_ROBUST_LIST_CMD_CREATE_32,
+ FUTEX_ROBUST_LIST_CMD_MODIFY_64,
+ FUTEX_ROBUST_LIST_CMD_MODIFY_32,
+ FUTEX_ROBUST_LIST_CMD_LIST_LIMIT,
+ FUTEX_ROBUST_LIST_CMD_USER_MAX,
+
+ /*
+ * Kernel internal, rejected for user space
+ */
+ FUTEX_ROBUST_LIST_SET_NATIVE = 128,
+ FUTEX_ROBUST_LIST_SET_COMPAT,
+};
+
/*
* Are there any waiters for this robust futex:
*/
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index 6fce97012015..dd6fa8035fb6 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -73,6 +73,90 @@ struct futex_private_hash {
struct futex_hash_bucket queues[];
};
+int futex_robust_list_create(uintptr_t head, enum robust_list2_cmd cmd)
+{
+ uintptr_t *rl = current->futex.robust_lists, entry = FUTEX_ROBUST_LIST_ENTRY_INUSE;
+ unsigned int index;
+
+ if (!rl) {
+ rl = kcalloc(FUTEX_ROBUST_LIST2_MAX_IDX, sizeof(*rl), GFP_KERNEL);
+ if (!rl)
+ return -ENOMEM;
+
+ scoped_guard(mutex, ¤t->futex.exit_mutex) {
+ /* check if another thread set the list before us */
+ if (current->futex.robust_lists) {
+ kfree(rl);
+ rl = current->futex.robust_lists;
+ } else {
+ current->futex.robust_lists = rl;
+ }
+ }
+
+ }
+
+ switch (cmd) {
+ case FUTEX_ROBUST_LIST_CMD_CREATE_32:
+ if (head)
+ entry |= FUTEX_ROBUST_LIST_ENTRY_32BIT;
+ fallthrough;
+ case FUTEX_ROBUST_LIST_CMD_CREATE_64:
+ /* Search for an empty slot */
+ for (index = FUTEX_ROBUST_LIST2_IDX;
+ index < FUTEX_ROBUST_LIST2_MAX_IDX; index++) {
+ if (rl[index] == 0)
+ goto exit;
+ }
+ return -ENOSPC;
+ default:
+ return -EINVAL;
+ }
+
+exit:
+ entry |= head;
+ scoped_guard(mutex, ¤t->futex.exit_mutex)
+ rl[index] = entry;
+
+ return index;
+}
+
+int futex_robust_list_modify(uintptr_t head, enum robust_list2_cmd cmd,
+ unsigned int index)
+{
+ uintptr_t *rl = current->futex.robust_lists, entry = head;
+
+ if (index >= FUTEX_ROBUST_LIST2_MAX_IDX - FUTEX_ROBUST_LIST2_IDX)
+ return -EINVAL;
+
+ /* See comment about index mapping at sys_set_robust_list2() */
+ index += FUTEX_ROBUST_LIST2_IDX;
+
+ if (!rl || !rl[index])
+ return -ENOENT;
+
+ switch (cmd) {
+ case FUTEX_ROBUST_LIST_CMD_MODIFY_64:
+ if (rl[index] & FUTEX_ROBUST_LIST_ENTRY_32BIT)
+ return -EINVAL;
+ if (futex_in_32bit_syscall())
+ return -EINVAL;
+ break;
+ case FUTEX_ROBUST_LIST_CMD_MODIFY_32:
+ if (!(rl[index] & FUTEX_ROBUST_LIST_ENTRY_32BIT))
+ return -EINVAL;
+ if (entry)
+ entry |= FUTEX_ROBUST_LIST_ENTRY_32BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ scoped_guard(mutex, ¤t->futex.exit_mutex)
+ rl[index] = entry;
+
+ return 0;
+}
+
/*
* Fault injections for futexes.
*/
@@ -1148,9 +1232,8 @@ static inline int fetch_robust_entry(struct robust_list __user **entry,
*
* We silently return on any sign of list-walking problem.
*/
-static void exit_robust_list(struct task_struct *curr)
+static void exit_robust_list(struct task_struct *curr, struct robust_list_head __user *head)
{
- struct robust_list_head __user *head = curr->futex.robust_list;
unsigned int limit = ROBUST_LIST_LIMIT, cur_mod, next_mod, pend_mod;
struct robust_list __user *entry, *next_entry, *pending;
unsigned long futex_offset;
@@ -1263,9 +1346,8 @@ static inline int fetch_robust_entry32(compat_uptr_t *uentry,
*
* We silently return on any sign of list-walking problem.
*/
-static void exit_robust_list32(struct task_struct *curr)
+static void exit_robust_list32(struct task_struct *curr, struct robust_list_head32 __user *head)
{
- struct robust_list_head32 __user *head = curr->futex.robust_list32;
unsigned int limit = ROBUST_LIST_LIMIT, cur_mod, next_mod, pend_mod;
struct robust_list __user *entry, *next_entry, *pending;
u32 uentry, next_uentry, upending;
@@ -1342,7 +1424,12 @@ static bool robust_list_clear_pending32(u32 __user *pop)
}
#else
static bool robust_list_clear_pending32(u32 __user *pop_addr) { return false; }
-#endif
+
+static void exit_robust_list32(struct task_struct *curr, struct robust_list_head32 __user *head)
+{
+ pr_crit("32-bit kernel should never call %s", __func__);
+}
+#endif /* CONFIG_64BIT */
#ifdef CONFIG_FUTEX_PI
@@ -1465,16 +1552,53 @@ void __futex_fixup_robust_unlock(struct pt_regs *regs, struct futex_unlock_cs_ra
}
#endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
+static void exit_robust_lists(struct task_struct *tsk)
+{
+ uintptr_t *rl = tsk->futex.robust_lists;
+
+ tsk->futex.robust_lists = NULL;
+
+ for (unsigned int idx = 0; idx < FUTEX_ROBUST_LIST2_MAX_IDX; idx++) {
+ uintptr_t entry = rl[idx];
+
+ if (!(entry & FUTEX_ROBUST_LIST_ENTRY_MASK))
+ continue;
+
+ /*
+ * If the list type is the same as the kernel bitness, always
+ * calls exit_robust_list(). exit_robust_list32() is only for
+ * 32-bit lists in a 64-bit kernel.
+ */
+ if (IS_ENABLED(CONFIG_64BIT) && (entry & FUTEX_ROBUST_LIST_ENTRY_32BIT)) {
+ struct robust_list_head32 __user *head;
+
+ entry &= FUTEX_ROBUST_LIST_ENTRY_MASK;
+
+ head = (__force struct robust_list_head32 __user *)entry;
+ exit_robust_list32(tsk, head);
+ } else {
+ struct robust_list_head __user *head;
+
+ entry &= FUTEX_ROBUST_LIST_ENTRY_MASK;
+
+ head = (__force struct robust_list_head __user *)entry;
+ exit_robust_list(tsk, head);
+ }
+ }
+
+ kfree(rl);
+}
+
static void futex_cleanup(struct task_struct *tsk)
{
if (unlikely(tsk->futex.robust_list)) {
- exit_robust_list(tsk);
+ exit_robust_list(tsk, tsk->futex.robust_list);
tsk->futex.robust_list = NULL;
}
#ifdef CONFIG_64BIT
if (unlikely(tsk->futex.robust_list32)) {
- exit_robust_list32(tsk);
+ exit_robust_list32(tsk, tsk->futex.robust_list32);
tsk->futex.robust_list32 = NULL;
}
#endif
diff --git a/kernel/futex/futex.h b/kernel/futex/futex.h
index f00f0863ed44..7706d2b6f8a9 100644
--- a/kernel/futex/futex.h
+++ b/kernel/futex/futex.h
@@ -478,4 +478,9 @@ extern int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, i
bool futex_robust_list_clear_pending(void __user *pop, unsigned int flags);
+int futex_robust_list_create(uintptr_t head, enum robust_list2_cmd cmd);
+
+int futex_robust_list_modify(uintptr_t head, enum robust_list2_cmd cmd, unsigned
+ int index);
+
#endif /* _FUTEX_H */
diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c
index 4a45bace75fc..48e87b5e4e33 100644
--- a/kernel/futex/syscalls.c
+++ b/kernel/futex/syscalls.c
@@ -105,6 +105,61 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
return put_user(head, head_ptr);
}
+SYSCALL_DEFINE4(set_robust_list2, struct robust_list_head * __user, head, unsigned int,
+ cmd, unsigned int, index, unsigned int, flags)
+{
+ uintptr_t entry = (__force uintptr_t)head;
+ size_t align = sizeof(u32);
+ int ret;
+
+ if (flags)
+ return -EINVAL;
+
+ if (cmd >= FUTEX_ROBUST_LIST_CMD_USER_MAX)
+ return -EINVAL;
+
+ if (cmd == FUTEX_ROBUST_LIST_CMD_CREATE_64 ||
+ cmd == FUTEX_ROBUST_LIST_CMD_MODIFY_64) {
+ if (futex_in_32bit_syscall())
+ return -EOPNOTSUPP;
+ align = sizeof(u64);
+ }
+
+ switch (cmd) {
+ case FUTEX_ROBUST_LIST_CMD_CREATE_64:
+ case FUTEX_ROBUST_LIST_CMD_CREATE_32:
+ if (index)
+ return -EINVAL;
+
+ if (entry % align)
+ return -EINVAL;
+
+ /*
+ * The first two indexes are reserved for the kernel to be used
+ * with the legacy syscall, so we hide them from userspace.
+ *
+ * We map [0, FUTEX_ROBUST_LISTS_PER_USER) to
+ * [FUTEX_ROBUST_LIST2_IDX, FUTEX_ROBUST_LIST2_MAX_IDX)
+ */
+ ret = futex_robust_list_create(entry, cmd);
+
+ if (ret >= 0)
+ ret -= FUTEX_ROBUST_LIST2_IDX;
+
+ return ret;
+
+ case FUTEX_ROBUST_LIST_CMD_MODIFY_64:
+ case FUTEX_ROBUST_LIST_CMD_MODIFY_32:
+ if (entry % align)
+ return -EINVAL;
+ return futex_robust_list_modify(entry, cmd, index);
+ case FUTEX_ROBUST_LIST_CMD_LIST_LIMIT:
+ return FUTEX_ROBUST_LISTS_PER_USER;
+ }
+
+ return -EINVAL;
+}
+
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
u32 __user *uaddr2, u32 val2, u32 val3)
{
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index c8be0abaa407..0bb92b3cb589 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -172,6 +172,7 @@ COND_SYSCALL_COMPAT(fadvise64_64);
COND_SYSCALL(lsm_get_self_attr);
COND_SYSCALL(lsm_set_self_attr);
COND_SYSCALL(lsm_list_modules);
+COND_SYSCALL(set_robust_list2);
/* CONFIG_MMU only */
COND_SYSCALL(swapon);
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 05/10] futex: Create get_robust_list2() syscall
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
` (3 preceding siblings ...)
2026-11-15 17:31 ` [PATCH v8 04/10] futex: Create set_robust_list2() syscall André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 17:31 ` [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall André Almeida
` (4 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
As in the original robust list interface, to pair with
set_robust_list2(), create a get_robust_list2() syscall with the
following signature:
get_robust_list2(int pid, void __user **head_ptr, unsigned int index,
unsigned int flags)
- `pid` sets with task's list should be returned. If is 0, it gets the
list of the calling task.
- `index` is the index of the list to get
- `flags` is unused but can be used for expanding the interface
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
kernel/futex/syscalls.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++---
kernel/sys_ni.c | 1 +
2 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c
index 48e87b5e4e33..0ecb32afd5e1 100644
--- a/kernel/futex/syscalls.c
+++ b/kernel/futex/syscalls.c
@@ -44,7 +44,7 @@ static inline void __user *futex_task_robust_list(struct task_struct *p, bool co
return p->futex.robust_list;
}
-static void __user *futex_get_robust_list_common(int pid, bool compat)
+static void __user *futex_get_robust_list_common(int pid, bool compat, int index)
{
struct task_struct *p = current;
void __user *head;
@@ -71,7 +71,15 @@ static void __user *futex_get_robust_list_common(int pid, bool compat)
if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
goto err_unlock;
- head = futex_task_robust_list(p, compat);
+ if (index >= 0) {
+ scoped_guard(mutex, &p->futex.exit_mutex) {
+ uintptr_t *rl = p->futex.robust_lists;
+
+ head = rl ? (void __user *) rl[index] : NULL;
+ }
+ } else {
+ head = futex_task_robust_list(p, compat);
+ }
up_read(&p->signal->exec_update_lock);
put_task_struct(p);
@@ -95,7 +103,7 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
struct robust_list_head __user * __user *, head_ptr,
size_t __user *, len_ptr)
{
- struct robust_list_head __user *head = futex_get_robust_list_common(pid, false);
+ struct robust_list_head __user *head = futex_get_robust_list_common(pid, false, -1);
if (IS_ERR(head))
return PTR_ERR(head);
@@ -160,6 +168,56 @@ SYSCALL_DEFINE4(set_robust_list2, struct robust_list_head * __user, head, unsign
return -EINVAL;
}
+SYSCALL_DEFINE4(get_robust_list2, int, pid,
+ void __user * __user *, head_ptr,
+ unsigned int, index, unsigned int, flags)
+{
+ struct robust_list_head *head;
+ void __user *entry_ptr;
+ uintptr_t entry;
+
+ if (index >= FUTEX_ROBUST_LISTS_PER_USER)
+ return -EINVAL;
+
+ if (flags)
+ return -EINVAL;
+
+ /*
+ * The first two indexes are reserved for the kernel to be used with the
+ * legacy syscall, so we hide them from userspace.
+ *
+ * We map [0, FUTEX_ROBUST_LISTS_PER_USER) to
+ * [FUTEX_ROBUST_LIST2_IDX, FUTEX_ROBUST_LIST2_MAX_IDX)
+ */
+ index += FUTEX_ROBUST_LIST2_IDX;
+
+ entry_ptr = futex_get_robust_list_common(pid, false, index);
+ if (IS_ERR(entry_ptr))
+ return PTR_ERR(entry_ptr);
+
+ entry = (uintptr_t) entry_ptr;
+
+ if (futex_in_32bit_syscall()) {
+ u32 entry32;
+
+ if (entry && !(entry & FUTEX_ROBUST_LIST_ENTRY_32BIT))
+ return -EOPNOTSUPP;
+
+ entry32 = (u32)entry;
+ entry32 &= FUTEX_ROBUST_LIST_ENTRY_MASK;
+
+ if (copy_to_user(head_ptr, &entry32, sizeof(entry32)))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ entry &= FUTEX_ROBUST_LIST_ENTRY_MASK;
+ head = (__force struct robust_list_head __user *)entry;
+
+ return put_user(head, head_ptr);
+}
+
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
u32 __user *uaddr2, u32 val2, u32 val3)
{
@@ -548,7 +606,7 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
compat_uptr_t __user *, head_ptr,
compat_size_t __user *, len_ptr)
{
- struct robust_list_head32 __user *head = futex_get_robust_list_common(pid, true);
+ struct robust_list_head32 __user *head = futex_get_robust_list_common(pid, true, -1);
if (IS_ERR(head))
return PTR_ERR(head);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 0bb92b3cb589..d8bbcd87d535 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -173,6 +173,7 @@ COND_SYSCALL(lsm_get_self_attr);
COND_SYSCALL(lsm_set_self_attr);
COND_SYSCALL(lsm_list_modules);
COND_SYSCALL(set_robust_list2);
+COND_SYSCALL(get_robust_list2);
/* CONFIG_MMU only */
COND_SYSCALL(swapon);
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
` (4 preceding siblings ...)
2026-11-15 17:31 ` [PATCH v8 05/10] futex: Create get_robust_list2() syscall André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 20:55 ` kernel test robot
2026-11-15 21:30 ` kernel test robot
2026-11-15 17:31 ` [PATCH v8 07/10] futex: Wire up get_robust_list2 syscall André Almeida
` (3 subsequent siblings)
9 siblings, 2 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
Wire up the new set_robust_list2 syscall in all available architectures.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
arch/alpha/kernel/syscalls/syscall.tbl | 1 +
arch/arm/tools/syscall.tbl | 1 +
arch/m68k/kernel/syscalls/syscall.tbl | 1 +
arch/microblaze/kernel/syscalls/syscall.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n32.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n64.tbl | 1 +
arch/mips/kernel/syscalls/syscall_o32.tbl | 1 +
arch/parisc/kernel/syscalls/syscall.tbl | 1 +
arch/powerpc/kernel/syscalls/syscall.tbl | 1 +
arch/s390/kernel/syscalls/syscall.tbl | 1 +
arch/sh/kernel/syscalls/syscall.tbl | 1 +
arch/sparc/kernel/syscalls/syscall.tbl | 1 +
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
arch/xtensa/kernel/syscalls/syscall.tbl | 1 +
include/uapi/asm-generic/unistd.h | 5 ++++-
scripts/syscall.tbl | 1 +
17 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl
index 52e3538cc7df..cdf641845014 100644
--- a/arch/alpha/kernel/syscalls/syscall.tbl
+++ b/arch/alpha/kernel/syscalls/syscall.tbl
@@ -512,3 +512,4 @@
580 common listns sys_listns
581 common rseq_slice_yield sys_rseq_slice_yield
582 common fchroot sys_fchroot
+583 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl
index 55717ed32c27..c287461803ff 100644
--- a/arch/arm/tools/syscall.tbl
+++ b/arch/arm/tools/syscall.tbl
@@ -487,3 +487,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl
index ba7a4d8903d0..beb0ba7f350c 100644
--- a/arch/m68k/kernel/syscalls/syscall.tbl
+++ b/arch/m68k/kernel/syscalls/syscall.tbl
@@ -472,3 +472,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl
index 76d7cbe2a133..bf04133f7239 100644
--- a/arch/microblaze/kernel/syscalls/syscall.tbl
+++ b/arch/microblaze/kernel/syscalls/syscall.tbl
@@ -478,3 +478,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl
index 9ae88e4eac61..5b5b217ee7f3 100644
--- a/arch/mips/kernel/syscalls/syscall_n32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n32.tbl
@@ -411,3 +411,4 @@
470 n32 listns sys_listns
471 n32 rseq_slice_yield sys_rseq_slice_yield
472 n32 fchroot sys_fchroot
+473 n32 set_robust_list2 sys_set_robust_list2
diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl
index 83dc93a0712f..6f203cb3a558 100644
--- a/arch/mips/kernel/syscalls/syscall_n64.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n64.tbl
@@ -387,3 +387,4 @@
470 n64 listns sys_listns
471 n64 rseq_slice_yield sys_rseq_slice_yield
472 n64 fchroot sys_fchroot
+473 n64 set_robust_list2 sys_set_robust_list2
diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl
index 9c62429c9b7b..d170650521a7 100644
--- a/arch/mips/kernel/syscalls/syscall_o32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_o32.tbl
@@ -460,3 +460,4 @@
470 o32 listns sys_listns
471 o32 rseq_slice_yield sys_rseq_slice_yield
472 o32 fchroot sys_fchroot
+473 o32 set_robust_list2 sys_set_robust_list2
diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl
index 88adc4016cce..f9317ff28e37 100644
--- a/arch/parisc/kernel/syscalls/syscall.tbl
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
@@ -471,3 +471,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl
index cfbb70039ff0..acb9d446d1f6 100644
--- a/arch/powerpc/kernel/syscalls/syscall.tbl
+++ b/arch/powerpc/kernel/syscalls/syscall.tbl
@@ -563,3 +563,4 @@
470 common listns sys_listns
471 nospu rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl
index 1b45e68a217b..987e026ffbcf 100644
--- a/arch/s390/kernel/syscalls/syscall.tbl
+++ b/arch/s390/kernel/syscalls/syscall.tbl
@@ -399,3 +399,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl
index ace068dff0de..c944333c1990 100644
--- a/arch/sh/kernel/syscalls/syscall.tbl
+++ b/arch/sh/kernel/syscalls/syscall.tbl
@@ -476,3 +476,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
index 5b9fe0e8140f..3c01fa1cd885 100644
--- a/arch/sparc/kernel/syscalls/syscall.tbl
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
@@ -518,3 +518,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 2c172ef48dfd..11ebbf074920 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -478,3 +478,4 @@
470 i386 listns sys_listns
471 i386 rseq_slice_yield sys_rseq_slice_yield
472 i386 fchroot sys_fchroot
+473 i386 set_robust_list2 sys_set_robust_list2
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index d5b6045b0090..53398e8d4981 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -397,6 +397,7 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
#
# Due to a historical design error, certain syscalls are numbered differently
diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl
index d354bb231796..7ba9d6993800 100644
--- a/arch/xtensa/kernel/syscalls/syscall.tbl
+++ b/arch/xtensa/kernel/syscalls/syscall.tbl
@@ -443,3 +443,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 5b7e77a7c736..7525e0add809 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -867,8 +867,11 @@ __SYSCALL(__NR_rseq_slice_yield, sys_rseq_slice_yield)
#define __NR_fchroot 472
__SYSCALL(__NR_fchroot, sys_fchroot)
+#define __NR_set_robust_list2 473
+__SYSCALL(__NR_set_robust_list2, sys_set_robust_list2)
+
#undef __NR_syscalls
-#define __NR_syscalls 473
+#define __NR_syscalls 474
/*
* 32 bit systems traditionally used different
diff --git a/scripts/syscall.tbl b/scripts/syscall.tbl
index 0ab531605120..c8d261cb8762 100644
--- a/scripts/syscall.tbl
+++ b/scripts/syscall.tbl
@@ -413,3 +413,4 @@
470 common listns sys_listns
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
+473 common set_robust_list2 sys_set_robust_list2
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall
2026-11-15 17:31 ` [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall André Almeida
@ 2026-11-15 20:55 ` kernel test robot
2026-11-15 21:30 ` kernel test robot
1 sibling, 0 replies; 14+ messages in thread
From: kernel test robot @ 2026-11-15 20:55 UTC (permalink / raw)
To: André Almeida, Ingo Molnar, Peter Zijlstra, Darren Hart,
Davidlohr Bueso, Arnd Bergmann, Sebastian Andrzej Siewior,
Waiman Long, Ryan Houdek, Thomas Gleixner
Cc: oe-kbuild-all, linux-kernel, linux-kselftest, linux-api,
kernel-dev, André Almeida
Hi André,
kernel test robot noticed the following build errors:
[auto build test ERROR on 9f74092fda91ef93c2b07585785c1dc83cd7971f]
url: https://github.com/intel-lab-lkp/linux/commits/Andr-Almeida/futex-Skip-test_futex_robust_unlock-if-not-supported/20261115-143110
base: 9f74092fda91ef93c2b07585785c1dc83cd7971f
patch link: https://lore.kernel.org/r/20261115-tonyk-robust_futex-v8-6-a4fe47333a28%40igalia.com
patch subject: [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall
config: openrisc-allnoconfig (https://download.01.org/0day-ci/archive/20261116/202611160433.ySzwblT6-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 16.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261116/202611160433.ySzwblT6-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202611160433.ySzwblT6-lkp@intel.com/
All errors (new ones prefixed by >>):
>> ./arch/openrisc/include/generated/asm/syscall_table_32.h:474:16: error: 'sys_set_robust_list2' undeclared here (not in a function); did you mean 'sys_set_robust_list'?
474 | __SYSCALL(473, sys_set_robust_list2)
| ^~~~~~~~~~~~~~~~~~~~
arch/openrisc/kernel/sys_call_table.c:19:37: note: in definition of macro '__SYSCALL'
19 | #define __SYSCALL(nr, call) [nr] = (call),
| ^~~~
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall
2026-11-15 17:31 ` [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall André Almeida
2026-11-15 20:55 ` kernel test robot
@ 2026-11-15 21:30 ` kernel test robot
1 sibling, 0 replies; 14+ messages in thread
From: kernel test robot @ 2026-11-15 21:30 UTC (permalink / raw)
To: André Almeida, Ingo Molnar, Peter Zijlstra, Darren Hart,
Davidlohr Bueso, Arnd Bergmann, Sebastian Andrzej Siewior,
Waiman Long, Ryan Houdek, Thomas Gleixner
Cc: oe-kbuild-all, linux-kernel, linux-kselftest, linux-api,
kernel-dev, André Almeida
Hi André,
kernel test robot noticed the following build errors:
[auto build test ERROR on 9f74092fda91ef93c2b07585785c1dc83cd7971f]
url: https://github.com/intel-lab-lkp/linux/commits/Andr-Almeida/futex-Skip-test_futex_robust_unlock-if-not-supported/20261115-143110
base: 9f74092fda91ef93c2b07585785c1dc83cd7971f
patch link: https://lore.kernel.org/r/20261115-tonyk-robust_futex-v8-6-a4fe47333a28%40igalia.com
patch subject: [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall
config: xtensa-allnoconfig (https://download.01.org/0day-ci/archive/20261116/202611160554.MGBENVam-lkp@intel.com/config)
compiler: xtensa-linux-gcc (GCC) 16.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261116/202611160554.MGBENVam-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202611160554.MGBENVam-lkp@intel.com/
All errors (new ones prefixed by >>):
>> ./arch/xtensa/include/generated/asm/syscall_table.h:474:16: error: 'sys_set_robust_list2' undeclared here (not in a function); did you mean 'sys_set_robust_list'?
474 | __SYSCALL(473, sys_set_robust_list2)
| ^~~~~~~~~~~~~~~~~~~~
arch/xtensa/kernel/syscall.c:31:44: note: in definition of macro '__SYSCALL'
31 | #define __SYSCALL(nr, entry) (syscall_t)entry,
| ^~~~~
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v8 07/10] futex: Wire up get_robust_list2 syscall
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
` (5 preceding siblings ...)
2026-11-15 17:31 ` [PATCH v8 06/10] futex: Wire up set_robust_list2 syscall André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 17:31 ` [PATCH v8 08/10] selftests/futex: Expand for set_robust_list2() André Almeida
` (2 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
Wire up the new get_robust_list2 syscall in all available architectures.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
arch/alpha/kernel/syscalls/syscall.tbl | 1 +
arch/arm/tools/syscall.tbl | 1 +
arch/m68k/kernel/syscalls/syscall.tbl | 1 +
arch/microblaze/kernel/syscalls/syscall.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n32.tbl | 1 +
arch/mips/kernel/syscalls/syscall_n64.tbl | 1 +
arch/mips/kernel/syscalls/syscall_o32.tbl | 1 +
arch/parisc/kernel/syscalls/syscall.tbl | 1 +
arch/powerpc/kernel/syscalls/syscall.tbl | 1 +
arch/s390/kernel/syscalls/syscall.tbl | 1 +
arch/sh/kernel/syscalls/syscall.tbl | 1 +
arch/sparc/kernel/syscalls/syscall.tbl | 1 +
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
arch/xtensa/kernel/syscalls/syscall.tbl | 1 +
include/uapi/asm-generic/unistd.h | 4 +++-
scripts/syscall.tbl | 1 +
17 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl
index cdf641845014..e26df2cf9de7 100644
--- a/arch/alpha/kernel/syscalls/syscall.tbl
+++ b/arch/alpha/kernel/syscalls/syscall.tbl
@@ -513,3 +513,4 @@
581 common rseq_slice_yield sys_rseq_slice_yield
582 common fchroot sys_fchroot
583 common set_robust_list2 sys_set_robust_list2
+584 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl
index c287461803ff..0268a887f90d 100644
--- a/arch/arm/tools/syscall.tbl
+++ b/arch/arm/tools/syscall.tbl
@@ -488,3 +488,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl
index beb0ba7f350c..91cc1ea407ec 100644
--- a/arch/m68k/kernel/syscalls/syscall.tbl
+++ b/arch/m68k/kernel/syscalls/syscall.tbl
@@ -473,3 +473,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl
index bf04133f7239..18a59b24724c 100644
--- a/arch/microblaze/kernel/syscalls/syscall.tbl
+++ b/arch/microblaze/kernel/syscalls/syscall.tbl
@@ -479,3 +479,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl
index 5b5b217ee7f3..f498b01178e4 100644
--- a/arch/mips/kernel/syscalls/syscall_n32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n32.tbl
@@ -412,3 +412,4 @@
471 n32 rseq_slice_yield sys_rseq_slice_yield
472 n32 fchroot sys_fchroot
473 n32 set_robust_list2 sys_set_robust_list2
+474 n32 get_robust_list2 sys_get_robust_list2
diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl
index 6f203cb3a558..b12328d537e3 100644
--- a/arch/mips/kernel/syscalls/syscall_n64.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n64.tbl
@@ -388,3 +388,4 @@
471 n64 rseq_slice_yield sys_rseq_slice_yield
472 n64 fchroot sys_fchroot
473 n64 set_robust_list2 sys_set_robust_list2
+474 n64 get_robust_list2 sys_get_robust_list2
diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl
index d170650521a7..3c8e3890644f 100644
--- a/arch/mips/kernel/syscalls/syscall_o32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_o32.tbl
@@ -461,3 +461,4 @@
471 o32 rseq_slice_yield sys_rseq_slice_yield
472 o32 fchroot sys_fchroot
473 o32 set_robust_list2 sys_set_robust_list2
+474 o32 get_robust_list2 sys_get_robust_list2
diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl
index f9317ff28e37..f746f152cd51 100644
--- a/arch/parisc/kernel/syscalls/syscall.tbl
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
@@ -472,3 +472,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl
index acb9d446d1f6..b785d6861963 100644
--- a/arch/powerpc/kernel/syscalls/syscall.tbl
+++ b/arch/powerpc/kernel/syscalls/syscall.tbl
@@ -564,3 +564,4 @@
471 nospu rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl
index 987e026ffbcf..eb0c5bf1d71f 100644
--- a/arch/s390/kernel/syscalls/syscall.tbl
+++ b/arch/s390/kernel/syscalls/syscall.tbl
@@ -400,3 +400,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl
index c944333c1990..520ec9072ce3 100644
--- a/arch/sh/kernel/syscalls/syscall.tbl
+++ b/arch/sh/kernel/syscalls/syscall.tbl
@@ -477,3 +477,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
index 3c01fa1cd885..8d332ffde99f 100644
--- a/arch/sparc/kernel/syscalls/syscall.tbl
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
@@ -519,3 +519,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 11ebbf074920..be72e54ce2fd 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -479,3 +479,4 @@
471 i386 rseq_slice_yield sys_rseq_slice_yield
472 i386 fchroot sys_fchroot
473 i386 set_robust_list2 sys_set_robust_list2
+474 i386 get_robust_list2 sys_get_robust_list2
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 53398e8d4981..d5f91d276e75 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -398,6 +398,7 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
#
# Due to a historical design error, certain syscalls are numbered differently
diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl
index 7ba9d6993800..4908baf60363 100644
--- a/arch/xtensa/kernel/syscalls/syscall.tbl
+++ b/arch/xtensa/kernel/syscalls/syscall.tbl
@@ -444,3 +444,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 7525e0add809..3d84f306e677 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -869,9 +869,11 @@ __SYSCALL(__NR_fchroot, sys_fchroot)
#define __NR_set_robust_list2 473
__SYSCALL(__NR_set_robust_list2, sys_set_robust_list2)
+#define __NR_get_robust_list2 474
+__SYSCALL(__NR_get_robust_list2, sys_get_robust_list2)
#undef __NR_syscalls
-#define __NR_syscalls 474
+#define __NR_syscalls 475
/*
* 32 bit systems traditionally used different
diff --git a/scripts/syscall.tbl b/scripts/syscall.tbl
index c8d261cb8762..b4fb5e1a2141 100644
--- a/scripts/syscall.tbl
+++ b/scripts/syscall.tbl
@@ -414,3 +414,4 @@
471 common rseq_slice_yield sys_rseq_slice_yield
472 common fchroot sys_fchroot
473 common set_robust_list2 sys_set_robust_list2
+474 common get_robust_list2 sys_get_robust_list2
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 08/10] selftests/futex: Expand for set_robust_list2()
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
` (6 preceding siblings ...)
2026-11-15 17:31 ` [PATCH v8 07/10] futex: Wire up get_robust_list2 syscall André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 17:31 ` [PATCH v8 09/10] selftests/futex: Expand for get_robust_list2() André Almeida
2026-11-15 17:31 ` [PATCH v8 10/10] futex: Use new robust list API internally André Almeida
9 siblings, 0 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
Reuse the same selftest for the original set_robust_list() syscall for
the new set_robust_list2() syscall. Use kselftest variants feature to
run the relevant tests for both interfaces. Create new test cases for
checking invalid parameters, the ability to correctly set multiple lists
for the same task, and to use 32-bit lists in a 64-bit task.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
.../selftests/futex/functional/robust_list.c | 465 +++++++++++++++++++--
1 file changed, 431 insertions(+), 34 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
index ddb610149857..7666b9a64501 100644
--- a/tools/testing/selftests/futex/functional/robust_list.c
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -49,6 +49,35 @@
# define BUILD_64
#endif
+#ifndef SYS_set_robust_list2
+# define SYS_set_robust_list2 473
+
+enum robust_list_cmd {
+ FUTEX_ROBUST_LIST_CMD_CREATE_64,
+ FUTEX_ROBUST_LIST_CMD_CREATE_32,
+ FUTEX_ROBUST_LIST_CMD_MODIFY_64,
+ FUTEX_ROBUST_LIST_CMD_MODIFY_32,
+ FUTEX_ROBUST_LIST_CMD_LIST_LIMIT,
+ FUTEX_ROBUST_LIST_CMD_USER_MAX,
+
+ /*
+ * Kernel internal, rejected for user space
+ */
+ FUTEX_ROBUST_LIST_SET_NATIVE = 128,
+ FUTEX_ROBUST_LIST_SET_COMPAT,
+};
+
+struct robust_list32 {
+ uint32_t next;
+};
+
+struct robust_list_head32 {
+ struct robust_list32 list;
+ int32_t futex_offset;
+ uint32_t list_op_pending;
+};
+#endif
+
static pthread_barrier_t barrier, barrier2;
static int set_robust_list(struct robust_list_head *head, size_t len)
@@ -67,6 +96,65 @@ static int sys_futex_robust_unlock(_Atomic(uint32_t) *uaddr, unsigned int op, in
return syscall(SYS_futex, uaddr, op, val, NULL, list_op_pending, val3, 0);
}
+static int set_robust_list2(struct robust_list_head *head, enum robust_list_cmd cmd,
+ unsigned int index, unsigned int flags)
+{
+ return syscall(SYS_set_robust_list2, head, cmd, index, flags, 0, 0);
+}
+
+static bool robust_list2_support(void)
+{
+ int ret = set_robust_list2(NULL, FUTEX_ROBUST_LIST_CMD_LIST_LIMIT, 0, 0);
+
+ if (ret == -1 && errno == ENOSYS)
+ return false;
+
+ return true;
+}
+
+/*
+ * Return the set command according to the app bitness
+ */
+static int get_cmd_create(void)
+{
+ return sizeof(uintptr_t) == 8 ? FUTEX_ROBUST_LIST_CMD_CREATE_64 :
+ FUTEX_ROBUST_LIST_CMD_CREATE_32;
+}
+
+static int get_cmd_modify(void)
+{
+ return sizeof(uintptr_t) == 8 ? FUTEX_ROBUST_LIST_CMD_MODIFY_64 :
+ FUTEX_ROBUST_LIST_CMD_MODIFY_32;
+}
+
+FIXTURE(robust_api) {};
+
+FIXTURE_VARIANT(robust_api)
+{
+ bool robust2;
+};
+
+FIXTURE_SETUP(robust_api)
+{
+ if (!variant->robust2)
+ return;
+
+ if (!robust_list2_support())
+ SKIP(return, "robust_list2 not supported");
+}
+
+FIXTURE_TEARDOWN(robust_api) {}
+
+FIXTURE_VARIANT_ADD(robust_api, robust1)
+{
+ .robust2 = false,
+};
+
+FIXTURE_VARIANT_ADD(robust_api, robust2)
+{
+ .robust2 = true,
+};
+
/*
* Basic lock struct, contains just the futex word and the robust list element
* Real implementations have also a *prev to easily walk in the list
@@ -76,6 +164,12 @@ typedef _Atomic(unsigned int) atomic_futex_t;
struct lock_struct {
atomic_futex_t futex;
struct robust_list list;
+ bool robust2;
+};
+
+struct lock_struct32 {
+ _Atomic(uint32_t) futex;
+ struct robust_list32 list;
};
struct child_args {
@@ -118,20 +212,32 @@ static int create_child(struct __test_metadata *_metadata, int (*fn)(void *arg),
/*
* Helper function to prepare and register a robust list
*/
-static int set_list(struct robust_list_head *head)
+static int set_list(struct robust_list_head *head, bool robust2, int *index)
{
int ret;
- ret = set_robust_list(head, sizeof(*head));
- if (ret)
- return ret;
-
head->futex_offset = (size_t) offsetof(struct lock_struct, futex) -
(size_t) offsetof(struct lock_struct, list);
head->list.next = &head->list;
head->list_op_pending = NULL;
- return 0;
+ if (!robust2)
+ return set_robust_list(head, sizeof(*head));
+
+ ret = set_robust_list2(head, get_cmd_create(), 0, 0);
+
+ if (ret >= 0 && index)
+ *index = ret;
+
+ return ret;
+}
+
+/*
+ * Change a given list index to a different head
+ */
+static int modify_list(struct robust_list_head *head, int index)
+{
+ return set_robust_list2(head, get_cmd_modify(), index, 0);
}
/*
@@ -203,12 +309,12 @@ static int child_fn_lock(void *arg)
struct __test_metadata *_metadata = cargs->_metadata;
struct lock_struct *lock = cargs->arg;
struct robust_list_head head;
- int ret;
+ int ret, index;
free(cargs);
- ret = set_list(&head);
- ASSERT_EQ(ret, 0)
+ ret = set_list(&head, lock->robust2, &index);
+ ASSERT_NE(ret, -1)
TH_LOG("set_robust_list error");
ret = mutex_lock(lock, &head, false);
@@ -233,15 +339,17 @@ static int child_fn_lock(void *arg)
* in the robust list and die. The parent thread will wait on this futex, and
* should be waken up when the child exits.
*/
-TEST(test_robustness)
+TEST_F(robust_api, test_robustness)
{
struct lock_struct lock = { .futex = 0 };
atomic_futex_t *futex = &lock.futex;
struct robust_list_head head;
- int ret, pid, wstatus;
+ int ret, pid, wstatus, index;
- ret = set_list(&head);
- ASSERT_EQ(ret, 0);
+ lock.robust2 = variant->robust2;
+
+ ret = set_list(&head, lock.robust2, &index);
+ ASSERT_NE(ret, -1);
/*
* Lets use a barrier to ensure that the child thread takes the lock
@@ -281,7 +389,7 @@ TEST(test_set_robust_list_invalid_size)
int ret;
ret = set_robust_list(&head, head_size);
- ASSERT_EQ(ret, 0);
+ ASSERT_GE(ret, 0);
ret = set_robust_list(&head, head_size * 2);
ASSERT_EQ(ret, -1);
@@ -296,6 +404,53 @@ TEST(test_set_robust_list_invalid_size)
ASSERT_EQ(errno, EINVAL);
}
+/*
+ * Test invalid parameters
+ */
+TEST(test_set_robust_list2_inval)
+{
+ struct robust_list_head head;
+ int i, ret, index, list_limit;
+
+ if (!robust_list2_support())
+ SKIP(return, "robust_list2 not supported\n");
+
+ /* Bad flag */
+ ret = set_robust_list2(&head, get_cmd_create(), 0, 999);
+ ASSERT_EQ(ret, -1);
+ ASSERT_EQ(errno, EINVAL);
+
+ /* List out of range */
+ list_limit = set_robust_list2(NULL, FUTEX_ROBUST_LIST_CMD_LIST_LIMIT, 0, 0);
+ ASSERT_GT(list_limit, 1);
+
+ for (i = 0; i < list_limit; i++) {
+ ret = set_list(&head, true, &index);
+ ASSERT_EQ(ret, i);
+ }
+
+ ret = set_list(&head, true, &index);
+ ASSERT_EQ(ret, -1);
+ ASSERT_EQ(errno, ENOSPC);
+
+ /* clear the list */
+ for (i = 0; i < list_limit; i++)
+ modify_list(NULL, i);
+
+#ifdef BUILD_64
+ /* Create a 64-bit entry, and try to set it as 32-bit */
+ ret = set_robust_list2(&head, FUTEX_ROBUST_LIST_CMD_CREATE_64, 0, 0);
+ ASSERT_GE(ret, 0);
+
+ ret = set_robust_list2(&head, FUTEX_ROBUST_LIST_CMD_MODIFY_64, 0, 0);
+ ASSERT_GE(ret, 0);
+
+ ret = set_robust_list2(&head, FUTEX_ROBUST_LIST_CMD_MODIFY_32, 0, 0);
+ ASSERT_NE(ret, 0);
+#endif
+
+}
+
/*
* Test get_robust_list with pid = 0, getting the list of the running thread
*/
@@ -388,12 +543,12 @@ static int child_fn_lock_with_error(void *arg)
struct __test_metadata *_metadata = cargs->_metadata;
struct lock_struct *lock = cargs->arg;
struct robust_list_head head;
- int ret;
+ int ret, index;
free(cargs);
- ret = set_list(&head);
- ASSERT_EQ(ret, 0)
+ ret = set_list(&head, lock->robust2, &index);
+ ASSERT_NE(ret, -1)
TH_LOG("set_robust_list error");
ret = mutex_lock(lock, &head, true);
@@ -413,15 +568,17 @@ static int child_fn_lock_with_error(void *arg)
* earlier, just after setting list_op_pending and taking the lock, to test the
* list_op_pending mechanism
*/
-TEST(test_set_list_op_pending)
+TEST_F(robust_api, test_set_list_op_pending)
{
struct lock_struct lock = { .futex = 0 };
atomic_futex_t *futex = &lock.futex;
struct robust_list_head head;
- int ret, wstatus;
+ int ret, wstatus, index;
- ret = set_list(&head);
- ASSERT_EQ(ret, 0);
+ lock.robust2 = variant->robust2;
+
+ ret = set_list(&head, lock.robust2, &index);
+ ASSERT_NE(ret, -1);
ret = pthread_barrier_init(&barrier, NULL, 2);
ASSERT_EQ(ret, 0);
@@ -450,11 +607,11 @@ static int child_lock_holder(void *arg)
struct child_args *cargs = arg;
struct lock_struct *locks = cargs->arg;
struct robust_list_head head;
- int i;
+ int i, index;
free(cargs);
- set_list(&head);
+ set_list(&head, locks[0].robust2, &index);
for (i = 0; i < CHILD_NR; i++) {
locks[i].futex = 0;
@@ -495,17 +652,23 @@ static int child_wait_lock(void *arg)
* Test a robust list of more than one element. All the waiters should wake when
* the holder dies
*/
-TEST(test_robust_list_multiple_elements)
+TEST_F(robust_api, test_robust_list_multiple_elements)
{
struct lock_struct locks[CHILD_NR];
pid_t pids[CHILD_NR + 1];
int i, ret, wstatus;
+ if (variant->robust2 && !robust_list2_support())
+ SKIP(return, "robust_list2 not supported\n");
+
+ locks[0].robust2 = variant->robust2;
+
ret = pthread_barrier_init(&barrier, NULL, 2);
ASSERT_EQ(ret, 0);
ret = pthread_barrier_init(&barrier2, NULL, CHILD_NR + 1);
ASSERT_EQ(ret, 0);
+
pids[0] = create_child(_metadata, &child_lock_holder, &locks);
ASSERT_NE(pids[0], -1);
@@ -532,18 +695,112 @@ TEST(test_robust_list_multiple_elements)
TH_LOG("One or more children failed");
}
+static int child_lock_holder_multiple_lists(void *arg)
+{
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct *locks = cargs->arg;
+ struct robust_list_head *heads;
+ int i, list_limit, index, ret;
+
+ free(cargs);
+
+ list_limit = set_robust_list2(NULL, FUTEX_ROBUST_LIST_CMD_LIST_LIMIT, 0, 0);
+ ASSERT_GT(list_limit, 1);
+
+ heads = malloc(list_limit * sizeof(*heads));
+ ASSERT_TRUE((uintptr_t) heads);
+
+ /*
+ * Try to clear any exiting list, ignore errors if they didn't exit
+ */
+ for (i = 0; i < list_limit; i++)
+ modify_list(NULL, i);
+
+ /*
+ * Given that this thread has no robust list attached yet, it should
+ * get as return all available lists in order [0, list_limit)
+ */
+ for (i = 0; i < list_limit; i++) {
+ ret = set_list(&heads[i], true, &index);
+ ASSERT_EQ(ret, i);
+ locks[i].futex = 0;
+ mutex_lock(&locks[i], &heads[i], false);
+ }
+
+ pthread_barrier_wait(&barrier);
+ pthread_barrier_wait(&barrier2);
+
+ /* See comment at child_fn_lock() */
+ usleep(SLEEP_US * 10);
+
+ return 0;
+}
+
+/*
+ * Similar to test_robust_list_multiple_elements, but instead of one list with
+ * several elements, create several lists with one element.
+ */
+TEST(test_robust_list_multiple_lists)
+{
+ int i, ret, wstatus, list_limit;
+ struct lock_struct *locks;
+ pid_t *pids;
+
+ if (!robust_list2_support())
+ SKIP(return, "robust_list2 not supported\n");
+
+ list_limit = set_robust_list2(NULL, FUTEX_ROBUST_LIST_CMD_LIST_LIMIT, 0, 0);
+ ASSERT_GT(list_limit, 1);
+
+ locks = malloc(list_limit * sizeof(*locks));
+ ASSERT_NE(locks, NULL);
+
+ pids = malloc(list_limit * sizeof(*pids));
+ ASSERT_NE(pids, NULL);
+
+ ret = pthread_barrier_init(&barrier, NULL, 2);
+ ASSERT_EQ(ret, 0);
+ ret = pthread_barrier_init(&barrier2, NULL, list_limit + 1);
+ ASSERT_EQ(ret, 0);
+
+ pids[0] = create_child(_metadata, &child_lock_holder_multiple_lists, locks);
+
+ /* Wait until the locker thread takes the look */
+ pthread_barrier_wait(&barrier);
+
+ for (i = 0; i < list_limit; i++)
+ pids[i+1] = create_child(_metadata, &child_wait_lock, &locks[i]);
+
+ /* Wait for all children to return */
+ ret = 0;
+
+ for (i = 0; i < list_limit; i++) {
+ waitpid(pids[i], &wstatus, 0);
+ if (WEXITSTATUS(wstatus))
+ ret = -1;
+ }
+
+ pthread_barrier_destroy(&barrier);
+ pthread_barrier_destroy(&barrier2);
+
+ free(locks);
+ free(pids);
+}
+
static int child_circular_list(void *arg)
{
struct child_args *cargs = arg;
+ bool robust2 = cargs->arg;
struct __test_metadata *_metadata = cargs->_metadata;
static struct lock_struct a, b, c;
struct robust_list_head head;
- int ret;
+ int ret, index;
free(cargs);
- ret = set_list(&head);
- ASSERT_EQ(ret, 0)
+ ret = set_list(&head, robust2, &index);
+ ASSERT_NE(ret, -1)
TH_LOG("set_list error");
head.list.next = &a.list;
@@ -563,11 +820,13 @@ static int child_circular_list(void *arg)
* while processing it so it won't be trapped in an infinite loop while handling
* a process exit
*/
-TEST(test_circular_list)
+TEST_F(robust_api, test_circular_list)
{
+ bool robust2 = variant->robust2;
int wstatus;
pid_t pid;
+ create_child(_metadata, child_circular_list, (void *) robust2);
pid = create_child(_metadata, child_circular_list, NULL);
ASSERT_NE(pid, -1);
@@ -660,8 +919,8 @@ TEST_F(vdso_unlock, test_robust_try_unlock_uncontended)
*futex = tid;
- ret = set_list(&head);
- if (ret)
+ ret = set_list(&head, false, NULL);
+ if (ret == -1)
ksft_test_result_fail("set_robust_list error\n");
head.list_op_pending = &lock.list;
@@ -700,8 +959,8 @@ TEST_F(vdso_unlock, test_robust_try_unlock_contended)
*futex = tid | FUTEX_WAITERS;
- ret = set_list(&head);
- if (ret)
+ ret = set_list(&head, false, NULL);
+ if (ret == -1)
ksft_test_result_fail("set_robust_list error\n");
head.list_op_pending = &lock.list;
@@ -783,8 +1042,8 @@ TEST_F(futex_op, test_futex_robust_unlock)
*futex = tid | FUTEX_WAITERS;
- ret = set_list(&head);
- if (ret)
+ ret = set_list(&head, false, 0);
+ if (ret == -1)
ksft_test_result_fail("set_robust_list error\n");
head.list_op_pending = &lock.list;
@@ -806,4 +1065,142 @@ TEST_F(futex_op, test_futex_robust_unlock)
ASSERT_EQ((uintptr_t)(unsigned long)head.list_op_pending, exp);
}
+/*
+ * 32-bit version of child_lock_holder.
+ */
+static int child_lock_holder32(void *arg)
+{
+ struct child_args *cargs = arg;
+ struct lock_struct32 *locks = cargs->arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct robust_list_head32 *head;
+ pid_t tid = gettid();
+ int i, ret;
+
+ head = mmap((void *)0x10000, sizeof(*head), PROT_READ | PROT_WRITE,
+ MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+ ASSERT_TRUE((uintptr_t) head);
+ ASSERT_LT(((uint32_t)(uintptr_t) head), 0x7FFFFFFF);
+
+ head->futex_offset = (uint32_t) ((size_t) offsetof(struct lock_struct32, futex) -
+ (size_t) offsetof(struct lock_struct32, list));
+ head->list.next = (uint32_t)(uintptr_t) &head->list;
+ head->list_op_pending = (uint32_t)(uintptr_t) NULL;
+
+ ret = set_robust_list2((struct robust_list_head *) head,
+ FUTEX_ROBUST_LIST_CMD_CREATE_32, 0, 0);
+ ASSERT_GE(ret, 0);
+
+ /*
+ * Take all the locks and insert them in the list
+ */
+ for (i = 0; i < CHILD_NR; i++) {
+ struct robust_list32 *list = &head->list;
+
+ locks[i].futex = tid;
+
+ while (list->next != (uint32_t)(uintptr_t) &head->list)
+ list = (struct robust_list32 *)(uintptr_t) list->next;
+
+ list->next = (uint32_t)(uintptr_t) &locks[i].list;
+ locks[i].list.next = (uint32_t)(uintptr_t) &head->list;
+ }
+
+ pthread_barrier_wait(&barrier);
+ pthread_barrier_wait(&barrier2);
+
+ /* See comment at child_fn_lock() */
+ usleep(SLEEP_US);
+
+ /* Exit holding all the locks */
+ return 0;
+}
+
+static int child_wait_lock32(void *arg)
+{
+ struct child_args *cargs = arg;
+ struct __test_metadata *_metadata = cargs->_metadata;
+ struct lock_struct32 *lock = cargs->arg;
+ atomic_futex_t *futex;
+ struct timespec to;
+ pid_t tid;
+ int ret;
+
+ futex = &lock->futex;
+
+ pthread_barrier_wait(&barrier2);
+
+ to.tv_sec = FUTEX_TIMEOUT;
+ to.tv_nsec = 0;
+
+ tid = atomic_load(futex);
+
+ /* Kernel ignores futexes without the waiters flag */
+ tid |= FUTEX_WAITERS;
+ atomic_store(futex, tid);
+
+ ret = futex_wait((futex_t *) futex, tid, &to, 0);
+
+ ASSERT_EQ(ret, 0);
+ ASSERT_TRUE(lock->futex & FUTEX_OWNER_DIED);
+
+ return 0;
+}
+
+/*
+ * Test to create a 32-bit robust list in a 64-bit kernel. Replicate
+ * test_robust_list_multiple_elements, but it's simplified: don't do all the
+ * mutex lock dance, just insert futexes in the list and check if the kernel
+ * correctly walks the list and wake the threads
+ */
+TEST(test_32bit_lists)
+{
+ struct lock_struct32 *locks;
+ pid_t pids[CHILD_NR + 1];
+ int i, ret, wstatus;
+
+#ifndef BUILD_64
+ SKIP(return, "Test only for 64-bit\n");
+#endif
+
+ if (!robust_list2_support())
+ SKIP(return, "robust_list2 not supported\n");
+
+ locks = mmap((void *)0x20000, sizeof(*locks) * CHILD_NR,
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0);
+
+ ASSERT_NE(locks, NULL);
+ ASSERT_LT((uintptr_t) locks, 0x7FFFFFFF);
+
+ ret = pthread_barrier_init(&barrier, NULL, 2);
+ ASSERT_EQ(ret, 0);
+ ret = pthread_barrier_init(&barrier2, NULL, CHILD_NR + 1);
+ ASSERT_EQ(ret, 0);
+
+ pids[0] = create_child(_metadata, &child_lock_holder32, locks);
+
+ /* Wait until the locker thread takes the look */
+ pthread_barrier_wait(&barrier);
+
+ for (i = 0; i < CHILD_NR; i++)
+ pids[i+1] = create_child(_metadata, &child_wait_lock32, &locks[i]);
+
+ /* Wait for all children to return */
+ ret = 0;
+
+ for (i = 0; i < CHILD_NR; i++) {
+ waitpid(pids[i], &wstatus, 0);
+ if (WEXITSTATUS(wstatus))
+ ret = -1;
+ }
+
+ pthread_barrier_destroy(&barrier);
+ pthread_barrier_destroy(&barrier2);
+
+ munmap(locks, sizeof(*locks) * CHILD_NR);
+}
+
TEST_HARNESS_MAIN
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 09/10] selftests/futex: Expand for get_robust_list2()
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
` (7 preceding siblings ...)
2026-11-15 17:31 ` [PATCH v8 08/10] selftests/futex: Expand for set_robust_list2() André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 17:31 ` [PATCH v8 10/10] futex: Use new robust list API internally André Almeida
9 siblings, 0 replies; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
Reuse the same selftest for the original set_robust_list() syscall for
the new set_robust_list2() syscall. Use kselftest variants feature to
run the relevant tests for both interfaces. Create a new test case to
get different lists from the same task.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
.../selftests/futex/functional/robust_list.c | 164 ++++++++++++++++++---
1 file changed, 143 insertions(+), 21 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/robust_list.c b/tools/testing/selftests/futex/functional/robust_list.c
index 7666b9a64501..3d97b948bc0a 100644
--- a/tools/testing/selftests/futex/functional/robust_list.c
+++ b/tools/testing/selftests/futex/functional/robust_list.c
@@ -51,6 +51,7 @@
#ifndef SYS_set_robust_list2
# define SYS_set_robust_list2 473
+# define SYS_get_robust_list2 474
enum robust_list_cmd {
FUTEX_ROBUST_LIST_CMD_CREATE_64,
@@ -102,6 +103,12 @@ static int set_robust_list2(struct robust_list_head *head, enum robust_list_cmd
return syscall(SYS_set_robust_list2, head, cmd, index, flags, 0, 0);
}
+static int get_robust_list2(int pid, struct robust_list_head **head,
+ unsigned int index, unsigned int flags)
+{
+ return syscall(SYS_get_robust_list2, pid, head, index, flags);
+}
+
static bool robust_list2_support(void)
{
int ret = set_robust_list2(NULL, FUTEX_ROBUST_LIST_CMD_LIST_LIMIT, 0, 0);
@@ -240,6 +247,23 @@ static int modify_list(struct robust_list_head *head, int index)
return set_robust_list2(head, get_cmd_modify(), index, 0);
}
+static int get_list(pid_t pid, struct robust_list_head **head, bool robust2, int index)
+{
+ int ret;
+
+ if (!robust2) {
+ size_t len_ptr;
+
+ ret = get_robust_list(pid, head, &len_ptr);
+ if (sizeof(**head) != len_ptr)
+ return -EINVAL;
+
+ return ret;
+ }
+
+ return get_robust_list2(pid, head, index, 0);
+}
+
/*
* A basic (and incomplete) mutex lock function with robustness
*/
@@ -454,40 +478,45 @@ TEST(test_set_robust_list2_inval)
/*
* Test get_robust_list with pid = 0, getting the list of the running thread
*/
-TEST(test_get_robust_list_self)
+TEST_F(robust_api, test_get_robust_list_self)
{
struct robust_list_head head, head2, *get_head;
- size_t head_size = sizeof(head), len_ptr;
- int ret;
+ bool robust2 = variant->robust2;
+ int ret, index = 0;
- ret = set_robust_list(&head, head_size);
- ASSERT_EQ(ret, 0);
+ ret = set_list(&head, robust2, 0);
+ ASSERT_GE(ret, 0);
- ret = get_robust_list(0, &get_head, &len_ptr);
+ ret = get_list(0, &get_head, robust2, 0);
ASSERT_EQ(ret, 0);
ASSERT_EQ(get_head, &head);
- ASSERT_EQ(head_size, len_ptr);
- ret = set_robust_list(&head2, head_size);
- ASSERT_EQ(ret, 0);
+ ret = set_list(&head2, robust2, &index);
+ ASSERT_GE(ret, 0);
- ret = get_robust_list(0, &get_head, &len_ptr);
+ ret = get_list(0, &get_head, robust2, index);
ASSERT_EQ(ret, 0);
ASSERT_EQ(get_head, &head2);
- ASSERT_EQ(head_size, len_ptr);
}
+struct child_arg_struct {
+ struct robust_list_head *head;
+ bool robust2;
+};
+
static int child_list(void *arg)
{
struct child_args *cargs = arg;
struct __test_metadata *_metadata = cargs->_metadata;
- struct robust_list_head *head = cargs->arg;
+ struct child_arg_struct *child_arg = (struct child_arg_struct *) cargs->arg;
+ struct robust_list_head *head = child_arg->head;
+ bool robust2 = child_arg->robust2;
int ret;
free(cargs);
- ret = set_robust_list(head, sizeof(*head));
- ASSERT_EQ(ret, 0)
+ ret = set_list(head, robust2, 0);
+ ASSERT_GE(ret, 0)
TH_LOG("set_robust_list error");
/*
@@ -507,23 +536,26 @@ static int child_list(void *arg)
* parent
* 2) the child thread still alive when we try to get the list from it
*/
-TEST(test_get_robust_list_child)
+TEST_F(robust_api, test_get_robust_list_child)
{
struct robust_list_head head, *get_head;
+ bool robust2 = variant->robust2;
+ struct child_arg_struct child =
+ {.robust2 = robust2, .head = &head};
int ret, wstatus;
- size_t len_ptr;
pid_t tid;
+
ret = pthread_barrier_init(&barrier, NULL, 2);
ret = pthread_barrier_init(&barrier2, NULL, 2);
ASSERT_EQ(ret, 0);
- tid = create_child(_metadata, &child_list, &head);
+ tid = create_child(_metadata, &child_list, &child);
ASSERT_NE(tid, -1);
pthread_barrier_wait(&barrier);
- ret = get_robust_list(tid, &get_head, &len_ptr);
+ ret = get_list(tid, &get_head, robust2, 0);
ASSERT_EQ(ret, 0);
ASSERT_EQ(&head, get_head);
@@ -1073,9 +1105,9 @@ static int child_lock_holder32(void *arg)
struct child_args *cargs = arg;
struct lock_struct32 *locks = cargs->arg;
struct __test_metadata *_metadata = cargs->_metadata;
- struct robust_list_head32 *head;
+ struct robust_list_head32 *head, *head_ptr;
pid_t tid = gettid();
- int i, ret;
+ int i, ret, index;
head = mmap((void *)0x10000, sizeof(*head), PROT_READ | PROT_WRITE,
MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -1088,9 +1120,20 @@ static int child_lock_holder32(void *arg)
head->list.next = (uint32_t)(uintptr_t) &head->list;
head->list_op_pending = (uint32_t)(uintptr_t) NULL;
- ret = set_robust_list2((struct robust_list_head *) head,
+ index = set_robust_list2((struct robust_list_head *)head,
FUTEX_ROBUST_LIST_CMD_CREATE_32, 0, 0);
+ ASSERT_GE(index, 0);
+
+ /* Test get list */
+ ret = get_robust_list2(0, (struct robust_list_head **)&head_ptr, index, 0);
ASSERT_GE(ret, 0);
+ ASSERT_EQ(head, head_ptr);
+
+ /* Test trying to set a 64 bit list in the same index */
+ ret = set_robust_list2((struct robust_list_head *)head,
+ FUTEX_ROBUST_LIST_CMD_MODIFY_64, 0, 0);
+ ASSERT_EQ(ret, -1);
+ ASSERT_TRUE(errno & (EOPNOTSUPP | EINVAL));
/*
* Take all the locks and insert them in the list
@@ -1203,4 +1246,83 @@ TEST(test_32bit_lists)
munmap(locks, sizeof(*locks) * CHILD_NR);
}
+/*
+ * Test setting and getting mutiple head lists
+ */
+TEST(set_and_get_robust2)
+{
+ struct robust_list_head *head = NULL, *heads;
+ int list_limit, ret, *index, i, j;
+
+ if (!robust_list2_support()) {
+ SKIP(return, "robust_list2 not supported\n");
+ return;
+ }
+
+ list_limit = set_robust_list2(NULL, FUTEX_ROBUST_LIST_CMD_LIST_LIMIT, 0, 0);
+ ASSERT_GT(list_limit, 1);
+
+ heads = malloc(list_limit * sizeof(*heads));
+ ASSERT_NE(heads, NULL);
+
+ index = malloc(list_limit * sizeof(*index));
+ ASSERT_NE(index, NULL);
+
+ /*
+ * Insert various elements into the lists
+ */
+ for (i = 0; i < list_limit; i++) {
+ ret = set_list(&heads[i], true, &index[i]);
+ ASSERT_GE(ret, 0);
+ ASSERT_EQ(i, index[i]);
+ }
+
+ for (i = 0; i < list_limit; i++) {
+ ret = get_list(0, &head, true, index[i]);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(head, &heads[i]);
+ }
+
+ /*
+ * Modify the list, adding the elements in the other ordering
+ */
+ for (i = 0, j = list_limit; i < list_limit; i++, j--) {
+ ret = modify_list(&heads[j], index[i]);
+ ASSERT_GE(ret, 0);
+ }
+
+ for (i = 0, j = list_limit; i < list_limit; i++, j--) {
+ ret = get_list(0, &head, true, index[i]);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(head, &heads[j]);
+ }
+
+ /*
+ * Delete all elements
+ */
+ for (i = 0; i < list_limit; i++) {
+ ret = modify_list(NULL, index[i]);
+ ASSERT_EQ(ret, 0);
+ }
+
+ for (i = 0; i < list_limit; i++) {
+ ret = get_list(0, &head, true, index[i]);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(head, NULL);
+ }
+
+ /*
+ * Recreate the list. It should support the same number of elements as
+ * before, given that we just cleared the list.
+ */
+ for (i = 0; i < list_limit; i++) {
+ ret = set_list(&heads[i], true, &index[i]);
+ ASSERT_GE(ret, 0);
+ ASSERT_EQ(i, index[i]);
+ }
+
+ free(heads);
+ free(index);
+}
+
TEST_HARNESS_MAIN
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 10/10] futex: Use new robust list API internally
2026-11-15 17:31 [PATCH v8 00/10] futex: Create {set,get}_robust_list2() syscalls André Almeida
` (8 preceding siblings ...)
2026-11-15 17:31 ` [PATCH v8 09/10] selftests/futex: Expand for get_robust_list2() André Almeida
@ 2026-11-15 17:31 ` André Almeida
2026-11-15 20:44 ` kernel test robot
9 siblings, 1 reply; 14+ messages in thread
From: André Almeida @ 2026-11-15 17:31 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Darren Hart, Davidlohr Bueso,
Arnd Bergmann, Sebastian Andrzej Siewior, Waiman Long,
Ryan Houdek, Thomas Gleixner
Cc: linux-kernel, linux-kselftest, linux-api, kernel-dev, André Almeida
The new robust list API internals can handle any kind of robust list, so
to simplify the code, reuse the same mechanisms for the original API and
when calling the original set syscall, set the head in the array of
lists. The first two indexes of the array of robust lists are reserved
for the original API lists, the native robust list and the compat robust
list.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
include/linux/futex.h | 4 ----
include/linux/futex_types.h | 6 ------
kernel/futex/core.c | 35 +++++++++++++++++--------------
kernel/futex/syscalls.c | 50 +++++++++++++++++++++++----------------------
4 files changed, 46 insertions(+), 49 deletions(-)
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 03a3973a7068..160e7e72b085 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -95,10 +95,6 @@ static inline void futex_init_task(struct task_struct *tsk)
INIT_LIST_HEAD(&tsk->futex.pi_state_list);
tsk->futex.state = FUTEX_STATE_OK;
mutex_init(&tsk->futex.exit_mutex);
- tsk->futex.robust_list = NULL;
-#ifdef CONFIG_COMPAT
- tsk->futex.robust_list32 = NULL;
-#endif
tsk->futex.robust_lists = NULL;
}
diff --git a/include/linux/futex_types.h b/include/linux/futex_types.h
index 58321314ecab..45c614923e46 100644
--- a/include/linux/futex_types.h
+++ b/include/linux/futex_types.h
@@ -12,8 +12,6 @@ struct robust_list_head;
/**
* struct futex_sched_data - Futex related per task data
- * @robust_list: User space registered robust list pointer
- * @robust_list32: User space registered robust list pointer for compat tasks
* @pi_state_list: List head for Priority Inheritance (PI) state management
* @pi_state_cache: Pointer to cache one PI state object per task
* @exit_mutex: Mutex for serializing exit
@@ -21,10 +19,6 @@ struct robust_list_head;
* @robust_lists: List of robust lists heads
*/
struct futex_sched_data {
- struct robust_list_head __user *robust_list;
-#ifdef CONFIG_COMPAT
- struct robust_list_head32 __user *robust_list32;
-#endif
struct list_head pi_state_list;
struct futex_pi_state *pi_state_cache;
struct mutex exit_mutex;
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index dd6fa8035fb6..23880a9d8bac 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -96,6 +96,13 @@ int futex_robust_list_create(uintptr_t head, enum robust_list2_cmd cmd)
}
switch (cmd) {
+ case FUTEX_ROBUST_LIST_SET_COMPAT:
+ entry |= FUTEX_ROBUST_LIST_ENTRY_32BIT;
+ index = FUTEX_ROBUST_LIST_COMPAT_IDX;
+ break;
+ case FUTEX_ROBUST_LIST_SET_NATIVE:
+ index = FUTEX_ROBUST_LIST_NATIVE_IDX;
+ break;
case FUTEX_ROBUST_LIST_CMD_CREATE_32:
if (head)
entry |= FUTEX_ROBUST_LIST_ENTRY_32BIT;
@@ -1294,7 +1301,8 @@ static void exit_robust_list(struct task_struct *curr, struct robust_list_head _
static bool robust_list_clear_pending(unsigned long __user *pop)
{
- struct robust_list_head __user *head = current->futex.robust_list;
+ struct robust_list_head __user *head = (struct robust_list_head __user *)
+ current->futex.robust_lists[FUTEX_ROBUST_LIST_NATIVE_IDX];
if (!put_user(0UL, pop))
return true;
@@ -1309,7 +1317,8 @@ static bool robust_list_clear_pending(unsigned long __user *pop)
* that's mostly an academic exercise.
*/
if (pop == (unsigned long __user *)&head->list_op_pending)
- current->futex.robust_list = NULL;
+ current->futex.robust_lists[FUTEX_ROBUST_LIST_NATIVE_IDX] = 0;
+
return false;
}
@@ -1412,14 +1421,16 @@ static void exit_robust_list32(struct task_struct *curr, struct robust_list_head
static bool robust_list_clear_pending32(u32 __user *pop)
{
- struct robust_list_head32 __user *head = current->futex.robust_list32;
+ struct robust_list_head32 __user *head =
+ (struct robust_list_head32 __user *)
+ current->futex.robust_lists[FUTEX_ROBUST_LIST_COMPAT_IDX];
if (!put_user(0U, pop))
return true;
/* See comment in robust_list_clear_pending(). */
if (pop == &head->list_op_pending)
- current->futex.robust_list32 = NULL;
+ current->futex.robust_lists[FUTEX_ROBUST_LIST_COMPAT_IDX] = 0;
return false;
}
#else
@@ -1527,6 +1538,9 @@ bool futex_robust_list_clear_pending(void __user *pop, unsigned int flags)
{
bool size32bit = !!(flags & FLAGS_ROBUST_LIST32);
+ if (!current->futex.robust_lists)
+ return false;
+
if (!IS_ENABLED(CONFIG_64BIT) && !size32bit)
return false;
@@ -1591,17 +1605,8 @@ static void exit_robust_lists(struct task_struct *tsk)
static void futex_cleanup(struct task_struct *tsk)
{
- if (unlikely(tsk->futex.robust_list)) {
- exit_robust_list(tsk, tsk->futex.robust_list);
- tsk->futex.robust_list = NULL;
- }
-
-#ifdef CONFIG_64BIT
- if (unlikely(tsk->futex.robust_list32)) {
- exit_robust_list32(tsk, tsk->futex.robust_list32);
- tsk->futex.robust_list32 = NULL;
- }
-#endif
+ if (unlikely(tsk->futex.robust_lists))
+ exit_robust_lists(tsk);
if (unlikely(!list_empty(&tsk->futex.pi_state_list)))
exit_pi_state_list(tsk);
diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c
index 0ecb32afd5e1..ba6730bfd47d 100644
--- a/kernel/futex/syscalls.c
+++ b/kernel/futex/syscalls.c
@@ -27,21 +27,19 @@
*/
SYSCALL_DEFINE2(set_robust_list, struct robust_list_head __user *, head, size_t, len)
{
- /* The kernel knows only one size for now. */
+ int ret;
+
+ /*
+ * The kernel knows only one size for now:
+ */
if (unlikely(len != sizeof(*head)))
return -EINVAL;
- current->futex.robust_list = head;
- return 0;
-}
-
-static inline void __user *futex_task_robust_list(struct task_struct *p, bool compat)
-{
-#ifdef CONFIG_COMPAT
- if (compat)
- return p->futex.robust_list32;
-#endif
- return p->futex.robust_list;
+ ret = futex_robust_list_create((uintptr_t) head,
+ FUTEX_ROBUST_LIST_SET_NATIVE);
+ if (ret >= 0)
+ return 0;
+ return ret;
}
static void __user *futex_get_robust_list_common(int pid, bool compat, int index)
@@ -50,6 +48,9 @@ static void __user *futex_get_robust_list_common(int pid, bool compat, int index
void __user *head;
int ret;
+ if (index >= FUTEX_ROBUST_LIST2_MAX_IDX)
+ return (void __user *)ERR_PTR(-EINVAL);
+
scoped_guard(rcu) {
if (pid) {
p = find_task_by_vpid(pid);
@@ -74,11 +75,8 @@ static void __user *futex_get_robust_list_common(int pid, bool compat, int index
if (index >= 0) {
scoped_guard(mutex, &p->futex.exit_mutex) {
uintptr_t *rl = p->futex.robust_lists;
-
head = rl ? (void __user *) rl[index] : NULL;
}
- } else {
- head = futex_task_robust_list(p, compat);
}
up_read(&p->signal->exec_update_lock);
@@ -103,11 +101,15 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
struct robust_list_head __user * __user *, head_ptr,
size_t __user *, len_ptr)
{
- struct robust_list_head __user *head = futex_get_robust_list_common(pid, false, -1);
+ struct robust_list_head __user *head =
+ futex_get_robust_list_common(pid, false, FUTEX_ROBUST_LIST_NATIVE_IDX);
if (IS_ERR(head))
return PTR_ERR(head);
+ head = (struct robust_list_head __user *)
+ ((uintptr_t) head & FUTEX_ROBUST_LIST_ENTRY_MASK);
+
if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
return put_user(head, head_ptr);
@@ -168,8 +170,7 @@ SYSCALL_DEFINE4(set_robust_list2, struct robust_list_head * __user, head, unsign
return -EINVAL;
}
-SYSCALL_DEFINE4(get_robust_list2, int, pid,
- void __user * __user *, head_ptr,
+SYSCALL_DEFINE4(get_robust_list2, int, pid, void __user * __user *, head_ptr,
unsigned int, index, unsigned int, flags)
{
struct robust_list_head *head;
@@ -597,22 +598,23 @@ COMPAT_SYSCALL_DEFINE2(set_robust_list, struct robust_list_head32 __user *, head
if (unlikely(len != sizeof(*head)))
return -EINVAL;
- current->futex.robust_list32 = head;
-
- return 0;
+ return futex_robust_list_create((uintptr_t) head,
+ FUTEX_ROBUST_LIST_SET_COMPAT);
}
COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
compat_uptr_t __user *, head_ptr,
compat_size_t __user *, len_ptr)
{
- struct robust_list_head32 __user *head = futex_get_robust_list_common(pid, true, -1);
+ struct robust_list_head32 __user *head =
+ futex_get_robust_list_common(pid, true, FUTEX_ROBUST_LIST_COMPAT_IDX);
- if (IS_ERR(head))
- return PTR_ERR(head);
+ head = (struct robust_list_head32 __user *)
+ ((uintptr_t) head & FUTEX_ROBUST_LIST_ENTRY_MASK);
if (put_user(sizeof(*head), len_ptr))
return -EFAULT;
+
return put_user(ptr_to_compat(head), head_ptr);
}
#endif /* CONFIG_COMPAT */
--
2.56.1
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v8 10/10] futex: Use new robust list API internally
2026-11-15 17:31 ` [PATCH v8 10/10] futex: Use new robust list API internally André Almeida
@ 2026-11-15 20:44 ` kernel test robot
0 siblings, 0 replies; 14+ messages in thread
From: kernel test robot @ 2026-11-15 20:44 UTC (permalink / raw)
To: André Almeida, Ingo Molnar, Peter Zijlstra, Darren Hart,
Davidlohr Bueso, Arnd Bergmann, Sebastian Andrzej Siewior,
Waiman Long, Ryan Houdek, Thomas Gleixner
Cc: llvm, oe-kbuild-all, linux-kernel, linux-kselftest, linux-api,
kernel-dev, André Almeida
Hi André,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 9f74092fda91ef93c2b07585785c1dc83cd7971f]
url: https://github.com/intel-lab-lkp/linux/commits/Andr-Almeida/futex-Skip-test_futex_robust_unlock-if-not-supported/20261115-143110
base: 9f74092fda91ef93c2b07585785c1dc83cd7971f
patch link: https://lore.kernel.org/r/20261115-tonyk-robust_futex-v8-10-a4fe47333a28%40igalia.com
patch subject: [PATCH v8 10/10] futex: Use new robust list API internally
config: x86_64-allnoconfig (https://download.01.org/0day-ci/archive/20261116/202611160419.vIdH20Tu-lkp@intel.com/config)
compiler: clang version 22.1.8 (https://github.com/llvm/llvm-project ca7933e47d3a3451d81e72ac174dcb5aa28b59d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261116/202611160419.vIdH20Tu-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202611160419.vIdH20Tu-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> kernel/futex/syscalls.c:75:6: warning: variable 'head' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
75 | if (index >= 0) {
| ^~~~~~~~~~
kernel/futex/syscalls.c:85:9: note: uninitialized use occurs here
85 | return head;
| ^~~~
kernel/futex/syscalls.c:75:2: note: remove the 'if' if its condition is always true
75 | if (index >= 0) {
| ^~~~~~~~~~~~~~~
kernel/futex/syscalls.c:48:19: note: initialize the variable 'head' to silence this warning
48 | void __user *head;
| ^
| = NULL
1 warning generated.
vim +75 kernel/futex/syscalls.c
af8cc9600bbf22 Peter Zijlstra 2021-09-23 44
5588aabbe40841 André Almeida 2026-11-15 45 static void __user *futex_get_robust_list_common(int pid, bool compat, int index)
6b54082c3ed4dc Pranav Tyagi 2025-09-15 46 {
6b54082c3ed4dc Pranav Tyagi 2025-09-15 47 struct task_struct *p = current;
6b54082c3ed4dc Pranav Tyagi 2025-09-15 48 void __user *head;
6b54082c3ed4dc Pranav Tyagi 2025-09-15 49 int ret;
af8cc9600bbf22 Peter Zijlstra 2021-09-23 50
a2d2b7acb53d36 André Almeida 2026-11-15 51 if (index >= FUTEX_ROBUST_LIST2_MAX_IDX)
a2d2b7acb53d36 André Almeida 2026-11-15 52 return (void __user *)ERR_PTR(-EINVAL);
a2d2b7acb53d36 André Almeida 2026-11-15 53
6b54082c3ed4dc Pranav Tyagi 2025-09-15 54 scoped_guard(rcu) {
6b54082c3ed4dc Pranav Tyagi 2025-09-15 55 if (pid) {
af8cc9600bbf22 Peter Zijlstra 2021-09-23 56 p = find_task_by_vpid(pid);
af8cc9600bbf22 Peter Zijlstra 2021-09-23 57 if (!p)
6b54082c3ed4dc Pranav Tyagi 2025-09-15 58 return (void __user *)ERR_PTR(-ESRCH);
6b54082c3ed4dc Pranav Tyagi 2025-09-15 59 }
6b54082c3ed4dc Pranav Tyagi 2025-09-15 60 get_task_struct(p);
af8cc9600bbf22 Peter Zijlstra 2021-09-23 61 }
af8cc9600bbf22 Peter Zijlstra 2021-09-23 62
6b54082c3ed4dc Pranav Tyagi 2025-09-15 63 /*
6b54082c3ed4dc Pranav Tyagi 2025-09-15 64 * Hold exec_update_lock to serialize with concurrent exec()
6b54082c3ed4dc Pranav Tyagi 2025-09-15 65 * so ptrace_may_access() is checked against stable credentials
6b54082c3ed4dc Pranav Tyagi 2025-09-15 66 */
6b54082c3ed4dc Pranav Tyagi 2025-09-15 67 ret = down_read_killable(&p->signal->exec_update_lock);
6b54082c3ed4dc Pranav Tyagi 2025-09-15 68 if (ret)
6b54082c3ed4dc Pranav Tyagi 2025-09-15 69 goto err_put;
6b54082c3ed4dc Pranav Tyagi 2025-09-15 70
af8cc9600bbf22 Peter Zijlstra 2021-09-23 71 ret = -EPERM;
af8cc9600bbf22 Peter Zijlstra 2021-09-23 72 if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
af8cc9600bbf22 Peter Zijlstra 2021-09-23 73 goto err_unlock;
af8cc9600bbf22 Peter Zijlstra 2021-09-23 74
5588aabbe40841 André Almeida 2026-11-15 @75 if (index >= 0) {
5588aabbe40841 André Almeida 2026-11-15 76 scoped_guard(mutex, &p->futex.exit_mutex) {
5588aabbe40841 André Almeida 2026-11-15 77 uintptr_t *rl = p->futex.robust_lists;
5588aabbe40841 André Almeida 2026-11-15 78 head = rl ? (void __user *) rl[index] : NULL;
5588aabbe40841 André Almeida 2026-11-15 79 }
5588aabbe40841 André Almeida 2026-11-15 80 }
af8cc9600bbf22 Peter Zijlstra 2021-09-23 81
6b54082c3ed4dc Pranav Tyagi 2025-09-15 82 up_read(&p->signal->exec_update_lock);
6b54082c3ed4dc Pranav Tyagi 2025-09-15 83 put_task_struct(p);
6b54082c3ed4dc Pranav Tyagi 2025-09-15 84
6b54082c3ed4dc Pranav Tyagi 2025-09-15 85 return head;
af8cc9600bbf22 Peter Zijlstra 2021-09-23 86
af8cc9600bbf22 Peter Zijlstra 2021-09-23 87 err_unlock:
6b54082c3ed4dc Pranav Tyagi 2025-09-15 88 up_read(&p->signal->exec_update_lock);
6b54082c3ed4dc Pranav Tyagi 2025-09-15 89 err_put:
6b54082c3ed4dc Pranav Tyagi 2025-09-15 90 put_task_struct(p);
6b54082c3ed4dc Pranav Tyagi 2025-09-15 91 return (void __user *)ERR_PTR(ret);
6b54082c3ed4dc Pranav Tyagi 2025-09-15 92 }
af8cc9600bbf22 Peter Zijlstra 2021-09-23 93
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 14+ messages in thread