Re: [PATCH 3/5] locking/rtmutex: Clone a waiter's sort keys as it enters pi_waiters

From: Peter Zijlstra

Date: Sat Nov 07 2026 - 06:03:11 EST


On Fri, Nov 06, 2026 at 06:59:29PM -0500, Mathieu Desnoyers wrote:

snip unreadable changelog

> Fixes: f7853c342418 ("locking/rtmutex: Fix task->pi_waiters integrity")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@xxxxxxxxxxxx>
> ---
> kernel/locking/rtmutex.c | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
> index 323973be2074..e89f0f0e604b 100644
> --- a/kernel/locking/rtmutex.c
> +++ b/kernel/locking/rtmutex.c
> @@ -512,11 +512,19 @@ static __always_inline bool __pi_waiter_less(struct rb_node *a, const struct rb_
> return rt_waiter_node_less(__node_2_rt_node(a), __node_2_rt_node(b));
> }
>
> +/*
> + * Enqueue @waiter in the pi_waiters of @task, its lock's owner, with the
> + * sort keys of its lock tree copy, current under the wait_lock held here:
> + * the chain walk updates the tree copy of a waiter that is not the top
> + * waiter of its lock, and does not clone it, so a copy cloned before would
> + * enter @task's pi_waiters with the keys of a priority it no longer has.
> + */

Oh gawd, Mathieu, can you please tell your AI thing to never write a
Changelog or comment? This is again unreadable soup.

> static __always_inline void
> rt_mutex_enqueue_pi(struct task_struct *task, struct rt_mutex_waiter *waiter)
> {
> lockdep_assert_held(&task->pi_lock);
>
> + waiter_clone_prio(waiter, task);
> rb_add_cached(&waiter->pi_tree.entry, &task->pi_waiters, __pi_waiter_less);
> }
>
> @@ -1005,7 +1013,6 @@ static int __sched rt_mutex_adjust_prio_chain(struct task_struct *task,
> * and adjust the priority of the owner.
> */
> rt_mutex_dequeue_pi(task, prerequeue_top_waiter);
> - waiter_clone_prio(waiter, task);
> rt_mutex_enqueue_pi(task, waiter);
> rt_mutex_adjust_prio(lock, task);
>
> @@ -1022,7 +1029,6 @@ static int __sched rt_mutex_adjust_prio_chain(struct task_struct *task,
> */
> rt_mutex_dequeue_pi(task, waiter);
> waiter = rt_mutex_top_waiter(lock);
> - waiter_clone_prio(waiter, task);
> rt_mutex_enqueue_pi(task, waiter);
> rt_mutex_adjust_prio(lock, task);
> } else {
> @@ -1243,7 +1249,6 @@ static int __sched task_blocks_on_rt_mutex(struct rt_mutex_base *lock,
> waiter->task = task;
> waiter->lock = lock;
> waiter_update_prio(waiter, task);
> - waiter_clone_prio(waiter, task);

Reverse engineering the problem leads me to think this is the problem
spot. Because this is the one site that is not immediately followed by
rt_mutex_enqueue_pi().

I'm thinking there's race due to dropping pi_lock between this copy and
the subsequent enqueue?

>
> /* Get the top priority waiter on the lock */
> if (rt_mutex_has_waiters(lock))
> --
> 2.47.3
>