121 lines
3.9 KiB
Diff
121 lines
3.9 KiB
Diff
From: Peter Zijlstra <peterz@infradead.org>
|
|
Date: Thu, 23 Mar 2017 15:56:13 +0100
|
|
Subject: [PATCH 7/9] rtmutex: Fix PI chain order integrity
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.11/older/patches-4.11.8-rt5.tar.xz
|
|
|
|
rt_mutex_waiter::prio is a copy of task_struct::prio which is updated
|
|
during the PI chain walk, such that the PI chain order isn't messed up
|
|
by (asynchronous) task state updates.
|
|
|
|
Currently rt_mutex_waiter_less() uses task state for deadline tasks;
|
|
this is broken, since the task state can, as said above, change
|
|
asynchronously, causing the RB tree order to change without actual
|
|
tree update -> FAIL.
|
|
|
|
Fix this by also copying the deadline into the rt_mutex_waiter state
|
|
and updating it along with its prio field.
|
|
|
|
Ideally we would also force PI chain updates whenever DL tasks update
|
|
their deadline parameter, but for first approximation this is less
|
|
broken than it was.
|
|
|
|
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
|
|
Cc: juri.lelli@arm.com
|
|
Cc: bigeasy@linutronix.de
|
|
Cc: xlpang@redhat.com
|
|
Cc: rostedt@goodmis.org
|
|
Cc: mathieu.desnoyers@efficios.com
|
|
Cc: jdesfossez@efficios.com
|
|
Cc: bristot@redhat.com
|
|
Link: http://lkml.kernel.org/r/20170323150216.403992539@infradead.org
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
---
|
|
kernel/locking/rtmutex.c | 29 +++++++++++++++++++++++++++--
|
|
kernel/locking/rtmutex_common.h | 1 +
|
|
2 files changed, 28 insertions(+), 2 deletions(-)
|
|
|
|
--- a/kernel/locking/rtmutex.c
|
|
+++ b/kernel/locking/rtmutex.c
|
|
@@ -238,8 +238,7 @@ rt_mutex_waiter_less(struct rt_mutex_wai
|
|
* then right waiter has a dl_prio() too.
|
|
*/
|
|
if (dl_prio(left->prio))
|
|
- return dl_time_before(left->task->dl.deadline,
|
|
- right->task->dl.deadline);
|
|
+ return dl_time_before(left->deadline, right->deadline);
|
|
|
|
return 0;
|
|
}
|
|
@@ -650,7 +649,26 @@ static int rt_mutex_adjust_prio_chain(st
|
|
|
|
/* [7] Requeue the waiter in the lock waiter tree. */
|
|
rt_mutex_dequeue(lock, waiter);
|
|
+
|
|
+ /*
|
|
+ * Update the waiter prio fields now that we're dequeued.
|
|
+ *
|
|
+ * These values can have changed through either:
|
|
+ *
|
|
+ * sys_sched_set_scheduler() / sys_sched_setattr()
|
|
+ *
|
|
+ * or
|
|
+ *
|
|
+ * DL CBS enforcement advancing the effective deadline.
|
|
+ *
|
|
+ * Even though pi_waiters also uses these fields, and that tree is only
|
|
+ * updated in [11], we can do this here, since we hold [L], which
|
|
+ * serializes all pi_waiters access and rb_erase() does not care about
|
|
+ * the values of the node being removed.
|
|
+ */
|
|
waiter->prio = task->prio;
|
|
+ waiter->deadline = task->dl.deadline;
|
|
+
|
|
rt_mutex_enqueue(lock, waiter);
|
|
|
|
/* [8] Release the task */
|
|
@@ -777,6 +795,8 @@ static int rt_mutex_adjust_prio_chain(st
|
|
static int try_to_take_rt_mutex(struct rt_mutex *lock, struct task_struct *task,
|
|
struct rt_mutex_waiter *waiter)
|
|
{
|
|
+ lockdep_assert_held(&lock->wait_lock);
|
|
+
|
|
/*
|
|
* Before testing whether we can acquire @lock, we set the
|
|
* RT_MUTEX_HAS_WAITERS bit in @lock->owner. This forces all
|
|
@@ -902,6 +922,8 @@ static int task_blocks_on_rt_mutex(struc
|
|
struct rt_mutex *next_lock;
|
|
int chain_walk = 0, res;
|
|
|
|
+ lockdep_assert_held(&lock->wait_lock);
|
|
+
|
|
/*
|
|
* Early deadlock detection. We really don't want the task to
|
|
* enqueue on itself just to untangle the mess later. It's not
|
|
@@ -919,6 +941,7 @@ static int task_blocks_on_rt_mutex(struc
|
|
waiter->task = task;
|
|
waiter->lock = lock;
|
|
waiter->prio = task->prio;
|
|
+ waiter->deadline = task->dl.deadline;
|
|
|
|
/* Get the top priority waiter on the lock */
|
|
if (rt_mutex_has_waiters(lock))
|
|
@@ -1036,6 +1059,8 @@ static void remove_waiter(struct rt_mute
|
|
struct task_struct *owner = rt_mutex_owner(lock);
|
|
struct rt_mutex *next_lock;
|
|
|
|
+ lockdep_assert_held(&lock->wait_lock);
|
|
+
|
|
raw_spin_lock(¤t->pi_lock);
|
|
rt_mutex_dequeue(lock, waiter);
|
|
current->pi_blocked_on = NULL;
|
|
--- a/kernel/locking/rtmutex_common.h
|
|
+++ b/kernel/locking/rtmutex_common.h
|
|
@@ -34,6 +34,7 @@ struct rt_mutex_waiter {
|
|
struct rt_mutex *deadlock_lock;
|
|
#endif
|
|
int prio;
|
|
+ u64 deadline;
|
|
};
|
|
|
|
/*
|