diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-09-30 22:35:22 +0200 |
---|---|---|
committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-09-30 23:32:24 +0200 |
commit | 8596973fc83d29b923628e287cf65685b94bfbec (patch) | |
tree | dfc15014d82dc7ad397a15a1beff40ec1cae502b | |
parent | 721e3970304532c88dddce11e794001cb90f374f (diff) | |
download | 4.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.patch | 161 | ||||
-rw-r--r-- | patches/localversion.patch | 2 | ||||
-rw-r--r-- | patches/rt-locking-Reenable-migration-accross-schedule.patch | 8 | ||||
-rw-r--r-- | patches/series | 1 |
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 |