summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2016-09-30 22:35:22 +0200
committerSebastian Andrzej Siewior <bigeasy@linutronix.de>2016-09-30 23:32:24 +0200
commit8596973fc83d29b923628e287cf65685b94bfbec (patch)
treedfc15014d82dc7ad397a15a1beff40ec1cae502b
parent721e3970304532c88dddce11e794001cb90f374f (diff)
download4.9-rt-patches-8596973fc83d29b923628e287cf65685b94bfbec.tar.gz
[ANNOUNCE] 4.6.7-rt14
Dear RT folks! I'm pleased to announce the v4.6.7-rt14 patch set. Changes since v4.6.7-rt13: - It is possible that a task which got priority boosted, de-boosted itself too early in the unlock path. This leads to then priority inversion because the waiter with priority waits while a process with lower priority runs. Known issues - CPU hotplug got a little better but can deadlock. The delta patch against 4.6.7-rt12 is appended below and can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.6/incr/patch-4.6.7-rt13-rt14.patch.xz You can get this release via the git tree at: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v4.6.7-rt14 The RT patch against 4.6.7 can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.6/patch-4.6.7-rt14.patch.xz The split quilt queue is available at: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.6/patches-4.6.7-rt14.tar.xz Sebastian Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-rw-r--r--patches/kernel-futex-don-t-deboost-too-early.patch161
-rw-r--r--patches/localversion.patch2
-rw-r--r--patches/rt-locking-Reenable-migration-accross-schedule.patch8
-rw-r--r--patches/series1
4 files changed, 167 insertions, 5 deletions
diff --git a/patches/kernel-futex-don-t-deboost-too-early.patch b/patches/kernel-futex-don-t-deboost-too-early.patch
new file mode 100644
index 00000000000000..7be17e7b606ac1
--- /dev/null
+++ b/patches/kernel-futex-don-t-deboost-too-early.patch
@@ -0,0 +1,161 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Thu, 29 Sep 2016 18:49:22 +0200
+Subject: [PATCH] kernel/futex: don't deboost too early
+
+The sequence:
+ T1 holds futex
+ T2 blocks on futex and boosts T1
+ T1 unlocks futex and holds hb->lock
+ T1 unlocks rt mutex, so T1 has no more pi waiters
+ T3 blocks on hb->lock and adds itself to the pi waiters list of T1
+ T1 unlocks hb->lock and deboosts itself
+ T4 preempts T1 so the wakeup of T2 gets delayed
+
+As a workaround I attempt here do unlock the hb->lock without a deboost
+and perform the deboost after the wake up of the waiter.
+
+Cc: stable-rt@vger.kernel.org
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ include/linux/spinlock.h | 6 ++++
+ include/linux/spinlock_rt.h | 2 +
+ kernel/futex.c | 2 -
+ kernel/locking/rtmutex.c | 53 ++++++++++++++++++++++++++++++++++++++------
+ 4 files changed, 55 insertions(+), 8 deletions(-)
+
+--- a/include/linux/spinlock.h
++++ b/include/linux/spinlock.h
+@@ -355,6 +355,12 @@ static __always_inline void spin_unlock(
+ raw_spin_unlock(&lock->rlock);
+ }
+
++static __always_inline int spin_unlock_no_deboost(spinlock_t *lock)
++{
++ raw_spin_unlock(&lock->rlock);
++ return 0;
++}
++
+ static __always_inline void spin_unlock_bh(spinlock_t *lock)
+ {
+ raw_spin_unlock_bh(&lock->rlock);
+--- a/include/linux/spinlock_rt.h
++++ b/include/linux/spinlock_rt.h
+@@ -26,6 +26,7 @@ extern void __lockfunc rt_spin_lock(spin
+ extern unsigned long __lockfunc rt_spin_lock_trace_flags(spinlock_t *lock);
+ extern void __lockfunc rt_spin_lock_nested(spinlock_t *lock, int subclass);
+ extern void __lockfunc rt_spin_unlock(spinlock_t *lock);
++extern int __lockfunc rt_spin_unlock_no_deboost(spinlock_t *lock);
+ extern void __lockfunc rt_spin_unlock_wait(spinlock_t *lock);
+ extern int __lockfunc rt_spin_trylock_irqsave(spinlock_t *lock, unsigned long *flags);
+ extern int __lockfunc rt_spin_trylock_bh(spinlock_t *lock);
+@@ -112,6 +113,7 @@ static inline unsigned long spin_lock_tr
+ #define spin_lock_nest_lock(lock, nest_lock) spin_lock_nested(lock, 0)
+
+ #define spin_unlock(lock) rt_spin_unlock(lock)
++#define spin_unlock_no_deboost(lock) rt_spin_unlock_no_deboost(lock)
+
+ #define spin_unlock_bh(lock) \
+ do { \
+--- a/kernel/futex.c
++++ b/kernel/futex.c
+@@ -1347,7 +1347,7 @@ static int wake_futex_pi(u32 __user *uad
+ * deboost first (and lose our higher priority), then the task might get
+ * scheduled away before the wake up can take place.
+ */
+- spin_unlock(&hb->lock);
++ deboost |= spin_unlock_no_deboost(&hb->lock);
+ wake_up_q(&wake_q);
+ wake_up_q_sleeper(&wake_sleeper_q);
+ if (deboost)
+--- a/kernel/locking/rtmutex.c
++++ b/kernel/locking/rtmutex.c
+@@ -934,13 +934,14 @@ static inline void rt_spin_lock_fastlock
+ slowfn(lock);
+ }
+
+-static inline void rt_spin_lock_fastunlock(struct rt_mutex *lock,
+- void (*slowfn)(struct rt_mutex *lock))
++static inline int rt_spin_lock_fastunlock(struct rt_mutex *lock,
++ int (*slowfn)(struct rt_mutex *lock))
+ {
+- if (likely(rt_mutex_cmpxchg_release(lock, current, NULL)))
++ if (likely(rt_mutex_cmpxchg_release(lock, current, NULL))) {
+ rt_mutex_deadlock_account_unlock(current);
+- else
+- slowfn(lock);
++ return 0;
++ }
++ return slowfn(lock);
+ }
+ #ifdef CONFIG_SMP
+ /*
+@@ -1075,7 +1076,7 @@ static void mark_wakeup_next_waiter(stru
+ /*
+ * Slow path to release a rt_mutex spin_lock style
+ */
+-static void noinline __sched rt_spin_lock_slowunlock(struct rt_mutex *lock)
++static int noinline __sched rt_spin_lock_slowunlock(struct rt_mutex *lock)
+ {
+ unsigned long flags;
+ WAKE_Q(wake_q);
+@@ -1090,7 +1091,7 @@ static void noinline __sched rt_spin_lo
+ if (!rt_mutex_has_waiters(lock)) {
+ lock->owner = NULL;
+ raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
+- return;
++ return 0;
+ }
+
+ mark_wakeup_next_waiter(&wake_q, &wake_sleeper_q, lock);
+@@ -1101,6 +1102,33 @@ static void noinline __sched rt_spin_lo
+
+ /* Undo pi boosting.when necessary */
+ rt_mutex_adjust_prio(current);
++ return 0;
++}
++
++static int noinline __sched rt_spin_lock_slowunlock_no_deboost(struct rt_mutex *lock)
++{
++ unsigned long flags;
++ WAKE_Q(wake_q);
++ WAKE_Q(wake_sleeper_q);
++
++ raw_spin_lock_irqsave(&lock->wait_lock, flags);
++
++ debug_rt_mutex_unlock(lock);
++
++ rt_mutex_deadlock_account_unlock(current);
++
++ if (!rt_mutex_has_waiters(lock)) {
++ lock->owner = NULL;
++ raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
++ return 0;
++ }
++
++ mark_wakeup_next_waiter(&wake_q, &wake_sleeper_q, lock);
++
++ raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
++ wake_up_q(&wake_q);
++ wake_up_q_sleeper(&wake_sleeper_q);
++ return 1;
+ }
+
+ void __lockfunc rt_spin_lock__no_mg(spinlock_t *lock)
+@@ -1158,6 +1186,17 @@ void __lockfunc rt_spin_unlock(spinlock_
+ }
+ EXPORT_SYMBOL(rt_spin_unlock);
+
++int __lockfunc rt_spin_unlock_no_deboost(spinlock_t *lock)
++{
++ int ret;
++
++ /* NOTE: we always pass in '1' for nested, for simplicity */
++ spin_release(&lock->dep_map, 1, _RET_IP_);
++ ret = rt_spin_lock_fastunlock(&lock->lock, rt_spin_lock_slowunlock_no_deboost);
++ migrate_enable();
++ return ret;
++}
++
+ void __lockfunc __rt_spin_unlock(struct rt_mutex *lock)
+ {
+ rt_spin_lock_fastunlock(lock, rt_spin_lock_slowunlock);
diff --git a/patches/localversion.patch b/patches/localversion.patch
index 25e5fadbaae8f1..e1f3b8d87864f2 100644
--- a/patches/localversion.patch
+++ b/patches/localversion.patch
@@ -10,4 +10,4 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
--- /dev/null
+++ b/localversion-rt
@@ -0,0 +1 @@
-+-rt13
++-rt14
diff --git a/patches/rt-locking-Reenable-migration-accross-schedule.patch b/patches/rt-locking-Reenable-migration-accross-schedule.patch
index f552a2d58bb1cf..3180135fe07c5c 100644
--- a/patches/rt-locking-Reenable-migration-accross-schedule.patch
+++ b/patches/rt-locking-Reenable-migration-accross-schedule.patch
@@ -39,8 +39,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ slowfn(lock, do_mig_dis);
}
- static inline void rt_spin_lock_fastunlock(struct rt_mutex *lock,
-@@ -989,7 +994,8 @@ static int task_blocks_on_rt_mutex(struc
+ static inline int rt_spin_lock_fastunlock(struct rt_mutex *lock,
+@@ -990,7 +995,8 @@ static int task_blocks_on_rt_mutex(struc
* We store the current state under p->pi_lock in p->saved_state and
* the try_to_wake_up() code handles this accordingly.
*/
@@ -50,7 +50,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{
struct task_struct *lock_owner, *self = current;
struct rt_mutex_waiter waiter, *top_waiter;
-@@ -1033,8 +1039,13 @@ static void noinline __sched rt_spin_lo
+@@ -1034,8 +1040,13 @@ static void noinline __sched rt_spin_lo
debug_rt_mutex_print_deadlock(&waiter);
@@ -65,7 +65,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
raw_spin_lock_irqsave(&lock->wait_lock, flags);
-@@ -1105,38 +1116,35 @@ static void noinline __sched rt_spin_lo
+@@ -1133,38 +1144,35 @@ static int noinline __sched rt_spin_lock
void __lockfunc rt_spin_lock__no_mg(spinlock_t *lock)
{
diff --git a/patches/series b/patches/series
index 1d2fa04282f757..8f9d915fc264e3 100644
--- a/patches/series
+++ b/patches/series
@@ -554,6 +554,7 @@ cpu_down_move_migrate_enable_back.patch
hotplug-Use-set_cpus_allowed_ptr-in-sync_unplug_thre.patch
rtmutex-push-down-migrate_disable-into-rt_spin_lock.patch
+kernel-futex-don-t-deboost-too-early.patch
rt-locking-Reenable-migration-accross-schedule.patch
# SCSCI QLA2xxx