Linux v4.14.170-rt75-rc2
Subsystems (12)
cover Linux v4.14.170-rt75-rc2
From: Tom Zanussi <[email protected]>
Dear RT Folks,
This is the RT stable review cycle of patch 4.14.170-rt75-rc2.
Please scream at me if I messed something up. Please test the patches too.
The -rc release will be uploaded to kernel.org and will be deleted when the final release is out. This is just a review release (or release candidate).
The pre-releases will not be pushed to the git repository, only the final release is.
If all goes well, this patch will be converted to the next main release on 2020-03-05.
To build 4.14.170-rt75-rc2 directly, the following patches should be applied:
https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.14.tar.xz
https://www.kernel.org/pub/linux/kernel/v4.x/patch-4.14.170.xz
https://www.kernel.org/pub/linux/kernel/projects/rt/4.14/patch-4.14.170-rt75-rc2.patch.xz
You can also build from 4.14.170-rt74 by applying the incremental patch:
https://www.kernel.org/pub/linux/kernel/projects/rt/4.14/incr/patch-4.14.170-rt74-rt75-rc2.patch.xz
Enjoy,
-- Tom
Daniel Wagner (1):
lib/smp_processor_id: Adjust check_preemption_disabled()
Joe Korty (1):
Fix wrong-variable use in irq_set_affinity_notifier
Julien Grall (1):
lib/ubsan: Don't seralize UBSAN report
Juri Lelli (1):
sched/deadline: Ensure inactive_timer runs in hardirq context
Liu Haitao (1):
kmemleak: Change the lock of kmemleak_object to raw_spinlock_t
Peter Zijlstra (1):
locking/rtmutex: Clean ->pi_blocked_on in the error case
Scott Wood (7):
sched: migrate_dis/enable: Use sleeping_lock…() to annotate sleeping
points
sched: __set_cpus_allowed_ptr: Check cpus_mask, not cpus_ptr
sched: Remove dead __migrate_disabled() check
sched: migrate disable: Protect cpus_ptr with lock
sched: migrate_enable: Use select_fallback_rq()
sched: Lazy migrate_disable processing
sched: migrate_enable: Use stop_one_cpu_nowait()
Sebastian Andrzej Siewior (8):
i2c: exynos5: Remove IRQF_ONESHOT
i2c: hix5hd2: Remove IRQF_ONESHOT
x86: preempt: Check preemption level before looking at lazy-preempt
futex: Make the futex_hash_bucket spinlock_t again and bring back its
old state
Revert "ARM: Initialize split page table locks for vector page"
locking: Make spinlock_t and rwlock_t a RCU section on RT sched/core: migrate_enable() must access takedown_cpu_task on
!HOTPLUG_CPU
sched: migrate_enable: Busy loop until the migration request is
completed
Tom Zanussi (1):
Linux 4.14.170-rt75-rc2
Waiman Long (1):
lib/smp_processor_id: Don't use cpumask_equal()
arch/arm/kernel/process.c | 24 ---- arch/x86/include/asm/preempt.h | 2 + drivers/i2c/busses/i2c-exynos5.c | 4 +- drivers/i2c/busses/i2c-hix5hd2.c | 3 +- include/linux/cpu.h | 4 - include/linux/init_task.h | 9 ++ include/linux/sched.h | 11 +- include/linux/stop_machine.h | 2 + kernel/cpu.c | 103 +++++++---------- kernel/futex.c | 231 ++++++++++++++++++++++----------------- kernel/irq/manage.c | 2 +- kernel/locking/rtmutex.c | 114 +++++++++++++++---- kernel/locking/rtmutex_common.h | 3 + kernel/locking/rwlock-rt.c | 6 + kernel/sched/core.c | 211 +++++++++++++++-------------------- kernel/sched/deadline.c | 4 +- kernel/sched/sched.h | 4 + kernel/stop_machine.c | 7 +- lib/smp_processor_id.c | 7 +- lib/ubsan.c | 76 +++++-------- localversion-rt | 2 +- mm/kmemleak.c | 72 ++++++------ 22 files changed, 461 insertions(+), 440 deletions(-)
Signature · 1 line
2.14.1
PATCH 1/23 Fix wrong-variable use in irq_set_affinity_notifier
From: Joe Korty <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Fixes upstream commit 3e4242082f0384311f15ab9c93e2620268c6257f,
which erroneously switched old_notify->work to notify->work when fixing a merge conflict ]
4.14-rt: Fix wrong-variable use in irq_set_affinity_notifier.
The bug was introduced in the 4.14-rt patch
0461-genirq-Handle-missing-work_struct-in-irq_set_affinit.patch
The symptom is a NULL pointer panic in the i40e driver on system shutdown.
Rebooting.
BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
IP: __kthread_cancel_work_sync+0x12/0xa0
CPU: 15 PID: 6274 Comm: reboot Not tainted 4.14.155-rt70-RedHawk-8.0.2-prt-trace #1
task: ffff9ef0d1a58000 task.stack: ffffbe540c038000
RIP: 0010:__kthread_cancel_work_sync+0x12/0xa0
RSP: 0018:ffffbe540c03bbd8 EFLAGS: 00010296
RAX: 0000084000000020 RBX: 0000000000000000 RCX: 0000000000000034
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000008
RBP: ffffbe540c03bc00 R08: ffff9ee8ccdc3800 R09: ffff9ef0d8c0c000
R10: ffff9ef0d8c0c028 R11: 0000000000000040 R12: ffff9ee8ccdc3800
R13: 0000000000000000 R14: ffff9ee8ccdc3960 R15: 0000000000000074
FS: 00007ffff7fcf380(0000) GS:ffff9ef0ffdc0000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000020 CR3: 000000104b428003 CR4: 00000000005606e0
DR0: 00000000006040e0 DR1: 00000000006040e8 DR2: 00000000006040f0
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000600
PKRU: 55555554
Call Trace:
kthread_cancel_work_sync+0xb/0x10
irq_set_affinity_notifier+0x8e/0xc0
i40e_vsi_free_irq+0xbc/0x230 [i40e]
i40e_vsi_close+0x24/0xa0 [i40e]
i40e_close+0x10/0x20 [i40e]
i40e_quiesce_vsi.part.40+0x30/0x40 [i40e]
i40e_pf_quiesce_all_vsi.isra.41+0x34/0x50 [i40e]
i40e_prep_for_reset+0x67/0x110 [i40e]
i40e_shutdown+0x39/0x220 [i40e]
pci_device_shutdown+0x2b/0x50
device_shutdown+0x147/0x1f0
kernel_restart_prepare+0x71/0x74
kernel_restart+0xd/0x4e
SyS_reboot.cold.1+0x9/0x34
do_syscall_64+0x7c/0x1504.19-rt and above do not have this problem due to a refactoring.
--- kernel/irq/manage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/irq/manage.c +1 -1
@@ -353,7 +353,7 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)if (old_notify) {#ifdef CONFIG_PREEMPT_RT_BASE -kthread_cancel_work_sync (¬ify->work); +kthread_cancel_work_sync (&old_notify->work);#else cancel_work_sync (&old_notify->work);#endif
Signature · 1 line
2.14.1
PATCH 2/23 i2c: exynos5: Remove IRQF_ONESHOT
In reply to [email protected]From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 4b217df0ab3f7910c96e42091cc7d9f221d05f01 ]
The drivers sets IRQF_ONESHOT and passes only a primary handler. The IRQ is masked while the primary is handler is invoked independently of IRQF_ONESHOT.
With IRQF_ONESHOT the core code will not force-thread the interrupt and this is probably not intended. I *assume* that the original author copied the IRQ registration from another driver which passed a primary and secondary handler and removed the secondary handler but keeping the ONESHOT flag.
Remove IRQF_ONESHOT.
--- drivers/i2c/busses/i2c-exynos5.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/i2c/busses/i2c-exynos5.c +1 -3
@@ -758,9 +758,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev) } ret =devm_request_irq (&pdev->dev, i2c->irq, exynos5_i2c_irq, -IRQF_NO_SUSPEND |IRQF_ONESHOT , -dev_name (&pdev->dev), i2c); - +IRQF_NO_SUSPEND ,dev_name (&pdev->dev), i2c);if (ret !=0 ) {dev_err (&pdev->dev,"cannot request HS-I2C IRQ %d\n" , i2c->irq); goto err_clk;
Signature · 1 line
2.14.1
PATCH 3/23 i2c: hix5hd2: Remove IRQF_ONESHOT
In reply to [email protected]From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit e88b481f3f86f11e3243e0808a830e5ca5782a9d ]
The drivers sets IRQF_ONESHOT and passes only a primary handler. The IRQ is masked while the primary is handler is invoked independently of IRQF_ONESHOT.
With IRQF_ONESHOT the core code will not force-thread the interrupt and this is probably not intended. I *assume* that the original author copied the IRQ registration from another driver which passed a primary and secondary handler and removed the secondary handler but keeping the ONESHOT flag.
Remove IRQF_ONESHOT.
--- drivers/i2c/busses/i2c-hix5hd2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/i2c/busses/i2c-hix5hd2.c +1 -2
@@ -464,8 +464,7 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev)hix5hd2_i2c_init (priv); ret =devm_request_irq (&pdev->dev, irq, hix5hd2_i2c_irq, -IRQF_NO_SUSPEND |IRQF_ONESHOT , -dev_name (&pdev->dev), priv); +IRQF_NO_SUSPEND ,dev_name (&pdev->dev), priv);if (ret !=0 ) {dev_err (&pdev->dev,"cannot request HS-I2C IRQ %d\n" , irq); goto err_clk;
Signature · 1 line
2.14.1
PATCH 4/23 x86: preempt: Check preemption level before looking at lazy-preempt
In reply to [email protected]From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 19fc8557f2323c52b26561651ed4d51fc688a740 ]
Before evaluating the lazy-preempt state it must be ensure that the preempt-count is zero.
--- arch/x86/include/asm/preempt.h | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/include/asm/preempt.h +2 -0
@@ -96,6 +96,8 @@ static __always_inline bool __preempt_count_dec_and_test(void)if (____preempt_count_dec_and_test ())return true;#ifdef CONFIG_PREEMPT_LAZY +if (preempt_count ()) +return false;if (current_thread_info ()->preempt_lazy_count)return false;return test_thread_flag (TIF_NEED_RESCHED_LAZY );
Signature · 1 line
2.14.1
PATCH 5/23 sched: migrate_dis/enable: Use sleeping_lock…() to annotate sleeping points
In reply to [email protected]From: Scott Wood <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 4230dd3824c3e1785504e6f757ce79a4b55651fa ]
Without this, rcu_note_context_switch() will complain if an RCU read lock is held when migrate_enable() calls stop_one_cpu(). Likewise when migrate_disable() calls pin_current_cpu() which calls __read_rt_lock() -- which bypasses the part of the mutex code that calls sleeping_lock_inc().
Conflicts:
kernel/sched/core.c
--- kernel/cpu.c | 2 ++ kernel/sched/core.c | 3 +++ 2 files changed, 5 insertions(+)
kernel/cpu.c +2 -0
@@ -314,7 +314,9 @@ void pin_current_cpu(void)preempt_lazy_enable ();preempt_enable (); +sleeping_lock_inc ();__read_rt_lock (cpuhp_pin); +sleeping_lock_dec ();preempt_disable ();preempt_lazy_disable ();
kernel/sched/core.c +3 -0
@@ -7045,7 +7045,10 @@ void migrate_enable(void)unpin_current_cpu ();preempt_lazy_enable ();preempt_enable (); + +sleeping_lock_inc ();stop_one_cpu (task_cpu (p), migration_cpu_stop, &arg); +sleeping_lock_dec ();tlb_migrate_finish (p->mm);return ;
Signature · 1 line
2.14.1
PATCH 6/23 sched: __set_cpus_allowed_ptr: Check cpus_mask, not cpus_ptr
In reply to [email protected]From: Scott Wood <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit e5606fb7b042db634ed62b4dd733d62e050e468f ]
This function is concerned with the long-term cpu mask, not the transitory mask the task might have while migrate disabled. Before this patch, if a task was migrate disabled at the time __set_cpus_allowed_ptr() was called, and the new mask happened to be equal to the cpu that the task was running on, then the mask update would be lost.
--- kernel/sched/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/core.c +1 -1
@@ -1192,7 +1192,7 @@ static int __set_cpus_allowed_ptr(struct task_struct *p, goto out; } -if (cpumask_equal (p->cpus_ptr, new_mask)) +if (cpumask_equal (&p->cpus_mask, new_mask)) goto out; dest_cpu =cpumask_any_and (cpu_valid_mask, new_mask);
Signature · 1 line
2.14.1
PATCH 7/23 sched: Remove dead __migrate_disabled() check
In reply to [email protected]From: Scott Wood <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 14d9272d534ea91262e15db99443fc5995c7c016 ]
This code was unreachable given the __migrate_disabled() branch to "out" immediately beforehand.
Conflicts:
kernel/sched/core.c
--- kernel/sched/core.c | 7 ------- 1 file changed, 7 deletions(-)
kernel/sched/core.c +0 -7
@@ -1217,13 +1217,6 @@ static int __set_cpus_allowed_ptr(struct task_struct *p,if (cpumask_test_cpu (task_cpu (p), new_mask) ||__migrate_disabled (p)) goto out; -#if defined(CONFIG_SMP ) && defined(CONFIG_PREEMPT_RT_BASE ) -if (__migrate_disabled (p)) { - p->migrate_disable_update =1 ; - goto out; - } -#endif -if (task_running (rq, p) || p->state ==TASK_WAKING ) {struct migration_arg arg = { p, dest_cpu };/* Need help from migration thread: drop lock and wait. */
Signature · 1 line
2.14.1
PATCH 8/23 sched: migrate disable: Protect cpus_ptr with lock
In reply to [email protected]From: Scott Wood <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 27ee52a891ed2c7e2e2c8332ccae0de7c2674b09 ]
Various places assume that cpus_ptr is protected by rq/pi locks, so don't change it before grabbing those locks.
--- kernel/sched/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
kernel/sched/core.c +2 -4
@@ -6923,9 +6923,8 @@ migrate_disable_update_cpus_allowed(struct task_struct *p)struct rq *rq;struct rq_flags rf; - p->cpus_ptr =cpumask_of (smp_processor_id ()); - rq =task_rq_lock (p, &rf); + p->cpus_ptr =cpumask_of (smp_processor_id ());update_nr_migratory (p,-1 ); p->nr_cpus_allowed =1 ;task_rq_unlock (rq, p, &rf);
@@ -6937,9 +6936,8 @@ migrate_enable_update_cpus_allowed(struct task_struct *p)struct rq *rq;struct rq_flags rf; - p->cpus_ptr = &p->cpus_mask; - rq =task_rq_lock (p, &rf); + p->cpus_ptr = &p->cpus_mask; p->nr_cpus_allowed =cpumask_weight (&p->cpus_mask);update_nr_migratory (p,1 );task_rq_unlock (rq, p, &rf);
Signature · 1 line
2.14.1
PATCH 9/23 lib/smp_processor_id: Don't use cpumask_equal()
In reply to [email protected]From: Waiman Long <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 659252061477862f45b79e1de169e6030f5c8918 ]
The check_preemption_disabled() function uses cpumask_equal() to see if the task is bounded to the current CPU only. cpumask_equal() calls memcmp() to do the comparison. As x86 doesn't have __HAVE_ARCH_MEMCMP, the slow memcmp() function in lib/string.c is used.
On a RT kernel that call check_preemption_disabled() very frequently, below is the perf-record output of a certain microbenchmark:
42.75% 2.45% testpmd [kernel.kallsyms] [k] check_preemption_disabled 40.01% 39.97% testpmd [kernel.kallsyms] [k] memcmp
We should avoid calling memcmp() in performance critical path. So the cpumask_equal() call is now replaced with an equivalent simpler check.
--- lib/smp_processor_id.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/smp_processor_id.c +1 -1
@@ -23,7 +23,7 @@ notrace static unsigned int check_preemption_disabled(const char *what1,* Kernel threads bound to a single CPU can safely use * smp_processor_id(): */ -if (cpumask_equal (current->cpus_ptr,cpumask_of (this_cpu))) +if (current->nr_cpus_allowed ==1 ) goto out;/*
Signature · 1 line
2.14.1
PATCH 10/23 futex: Make the futex_hash_bucket spinlock_t again and bring back its old state
In reply to [email protected]From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 954ad80c23edfe71f4e8ce70b961eac884320c3a ]
This is an all-in-one patch that reverts the patches:
futex: Make the futex_hash_bucket lock raw
futex: Delay deallocation of pi_state
and adds back the old patches we had:
futex: workaround migrate_disable/enable in different context
rtmutex: Handle the various new futex race conditions
futex: Fix bug on when a requeued RT task times out
futex: Ensure lock/unlock symetry versus pi_lock and hash bucket lock
Conflicts:
kernel/futex.c
--- kernel/futex.c | 231 +++++++++++++++++++++++----------------- kernel/locking/rtmutex.c | 65 +++++++++-- kernel/locking/rtmutex_common.h | 3 + 3 files changed, 194 insertions(+), 105 deletions(-)
kernel/futex.c +132 -99
@@ -243,7 +243,7 @@ struct futex_q {struct plist_node list;struct task_struct *task; -raw_spinlock_t *lock_ptr; +spinlock_t *lock_ptr;union futex_key key;struct futex_pi_state *pi_state;struct rt_mutex_waiter *rt_waiter;
@@ -264,7 +264,7 @@ static const struct futex_q futex_q_init = {*/ struct futex_hash_bucket {atomic_t waiters; -raw_spinlock_t lock; +spinlock_t lock;struct plist_head chain; }____cacheline_aligned_in_smp ;
@@ -831,13 +831,13 @@ static void get_pi_state(struct futex_pi_state *pi_state)* Drops a reference to the pi_state object and frees or caches it * when the last reference is gone. */ -static struct futex_pi_state *__put_pi_state (struct futex_pi_state *pi_state) +static void put_pi_state (struct futex_pi_state *pi_state) {if (!pi_state) -return NULL ; +return ;if (!atomic_dec_and_test (&pi_state->refcount)) -return NULL ; +return ;/* * If pi_state->owner is NULL, the owner is most probably dying
@@ -857,7 +857,9 @@ static struct futex_pi_state *__put_pi_state(struct futex_pi_state *pi_state)raw_spin_unlock_irq (&pi_state->pi_mutex.wait_lock); } -if (!current->pi_state_cache) { +if (current->pi_state_cache) { +kfree (pi_state); + }else {/* * pi_state->list is already empty. * clear pi_state->owner.
@@ -866,30 +868,6 @@ static struct futex_pi_state *__put_pi_state(struct futex_pi_state *pi_state) pi_state->owner =NULL ;atomic_set (&pi_state->refcount,1 ); current->pi_state_cache = pi_state; - pi_state =NULL ; - } -return pi_state; -} - -static void put_pi_state (struct futex_pi_state *pi_state) -{ -kfree (__put_pi_state (pi_state)); -} - -static void put_pi_state_atomic (struct futex_pi_state *pi_state, -struct list_head *to_free) -{ -if (__put_pi_state (pi_state)) -list_add (&pi_state->list, to_free); -} - -static void free_pi_state_list (struct list_head *to_free) -{ -struct futex_pi_state *p, *next; - -list_for_each_entry_safe (p, next, to_free, list) { -list_del (&p->list); -kfree (p); } }
@@ -924,7 +902,6 @@ static void exit_pi_state_list(struct task_struct *curr)struct futex_pi_state *pi_state;struct futex_hash_bucket *hb;union futex_key key =FUTEX_KEY_INIT ; -LIST_HEAD (to_free);if (!futex_cmpxchg_enabled)return ;
@@ -958,7 +935,7 @@ static void exit_pi_state_list(struct task_struct *curr) }raw_spin_unlock_irq (&curr->pi_lock); -raw_spin_lock (&hb->lock); +spin_lock (&hb->lock);raw_spin_lock_irq (&pi_state->pi_mutex.wait_lock);raw_spin_lock (&curr->pi_lock);/*
@@ -968,8 +945,10 @@ static void exit_pi_state_list(struct task_struct *curr)if (head->next != next) {/* retain curr->pi_lock for the loop invariant */ raw_spin_unlock (&pi_state->pi_mutex.wait_lock); -raw_spin_unlock (&hb->lock); -put_pi_state_atomic (pi_state, &to_free); +raw_spin_unlock_irq (&curr->pi_lock); +spin_unlock (&hb->lock); +raw_spin_lock_irq (&curr->pi_lock); +put_pi_state (pi_state);continue ; }
@@ -980,7 +959,7 @@ static void exit_pi_state_list(struct task_struct *curr)raw_spin_unlock (&curr->pi_lock);raw_spin_unlock_irq (&pi_state->pi_mutex.wait_lock); -raw_spin_unlock (&hb->lock); +spin_unlock (&hb->lock);rt_mutex_futex_unlock (&pi_state->pi_mutex);put_pi_state (pi_state);
@@ -988,8 +967,6 @@ static void exit_pi_state_list(struct task_struct *curr) raw_spin_lock_irq(&curr->pi_lock); }raw_spin_unlock_irq (&curr->pi_lock); - -free_pi_state_list (&to_free); }#else static inline void exit_pi_state_list (struct task_struct *curr) { }
@@ -1530,7 +1507,7 @@ static void __unqueue_futex(struct futex_q *q) {struct futex_hash_bucket *hb; -if (WARN_ON_SMP (!q->lock_ptr || !raw_spin_is_locked (q->lock_ptr)) +if (WARN_ON_SMP (!q->lock_ptr || !spin_is_locked (q->lock_ptr)) ||WARN_ON (plist_node_empty (&q->list)))return ;
@@ -1658,21 +1635,21 @@ static inline void double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2) {if (hb1 <= hb2) { -raw_spin_lock (&hb1->lock); +spin_lock (&hb1->lock);if (hb1 < hb2) -raw_spin_lock_nested (&hb2->lock,SINGLE_DEPTH_NESTING ); +spin_lock_nested (&hb2->lock,SINGLE_DEPTH_NESTING ); }else {/* hb1 > hb2 */ -raw_spin_lock (&hb2->lock); -raw_spin_lock_nested (&hb1->lock,SINGLE_DEPTH_NESTING ); +spin_lock (&hb2->lock); +spin_lock_nested (&hb1->lock,SINGLE_DEPTH_NESTING ); } }static inline void double_unlock_hb (struct futex_hash_bucket *hb1,struct futex_hash_bucket *hb2) { -raw_spin_unlock (&hb1->lock); +spin_unlock (&hb1->lock);if (hb1 != hb2) -raw_spin_unlock (&hb2->lock); +spin_unlock (&hb2->lock); }/*
@@ -1700,7 +1677,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)if (!hb_waiters_pending (hb)) goto out_put_key; -raw_spin_lock (&hb->lock); +spin_lock (&hb->lock);plist_for_each_entry_safe (this, next, &hb->chain, list) {if (match_futex (&this->key, &key)) {
@@ -1719,7 +1696,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) } } -raw_spin_unlock (&hb->lock); +spin_unlock (&hb->lock);wake_up_q (&wake_q); out_put_key:put_futex_key (&key);
@@ -2032,7 +2009,6 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,struct futex_hash_bucket *hb1, *hb2;struct futex_q *this, *next;DEFINE_WAKE_Q (wake_q); -LIST_HEAD (to_free);if (nr_wake <0 || nr_requeue <0 )return -EINVAL ;
@@ -2271,6 +2247,16 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,requeue_pi_wake_futex (this, &key2, hb2); drop_count++;continue ; + }else if (ret == -EAGAIN ) { +/* +* Waiter was woken by timeout or +* signal and has set pi_blocked_on to +* PI_WAKEUP_INPROGRESS before we +* tried to enqueue it on the rtmutex. +*/ + this->pi_state =NULL ; +put_pi_state (pi_state); +continue ; }else if (ret) {/* * rt_mutex_start_proxy_lock() detected a
@@ -2281,7 +2267,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,* object. */ this->pi_state =NULL ; -put_pi_state_atomic (pi_state, &to_free); +put_pi_state (pi_state);/* * We stop queueing more waiters and let user * space deal with the mess.
@@ -2298,7 +2284,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,* in futex_proxy_trylock_atomic() or in lookup_pi_state(). We * need to drop it here again. */ -put_pi_state_atomic (pi_state, &to_free); +put_pi_state (pi_state); out_unlock:double_unlock_hb (hb1, hb2);
@@ -2319,7 +2305,6 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, out_put_key1:put_futex_key (&key1); out: -free_pi_state_list (&to_free);return ret ? ret : task_count; }
@@ -2343,8 +2328,7 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q) q->lock_ptr = &hb->lock; -raw_spin_lock (&hb->lock); - +spin_lock (&hb->lock);return hb; }
@@ -2352,7 +2336,7 @@ static inline void queue_unlock(struct futex_hash_bucket *hb) __releases(&hb->lock) { -raw_spin_unlock (&hb->lock); +spin_unlock (&hb->lock);hb_waiters_dec (hb); }
@@ -2391,7 +2375,7 @@ static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb) __releases(&hb->lock) {__queue_me (q, hb); -raw_spin_unlock (&hb->lock); +spin_unlock (&hb->lock); }/**
@@ -2407,41 +2391,41 @@ static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb)*/ static int unqueue_me (struct futex_q *q) { -raw_spinlock_t *lock_ptr; +spinlock_t *lock_ptr;int ret =0 ;/* In the common case we don't take the spinlock, which is nice. */ retry:/* -* q->lock_ptr can change between this read and the following -* raw_spin_lock. Use READ_ONCE to forbid the compiler from reloading -* q->lock_ptr and optimizing lock_ptr out of the logic below. +* q->lock_ptr can change between this read and the following spin_lock. +* Use READ_ONCE to forbid the compiler from reloading q->lock_ptr and +* optimizing lock_ptr out of the logic below. */ lock_ptr =READ_ONCE (q->lock_ptr);if (lock_ptr !=NULL ) { -raw_spin_lock (lock_ptr); +spin_lock (lock_ptr);/* * q->lock_ptr can change between reading it and -* raw_spin_lock(), causing us to take the wrong lock. This +* spin_lock(), causing us to take the wrong lock. This * corrects the race condition. * * Reasoning goes like this: if we have the wrong lock, * q->lock_ptr must have changed (maybe several times) -* between reading it and the raw_spin_lock(). It can -* change again after the raw_spin_lock() but only if it was -* already changed before the raw_spin_lock(). It cannot, +* between reading it and the spin_lock(). It can +* change again after the spin_lock() but only if it was +* already changed before the spin_lock(). It cannot, * however, change back to the original value. Therefore * we can detect whether we acquired the correct lock. */ if (unlikely (lock_ptr != q->lock_ptr)) { -raw_spin_unlock (lock_ptr); +spin_unlock (lock_ptr); goto retry; }__unqueue_futex (q);BUG_ON (q->pi_state); -raw_spin_unlock (lock_ptr); +spin_unlock (lock_ptr); ret =1 ; }
@@ -2457,16 +2441,13 @@ static int unqueue_me(struct futex_q *q)static void unqueue_me_pi (struct futex_q *q) __releases(q->lock_ptr) { -struct futex_pi_state *ps; -__unqueue_futex (q);BUG_ON (!q->pi_state); - ps =__put_pi_state (q->pi_state); +put_pi_state (q->pi_state); q->pi_state =NULL ; -raw_spin_unlock (q->lock_ptr); -kfree (ps); +spin_unlock (q->lock_ptr); } static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
@@ -2599,7 +2580,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,*/ handle_err:raw_spin_unlock_irq (&pi_state->pi_mutex.wait_lock); -raw_spin_unlock (q->lock_ptr); +spin_unlock (q->lock_ptr);switch (err) {case -EFAULT :
@@ -2617,7 +2598,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,break ; } -raw_spin_lock (q->lock_ptr); +spin_lock (q->lock_ptr);raw_spin_lock_irq (&pi_state->pi_mutex.wait_lock);/*
@@ -2713,7 +2694,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,/* * The task state is guaranteed to be set before another task can * wake it. set_current_state() is implemented using smp_store_mb() and -* queue_me() calls raw_spin_unlock() upon completion, both serializing +* queue_me() calls spin_unlock() upon completion, both serializing * access to the hash list and forcing another memory barrier. */ set_current_state (TASK_INTERRUPTIBLE );
@@ -3013,7 +2994,15 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,* before __rt_mutex_start_proxy_lock() is done. */ raw_spin_lock_irq (&q.pi_state->pi_mutex.wait_lock); -raw_spin_unlock (q.lock_ptr); +/* +* the migrate_disable() here disables migration in the in_atomic() fast +* path which is enabled again in the following spin_unlock(). We have +* one migrate_disable() pending in the slow-path which is reversed +* after the raw_spin_unlock_irq() where we leave the atomic context. +*/ +migrate_disable (); + +spin_unlock (q.lock_ptr);/* * __rt_mutex_start_proxy_lock() unconditionally enqueues the @rt_waiter * such that futex_unlock_pi() is guaranteed to observe the waiter when
@@ -3021,6 +3010,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,*/ ret =__rt_mutex_start_proxy_lock (&q.pi_state->pi_mutex, &rt_waiter, current);raw_spin_unlock_irq (&q.pi_state->pi_mutex.wait_lock); +migrate_enable ();if (ret) {if (ret ==1 )
@@ -3034,7 +3024,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ret =rt_mutex_wait_proxy_lock (&q.pi_state->pi_mutex, to, &rt_waiter); cleanup: -raw_spin_lock (q.lock_ptr); +spin_lock (q.lock_ptr);/* * If we failed to acquire the lock (deadlock/signal/timeout), we must * first acquire the hb->lock before removing the lock from the
@@ -3135,7 +3125,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)return ret; hb =hash_futex (&key); -raw_spin_lock (&hb->lock); +spin_lock (&hb->lock);/* * Check waiters first. We do not trust user space values at
@@ -3169,10 +3159,19 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)* rt_waiter. Also see the WARN in wake_futex_pi(). */ raw_spin_lock_irq (&pi_state->pi_mutex.wait_lock); -raw_spin_unlock (&hb->lock); +/* +* Magic trickery for now to make the RT migrate disable +* logic happy. The following spin_unlock() happens with +* interrupts disabled so the internal migrate_enable() +* won't undo the migrate_disable() which was issued when +* locking hb->lock. +*/ +migrate_disable (); +spin_unlock (&hb->lock);/* drops pi_state->pi_mutex.wait_lock */ ret =wake_futex_pi (uaddr, uval, pi_state); +migrate_enable ();put_pi_state (pi_state);
@@ -3208,7 +3207,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)* owner. */ if ((ret =cmpxchg_futex_value_locked (&curval, uaddr, uval,0 ))) { -raw_spin_unlock (&hb->lock); +spin_unlock (&hb->lock);switch (ret) {case -EFAULT : goto pi_faulted;
@@ -3228,7 +3227,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags) ret = (curval == uval) ?0 : -EAGAIN ; out_unlock: -raw_spin_unlock (&hb->lock); +spin_unlock (&hb->lock); out_putkey:put_futex_key (&key);return ret;
@@ -3344,7 +3343,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,struct hrtimer_sleeper timeout, *to =NULL ;struct futex_pi_state *pi_state =NULL ;struct rt_mutex_waiter rt_waiter; -struct futex_hash_bucket *hb; +struct futex_hash_bucket *hb, *hb2;union futex_key key2 =FUTEX_KEY_INIT ;struct futex_q q = futex_q_init;int res, ret;
@@ -3402,20 +3401,55 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,/* Queue the futex_q, drop the hb lock, wait for wakeup. */ futex_wait_queue_me (hb, &q, to); -raw_spin_lock (&hb->lock); - ret =handle_early_requeue_pi_wakeup (hb, &q, &key2, to); -raw_spin_unlock (&hb->lock); -if (ret) - goto out_put_keys; +/* +* On RT we must avoid races with requeue and trying to block +* on two mutexes (hb->lock and uaddr2's rtmutex) by +* serializing access to pi_blocked_on with pi_lock. +*/ +raw_spin_lock_irq (¤t->pi_lock); +if (current->pi_blocked_on) { +/* +* We have been requeued or are in the process of +* being requeued. +*/ +raw_spin_unlock_irq (¤t->pi_lock); + }else { +/* +* Setting pi_blocked_on to PI_WAKEUP_INPROGRESS +* prevents a concurrent requeue from moving us to the +* uaddr2 rtmutex. After that we can safely acquire +* (and possibly block on) hb->lock. +*/ + current->pi_blocked_on =PI_WAKEUP_INPROGRESS ; +raw_spin_unlock_irq (¤t->pi_lock); + +spin_lock (&hb->lock); + +/* +* Clean up pi_blocked_on. We might leak it otherwise +* when we succeeded with the hb->lock in the fast +* path. +*/ +raw_spin_lock_irq (¤t->pi_lock); + current->pi_blocked_on =NULL ; +raw_spin_unlock_irq (¤t->pi_lock); + + ret =handle_early_requeue_pi_wakeup (hb, &q, &key2, to); +spin_unlock (&hb->lock); +if (ret) + goto out_put_keys; + }/* -* In order for us to be here, we know our q.key == key2, and since -* we took the hb->lock above, we also know that futex_requeue() has -* completed and we no longer have to concern ourselves with a wakeup -* race with the atomic proxy lock acquisition by the requeue code. The -* futex_requeue dropped our key1 reference and incremented our key2 -* reference count. +* In order to be here, we have either been requeued, are in +* the process of being requeued, or requeue successfully +* acquired uaddr2 on our behalf. If pi_blocked_on was +* non-null above, we may be racing with a requeue. Do not +* rely on q->lock_ptr to be hb2->lock until after blocking on +* hb->lock or hb2->lock. The futex_requeue dropped our key1 +* reference and incremented our key2 reference count. */ + hb2 =hash_futex (&key2);/* Check if the requeue code acquired the second futex for us. */ if (!q.rt_waiter) {
@@ -3424,9 +3458,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,* did a lock-steal - fix up the PI-state in that case. */ if (q.pi_state && (q.pi_state->owner != current)) { -struct futex_pi_state *ps_free; - -raw_spin_lock (q.lock_ptr); +spin_lock (&hb2->lock); +BUG_ON (&hb2->lock != q.lock_ptr); ret =fixup_pi_state_owner (uaddr2, &q, current);if (ret &&rt_mutex_owner (&q.pi_state->pi_mutex) == current) { pi_state = q.pi_state;
@@ -3436,9 +3469,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,* Drop the reference to the pi state which * the requeue_pi() code acquired for us. */ - ps_free =__put_pi_state (q.pi_state); -raw_spin_unlock (q.lock_ptr); -kfree (ps_free); +put_pi_state (q.pi_state); +spin_unlock (&hb2->lock); } }else {struct rt_mutex *pi_mutex;
@@ -3452,7 +3484,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, pi_mutex = &q.pi_state->pi_mutex; ret =rt_mutex_wait_proxy_lock (pi_mutex, to, &rt_waiter); -raw_spin_lock (q.lock_ptr); +spin_lock (&hb2->lock); +BUG_ON (&hb2->lock != q.lock_ptr);if (ret && !rt_mutex_cleanup_proxy_lock (pi_mutex, &rt_waiter)) ret =0 ;
@@ -4225,7 +4258,7 @@ static int __init futex_init(void)for (i =0 ; i < futex_hashsize; i++) {atomic_set (&futex_queues[i].waiters,0 );plist_head_init (&futex_queues[i].chain); -raw_spin_lock_init (&futex_queues[i].lock); +spin_lock_init (&futex_queues[i].lock); }return 0 ;
kernel/locking/rtmutex.c +59 -6
119 lines not on this page · raw message
kernel/locking/rtmutex_common.h +3 -0
@@ -131,6 +131,9 @@ enum rtmutex_chainwalk {/* * PI-futex support (proxy locking functions, etc.): */ +#define PI_WAKEUP_INPROGRESS ((struct rt_mutex_waiter *) 1) +#define PI_REQUEUE_INPROGRESS ((struct rt_mutex_waiter *) 2) +extern struct task_struct *rt_mutex_next_owner (struct rt_mutex *lock);extern void rt_mutex_init_proxy_locked (struct rt_mutex *lock,struct task_struct *proxy_owner);
Signature · 1 line
2.14.1
PATCH 11/23 locking/rtmutex: Clean ->pi_blocked_on in the error case
In reply to [email protected]From: Peter Zijlstra <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 0be4ea6e3ce693101be0fbd55a0cc7ce238ab2eb ]
The function rt_mutex_wait_proxy_lock() cleans ->pi_blocked_on in case of failure (timeout, signal). The same cleanup is required in __rt_mutex_start_proxy_lock().
In both the cases the tasks was interrupted by a signal or timeout while acquiring the lock and after the interruption it longer blocks on the lock.
--- kernel/locking/rtmutex.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-)
kernel/locking/rtmutex.c +25 -18
@@ -2328,6 +2328,26 @@ void rt_mutex_proxy_unlock(struct rt_mutex *lock,rt_mutex_set_owner (lock,NULL ); } +static void fixup_rt_mutex_blocked (struct rt_mutex *lock) +{ +struct task_struct *tsk = current; +/* +* RT has a problem here when the wait got interrupted by a timeout +* or a signal. task->pi_blocked_on is still set. The task must +* acquire the hash bucket lock when returning from this function. +* +* If the hash bucket lock is contended then the +* BUG_ON(rt_mutex_real_waiter(task->pi_blocked_on)) in +* task_blocks_on_rt_mutex() will trigger. This can be avoided by +* clearing task->pi_blocked_on which removes the task from the +* boosting chain of the rtmutex. That's correct because the task +* is not longer blocked on it. +*/ +raw_spin_lock (&tsk->pi_lock); + tsk->pi_blocked_on =NULL ; +raw_spin_unlock (&tsk->pi_lock); +} +/** * __rt_mutex_start_proxy_lock() - Start lock acquisition for another task * @lock: the rt_mutex to take
@@ -2400,6 +2420,9 @@ int __rt_mutex_start_proxy_lock(struct rt_mutex *lock, ret =0 ; } +if (ret) +fixup_rt_mutex_blocked (lock); +debug_rt_mutex_print_deadlock (waiter);return ret;
@@ -2480,7 +2503,6 @@ int rt_mutex_wait_proxy_lock(struct rt_mutex *lock,struct hrtimer_sleeper *to, struct rt_mutex_waiter *waiter) { - struct task_struct *tsk = current; int ret;raw_spin_lock_irq (&lock->wait_lock);
@@ -2492,23 +2514,8 @@ int rt_mutex_wait_proxy_lock(struct rt_mutex *lock,* have to fix that up. */ fixup_rt_mutex_waiters (lock); -/* -* RT has a problem here when the wait got interrupted by a timeout -* or a signal. task->pi_blocked_on is still set. The task must -* acquire the hash bucket lock when returning from this function. -* -* If the hash bucket lock is contended then the -* BUG_ON(rt_mutex_real_waiter(task->pi_blocked_on)) in -* task_blocks_on_rt_mutex() will trigger. This can be avoided by -* clearing task->pi_blocked_on which removes the task from the -* boosting chain of the rtmutex. That's correct because the task -* is not longer blocked on it. -*/ -if (ret) { -raw_spin_lock (&tsk->pi_lock); - tsk->pi_blocked_on =NULL ; -raw_spin_unlock (&tsk->pi_lock); - } +if (ret) +fixup_rt_mutex_blocked (lock);raw_spin_unlock_irq (&lock->wait_lock);
Signature · 1 line
2.14.1
PATCH 12/23 lib/ubsan: Don't seralize UBSAN report
In reply to [email protected]From: Julien Grall <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commmit 4702c28ac777b27acb499cbd5e8e787ce1a7d82d ]
At the moment, UBSAN report will be serialized using a spin_lock(). On RT-systems, spinlocks are turned to rt_spin_lock and may sleep. This will result to the following splat if the undefined behavior is in a context that can sleep:
| BUG: sleeping function called from invalid context at /src/linux/kernel/locking/rtmutex.c:968
| in_atomic(): 1, irqs_disabled(): 128, pid: 3447, name: make
| 1 lock held by make/3447:
| #0: 000000009a966332 (&mm->mmap_sem){++++}, at: do_page_fault+0x140/0x4f8
| Preemption disabled at:
| [<ffff000011324a4c>] rt_mutex_futex_unlock+0x4c/0xb0
| CPU: 3 PID: 3447 Comm: make Tainted: G W 5.2.14-rt7-01890-ge6e057589653 #911
| Call trace:
| dump_backtrace+0x0/0x148
| show_stack+0x14/0x20
| dump_stack+0xbc/0x104
| ___might_sleep+0x154/0x210
| rt_spin_lock+0x68/0xa0
| ubsan_prologue+0x30/0x68
| handle_overflow+0x64/0xe0
| __ubsan_handle_add_overflow+0x10/0x18
| __lock_acquire+0x1c28/0x2a28
| lock_acquire+0xf0/0x370
| _raw_spin_lock_irqsave+0x58/0x78
| rt_mutex_futex_unlock+0x4c/0xb0
| rt_spin_unlock+0x28/0x70
| get_page_from_freelist+0x428/0x2b60
| __alloc_pages_nodemask+0x174/0x1708
| alloc_pages_vma+0x1ac/0x238
| __handle_mm_fault+0x4ac/0x10b0
| handle_mm_fault+0x1d8/0x3b0
| do_page_fault+0x1c8/0x4f8
| do_translation_fault+0xb8/0xe0
| do_mem_abort+0x3c/0x98
| el0_da+0x20/0x24The spin_lock() will protect against multiple CPUs to output a report together, I guess to prevent them to be interleaved. However, they can still interleave with other messages (and even splat from __migth_sleep).
So the lock usefulness seems pretty limited. Rather than trying to accomodate RT-system by switching to a raw_spin_lock(), the lock is now completely dropped.
Conflicts:
lib/ubsan.c
--- lib/ubsan.c | 76 ++++++++++++++++++++++--------------------------------------- 1 file changed, 27 insertions(+), 49 deletions(-)
lib/ubsan.c +27 -49
@@ -147,26 +147,21 @@ static bool location_is_valid(struct source_location *loc) {return loc->file_name !=NULL ; } - -static DEFINE_SPINLOCK (report_lock); - -static void ubsan_prologue (struct source_location *location, -unsigned long *flags) +static void ubsan_prologue (struct source_location *location) { current->in_ubsan++; -spin_lock_irqsave (&report_lock, *flags);pr_err ("========================================" "========================================\n" );print_source_location ("UBSAN: Undefined behaviour in" , location); } -static void ubsan_epilogue (unsigned long *flags) +static void ubsan_epilogue (void ) {dump_stack ();pr_err ("========================================" "========================================\n" ); -spin_unlock_irqrestore (&report_lock, *flags); + current->in_ubsan--; }
@@ -175,14 +170,13 @@ static void handle_overflow(struct overflow_data *data, void *lhs, {struct type_descriptor *type = data->type; -unsigned long flags;char lhs_val_str[VALUE_LENGTH ];char rhs_val_str[VALUE_LENGTH ];if (suppress_report (&data->location))return ; -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);val_to_string (lhs_val_str,sizeof (lhs_val_str), type, lhs);val_to_string (rhs_val_str,sizeof (rhs_val_str), type, rhs);
@@ -194,7 +188,7 @@ static void handle_overflow(struct overflow_data *data, void *lhs, rhs_val_str, type->type_name); -ubsan_epilogue (&flags); +ubsan_epilogue (); } void __ubsan_handle_add_overflow(struct overflow_data *data,
@@ -222,20 +216,19 @@ EXPORT_SYMBOL(__ubsan_handle_mul_overflow);void __ubsan_handle_negate_overflow (struct overflow_data *data,void *old_val) { -unsigned long flags;char old_val_str[VALUE_LENGTH ];if (suppress_report (&data->location))return ; -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);val_to_string (old_val_str,sizeof (old_val_str), data->type, old_val);pr_err ("negation of %s cannot be represented in type %s:\n" , old_val_str, data->type->type_name); -ubsan_epilogue (&flags); +ubsan_epilogue (); }EXPORT_SYMBOL (__ubsan_handle_negate_overflow);
@@ -243,13 +236,12 @@ EXPORT_SYMBOL(__ubsan_handle_negate_overflow);void __ubsan_handle_divrem_overflow (struct overflow_data *data,void *lhs,void *rhs) { -unsigned long flags;char rhs_val_str[VALUE_LENGTH ];if (suppress_report (&data->location))return ; -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);val_to_string (rhs_val_str,sizeof (rhs_val_str), data->type, rhs);
@@ -259,58 +251,52 @@ void __ubsan_handle_divrem_overflow(struct overflow_data *data,else pr_err ("division by zero\n" ); -ubsan_epilogue (&flags); +ubsan_epilogue (); }EXPORT_SYMBOL (__ubsan_handle_divrem_overflow);static void handle_null_ptr_deref (struct type_mismatch_data_common *data) { -unsigned long flags; -if (suppress_report (data->location))return ; -ubsan_prologue (data->location, &flags); +ubsan_prologue (data->location);pr_err ("%s null pointer of type %s\n" , type_check_kinds[data->type_check_kind], data->type->type_name); -ubsan_epilogue (&flags); +ubsan_epilogue (); }static void handle_misaligned_access (struct type_mismatch_data_common *data,unsigned long ptr) { -unsigned long flags; -if (suppress_report (data->location))return ; -ubsan_prologue (data->location, &flags); +ubsan_prologue (data->location);pr_err ("%s misaligned address %p for type %s\n" , type_check_kinds[data->type_check_kind], (void *)ptr, data->type->type_name);pr_err ("which requires %ld byte alignment\n" , data->alignment); -ubsan_epilogue (&flags); +ubsan_epilogue (); }static void handle_object_size_mismatch (struct type_mismatch_data_common *data,unsigned long ptr) { -unsigned long flags; -if (suppress_report (data->location))return ; -ubsan_prologue (data->location, &flags); +ubsan_prologue (data->location);pr_err ("%s address %p with insufficient space\n" , type_check_kinds[data->type_check_kind], (void *) ptr);pr_err ("for an object of type %s\n" , data->type->type_name); -ubsan_epilogue (&flags); +ubsan_epilogue (); } static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
@@ -356,12 +342,10 @@ EXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1);void __ubsan_handle_nonnull_return (struct nonnull_return_data *data) { -unsigned long flags; -if (suppress_report (&data->location))return ; -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);pr_err ("null pointer returned from function declared to never return null\n" );
@@ -369,49 +353,46 @@ void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)print_source_location ("returns_nonnull attribute specified in" , &data->attr_location); -ubsan_epilogue (&flags); +ubsan_epilogue (); }EXPORT_SYMBOL (__ubsan_handle_nonnull_return);void __ubsan_handle_vla_bound_not_positive (struct vla_bound_data *data,void *bound) { -unsigned long flags;char bound_str[VALUE_LENGTH ];if (suppress_report (&data->location))return ; -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);val_to_string (bound_str,sizeof (bound_str), data->type, bound);pr_err ("variable length array bound value %s <= 0\n" , bound_str); -ubsan_epilogue (&flags); +ubsan_epilogue (); }EXPORT_SYMBOL (__ubsan_handle_vla_bound_not_positive);void __ubsan_handle_out_of_bounds (struct out_of_bounds_data *data,void *index) { -unsigned long flags;char index_str[VALUE_LENGTH ];if (suppress_report (&data->location))return ; -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);val_to_string (index_str,sizeof (index_str), data->index_type, index);pr_err ("index %s is out of range for type %s\n" , index_str, data->array_type->type_name); -ubsan_epilogue (&flags); +ubsan_epilogue (); }EXPORT_SYMBOL (__ubsan_handle_out_of_bounds);void __ubsan_handle_shift_out_of_bounds (struct shift_out_of_bounds_data *data,void *lhs,void *rhs) { -unsigned long flags;struct type_descriptor *rhs_type = data->rhs_type;struct type_descriptor *lhs_type = data->lhs_type;char rhs_str[VALUE_LENGTH ];
@@ -420,7 +401,7 @@ void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,if (suppress_report (&data->location))return ; -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);val_to_string (rhs_str,sizeof (rhs_str), rhs_type, rhs);val_to_string (lhs_str,sizeof (lhs_str), lhs_type, lhs);
@@ -443,18 +424,16 @@ void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data, lhs_str, rhs_str, lhs_type->type_name); -ubsan_epilogue (&flags); +ubsan_epilogue (); }EXPORT_SYMBOL (__ubsan_handle_shift_out_of_bounds);void __ubsan_handle_builtin_unreachable (struct unreachable_data *data) { -unsigned long flags; - -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);pr_err ("calling __builtin_unreachable()\n" ); -ubsan_epilogue (&flags); +ubsan_epilogue ();panic ("can't return from __builtin_unreachable()" ); }EXPORT_SYMBOL (__ubsan_handle_builtin_unreachable);
@@ -462,19 +441,18 @@ EXPORT_SYMBOL(__ubsan_handle_builtin_unreachable);void __ubsan_handle_load_invalid_value (struct invalid_value_data *data,void *val) { -unsigned long flags;char val_str[VALUE_LENGTH ];if (suppress_report (&data->location))return ; -ubsan_prologue (&data->location, &flags); +ubsan_prologue (&data->location);val_to_string (val_str,sizeof (val_str), data->type, val);pr_err ("load of value %s is not a valid value for type %s\n" , val_str, data->type->type_name); -ubsan_epilogue (&flags); +ubsan_epilogue (); }EXPORT_SYMBOL (__ubsan_handle_load_invalid_value);
Signature · 1 line
2.14.1
PATCH 13/23 kmemleak: Change the lock of kmemleak_object to raw_spinlock_t
In reply to [email protected]From: Liu Haitao <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 217847f57119b5fdd377bfa3d344613ddb98d9fc ]
The commit ("kmemleak: Turn kmemleak_lock to raw spinlock on RT") changed the kmemleak_lock to raw spinlock. However the kmemleak_object->lock is held after the kmemleak_lock is held in scan_block().
Make the object->lock a raw_spinlock_t.
--- mm/kmemleak.c | 72 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 36 deletions(-)
mm/kmemleak.c +36 -36
@@ -148,7 +148,7 @@ struct kmemleak_scan_area {* (use_count) and freed using the RCU mechanism. */ struct kmemleak_object { -spinlock_t lock; +raw_spinlock_t lock;unsigned int flags;/* object status flags */ struct list_head object_list;struct list_head gray_list;
@@ -562,7 +562,7 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,INIT_LIST_HEAD (&object->object_list);INIT_LIST_HEAD (&object->gray_list);INIT_HLIST_HEAD (&object->area_list); -spin_lock_init (&object->lock); +raw_spin_lock_init (&object->lock);atomic_set (&object->use_count,1 ); object->flags =OBJECT_ALLOCATED ; object->pointer = ptr;
@@ -643,9 +643,9 @@ static void __delete_object(struct kmemleak_object *object)* Locking here also ensures that the corresponding memory block * cannot be freed when it is being scanned. */ -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags); object->flags &= ~OBJECT_ALLOCATED ; -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags);put_object (object); }
@@ -717,9 +717,9 @@ static void paint_it(struct kmemleak_object *object, int color) {unsigned long flags; -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);__paint_it (object, color); -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags); }static void paint_ptr (unsigned long ptr,int color)
@@ -779,7 +779,7 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp) goto out; } -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);if (size ==SIZE_MAX ) { size = object->pointer + object->size - ptr; }else if (ptr + size > object->pointer + object->size) {
@@ -795,7 +795,7 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp)hlist_add_head (&area->node, &object->area_list); out_unlock: -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags); out:put_object (object); }
@@ -818,9 +818,9 @@ static void object_set_excess_ref(unsigned long ptr, unsigned long excess_ref)return ; } -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags); object->excess_ref = excess_ref; -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags);put_object (object); }
@@ -840,9 +840,9 @@ static void object_no_scan(unsigned long ptr)return ; } -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags); object->flags |=OBJECT_NO_SCAN ; -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags);put_object (object); }
@@ -903,11 +903,11 @@ static void early_alloc(struct early_log *log) log->min_count, GFP_ATOMIC);if (!object) goto out; -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);for (i =0 ; i < log->trace_len; i++) object->trace[i] = log->trace[i]; object->trace_len = log->trace_len; -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags); out:rcu_read_unlock (); }
@@ -1097,9 +1097,9 @@ void __ref kmemleak_update_trace(const void *ptr)return ; } -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags); object->trace_len =__save_stack_trace (object->trace); -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags);put_object (object); }
@@ -1335,7 +1335,7 @@ static void scan_block(void *_start, void *_end,* previously acquired in scan_object(). These locks are * enclosed by scan_mutex. */ -spin_lock_nested (&object->lock,SINGLE_DEPTH_NESTING ); +raw_spin_lock_nested (&object->lock,SINGLE_DEPTH_NESTING );/* only pass surplus references (object already gray) */ if (color_gray (object)) { excess_ref = object->excess_ref;
@@ -1344,7 +1344,7 @@ static void scan_block(void *_start, void *_end, excess_ref =0 ;update_refs (object); } -spin_unlock (&object->lock); +raw_spin_unlock (&object->lock);if (excess_ref) { object =lookup_object (excess_ref,0 );
@@ -1353,9 +1353,9 @@ static void scan_block(void *_start, void *_end,if (object == scanned)/* circular reference, ignore */ continue ; -spin_lock_nested (&object->lock,SINGLE_DEPTH_NESTING ); +raw_spin_lock_nested (&object->lock,SINGLE_DEPTH_NESTING );update_refs (object); -spin_unlock (&object->lock); +raw_spin_unlock (&object->lock); } }raw_spin_unlock_irqrestore (&kmemleak_lock, flags);
@@ -1391,7 +1391,7 @@ static void scan_object(struct kmemleak_object *object)* Once the object->lock is acquired, the corresponding memory block * cannot be freed (the same lock is acquired in delete_object). */ -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);if (object->flags &OBJECT_NO_SCAN ) goto out;if (!(object->flags &OBJECT_ALLOCATED ))
@@ -1410,9 +1410,9 @@ static void scan_object(struct kmemleak_object *object)if (start >= end)break ; -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags);cond_resched (); -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags); }while (object->flags &OBJECT_ALLOCATED ); }else hlist_for_each_entry (area, &object->area_list, node)
@@ -1420,7 +1420,7 @@ static void scan_object(struct kmemleak_object *object) (void *)(area->start + area->size), object); out: -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags); }/*
@@ -1473,7 +1473,7 @@ static void kmemleak_scan(void)/* prepare the kmemleak_object's */ rcu_read_lock ();list_for_each_entry_rcu (object, &object_list, object_list) { -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);#ifdef DEBUG /* * With a few exceptions there should be a maximum of
@@ -1490,7 +1490,7 @@ static void kmemleak_scan(void)if (color_gray (object) &&get_object (object))list_add_tail (&object->gray_list, &gray_list); -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags); }rcu_read_unlock ();
@@ -1555,14 +1555,14 @@ static void kmemleak_scan(void)*/ rcu_read_lock ();list_for_each_entry_rcu (object, &object_list, object_list) { -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);if (color_white (object) && (object->flags &OBJECT_ALLOCATED ) &&update_checksum (object) &&get_object (object)) {/* color it gray temporarily */ object->count = object->min_count;list_add_tail (&object->gray_list, &gray_list); } -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags); }rcu_read_unlock ();
@@ -1582,13 +1582,13 @@ static void kmemleak_scan(void)*/ rcu_read_lock ();list_for_each_entry_rcu (object, &object_list, object_list) { -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);if (unreferenced_object (object) && !(object->flags &OBJECT_REPORTED )) { object->flags |=OBJECT_REPORTED ; new_leaks++; } -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags); }rcu_read_unlock ();
@@ -1740,10 +1740,10 @@ static int kmemleak_seq_show(struct seq_file *seq, void *v)struct kmemleak_object *object = v;unsigned long flags; -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);if ((object->flags &OBJECT_REPORTED ) &&unreferenced_object (object))print_unreferenced (seq, object); -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags);return 0 ; }
@@ -1773,9 +1773,9 @@ static int dump_str_object_info(const char *str)return -EINVAL ; } -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);dump_object_info (object); -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags);put_object (object);return 0 ;
@@ -1794,11 +1794,11 @@ static void kmemleak_clear(void)rcu_read_lock ();list_for_each_entry_rcu (object, &object_list, object_list) { -spin_lock_irqsave (&object->lock, flags); +raw_spin_lock_irqsave (&object->lock, flags);if ((object->flags &OBJECT_REPORTED ) &&unreferenced_object (object))__paint_it (object,KMEMLEAK_GREY ); -spin_unlock_irqrestore (&object->lock, flags); +raw_spin_unlock_irqrestore (&object->lock, flags); }rcu_read_unlock ();
Signature · 1 line
2.14.1
PATCH 14/23 Revert "ARM: Initialize split page table locks for vector page"
In reply to [email protected]From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 247074c44d8c3e619dfde6404a52295d8d671d38 ]
I'm dropping this patch, with its original description:
|ARM: Initialize split page table locks for vector page | |Without this patch, ARM can not use SPLIT_PTLOCK_CPUS if |PREEMPT_RT_FULL=y because vectors_user_mapping() creates a |VM_ALWAYSDUMP mapping of the vector page (address 0xffff0000), but no |ptl->lock has been allocated for the page. An attempt to coredump |that page will result in a kernel NULL pointer dereference when |follow_page() attempts to lock the page. | |The call tree to the NULL pointer dereference is: | | do_notify_resume() | get_signal_to_deliver() | do_coredump() | elf_core_dump() | get_dump_page() | __get_user_pages() | follow_page() | pte_offset_map_lock() <----- a #define | ... | rt_spin_lock() | |The underlying problem is exposed by mm-shrink-the-page-frame-to-rt-size.patch.
The patch named mm-shrink-the-page-frame-to-rt-size.patch was dropped from the RT queue once the SPLIT_PTLOCK_CPUS feature (in a slightly different shape) went upstream (somewhere between v3.12 and v3.14).
I can see that the patch still allocates a lock which wasn't there before. However I can't trigger a kernel oops like described in the patch by triggering a coredump.
--- arch/arm/kernel/process.c | 24 ------------------------ 1 file changed, 24 deletions(-)
arch/arm/kernel/process.c +0 -24
@@ -325,30 +325,6 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) }#ifdef CONFIG_MMU -/* -* CONFIG_SPLIT_PTLOCK_CPUS results in a page->ptl lock. If the lock is not -* initialized by pgtable_page_ctor() then a coredump of the vector page will -* fail. -*/ -static int __init vectors_user_mapping_init_page (void ) -{ -struct page *page; -unsigned long addr =0xffff0000 ; -pgd_t *pgd; -pud_t *pud; -pmd_t *pmd; - - pgd =pgd_offset_k (addr); - pud =pud_offset (pgd, addr); - pmd =pmd_offset (pud, addr); - page =pmd_page (*(pmd)); - -pgtable_page_ctor (page); - -return 0 ; -} -late_initcall (vectors_user_mapping_init_page); -#ifdef CONFIG_KUSER_HELPERS /* * The vectors page is always readable from user space for the
Signature · 1 line
2.14.1
PATCH 15/23 locking: Make spinlock_t and rwlock_t a RCU section on RT
In reply to [email protected]From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 84440022a0e1c8c936d61f8f97593674a295d409 ]
On !RT a locked spinlock_t and rwlock_t disables preemption which implies a RCU read section. There is code that relies on that behaviour.
Add an explicit RCU read section on RT while a sleeping lock (a lock which would disables preemption on !RT) acquired.
--- kernel/locking/rtmutex.c | 6 ++++++ kernel/locking/rwlock-rt.c | 6 ++++++ 2 files changed, 12 insertions(+)
kernel/locking/rtmutex.c +6 -0
@@ -1142,6 +1142,7 @@ void __sched rt_spin_lock_slowunlock(struct rt_mutex *lock) void __lockfunc rt_spin_lock(spinlock_t *lock) {sleeping_lock_inc (); +rcu_read_lock ();migrate_disable ();spin_acquire (&lock->dep_map,0 ,0 , _RET_IP_);rt_spin_lock_fastlock (&lock->lock, rt_spin_lock_slowlock);
@@ -1157,6 +1158,7 @@ void __lockfunc __rt_spin_lock(struct rt_mutex *lock) void __lockfunc rt_spin_lock_nested(spinlock_t *lock, int subclass) {sleeping_lock_inc (); +rcu_read_lock ();migrate_disable ();spin_acquire (&lock->dep_map, subclass,0 , _RET_IP_);rt_spin_lock_fastlock (&lock->lock, rt_spin_lock_slowlock);
@@ -1170,6 +1172,7 @@ void __lockfunc rt_spin_unlock(spinlock_t *lock)spin_release (&lock->dep_map,1 , _RET_IP_);rt_spin_lock_fastunlock (&lock->lock, rt_spin_lock_slowunlock);migrate_enable (); +rcu_read_unlock ();sleeping_lock_dec (); }EXPORT_SYMBOL (rt_spin_unlock);
@@ -1201,6 +1204,7 @@ int __lockfunc rt_spin_trylock(spinlock_t *lock) ret =__rt_mutex_trylock (&lock->lock);if (ret) {spin_acquire (&lock->dep_map,0 ,1 , _RET_IP_); +rcu_read_lock (); }else {migrate_enable ();sleeping_lock_dec ();
@@ -1217,6 +1221,7 @@ int __lockfunc rt_spin_trylock_bh(spinlock_t *lock) ret =__rt_mutex_trylock (&lock->lock);if (ret) {sleeping_lock_inc (); +rcu_read_lock ();migrate_disable ();spin_acquire (&lock->dep_map,0 ,1 , _RET_IP_); }else
@@ -1233,6 +1238,7 @@ int __lockfunc rt_spin_trylock_irqsave(spinlock_t *lock, unsigned long *flags) ret =__rt_mutex_trylock (&lock->lock);if (ret) {sleeping_lock_inc (); +rcu_read_lock ();migrate_disable ();spin_acquire (&lock->dep_map,0 ,1 , _RET_IP_); }
kernel/locking/rwlock-rt.c +6 -0
@@ -310,6 +310,7 @@ int __lockfunc rt_read_trylock(rwlock_t *rwlock) ret =do_read_rt_trylock (rwlock);if (ret) {rwlock_acquire_read (&rwlock->dep_map,0 ,1 , _RET_IP_); +rcu_read_lock (); }else {migrate_enable ();sleeping_lock_dec ();
@@ -327,6 +328,7 @@ int __lockfunc rt_write_trylock(rwlock_t *rwlock) ret =do_write_rt_trylock (rwlock);if (ret) {rwlock_acquire (&rwlock->dep_map,0 ,1 , _RET_IP_); +rcu_read_lock (); }else {migrate_enable ();sleeping_lock_dec ();
@@ -338,6 +340,7 @@ EXPORT_SYMBOL(rt_write_trylock); void __lockfunc rt_read_lock(rwlock_t *rwlock) {sleeping_lock_inc (); +rcu_read_lock ();migrate_disable ();rwlock_acquire_read (&rwlock->dep_map,0 ,0 , _RET_IP_);do_read_rt_lock (rwlock);
@@ -347,6 +350,7 @@ EXPORT_SYMBOL(rt_read_lock); void __lockfunc rt_write_lock(rwlock_t *rwlock) {sleeping_lock_inc (); +rcu_read_lock ();migrate_disable ();rwlock_acquire (&rwlock->dep_map,0 ,0 , _RET_IP_);do_write_rt_lock (rwlock);
@@ -358,6 +362,7 @@ void __lockfunc rt_read_unlock(rwlock_t *rwlock)rwlock_release (&rwlock->dep_map,1 , _RET_IP_);do_read_rt_unlock (rwlock);migrate_enable (); +rcu_read_unlock ();sleeping_lock_dec (); }EXPORT_SYMBOL (rt_read_unlock);
@@ -367,6 +372,7 @@ void __lockfunc rt_write_unlock(rwlock_t *rwlock)rwlock_release (&rwlock->dep_map,1 , _RET_IP_);do_write_rt_unlock (rwlock);migrate_enable (); +rcu_read_unlock ();sleeping_lock_dec (); }EXPORT_SYMBOL (rt_write_unlock);
Signature · 1 line
2.14.1
PATCH 16/23 sched: migrate_enable: Use select_fallback_rq()
In reply to [email protected]From: Scott Wood <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit adfa969d4cfcc995a9d866020124e50f1827d2d1 ]
migrate_enable() currently open-codes a variant of select_fallback_rq(). However, it does not have the "No more Mr. Nice Guy" fallback and thus it will pass an invalid CPU to the migration thread if cpus_mask only contains a CPU that is !active.
--- kernel/sched/core.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-)
kernel/sched/core.c +10 -15
@@ -7008,6 +7008,7 @@ void migrate_enable(void)if (p->migrate_disable_update) {struct rq *rq;struct rq_flags rf; +int cpu =task_cpu (p); rq =task_rq_lock (p, &rf);update_rq_clock (rq);
@@ -7017,21 +7018,15 @@ void migrate_enable(void) p->migrate_disable_update =0 ; -WARN_ON (smp_processor_id () !=task_cpu (p)); -if (!cpumask_test_cpu (task_cpu (p), &p->cpus_mask)) { -const struct cpumask *cpu_valid_mask = cpu_active_mask; -struct migration_arg arg; -unsigned int dest_cpu; - -if (p->flags &PF_KTHREAD ) { -/* -* Kernel threads are allowed on online && !active CPUs -*/ - cpu_valid_mask = cpu_online_mask; - } - dest_cpu =cpumask_any_and (cpu_valid_mask, &p->cpus_mask); - arg.task = p; - arg.dest_cpu = dest_cpu; +WARN_ON (smp_processor_id () != cpu); +if (!cpumask_test_cpu (cpu, &p->cpus_mask)) { +struct migration_arg arg = { p }; +struct rq_flags rf; + + rq =task_rq_lock (p, &rf); +update_rq_clock (rq); + arg.dest_cpu =select_fallback_rq (cpu, p); +task_rq_unlock (rq, p, &rf);unpin_current_cpu ();preempt_lazy_enable ();
Signature · 1 line
2.14.1
PATCH 17/23 sched: Lazy migrate_disable processing
In reply to [email protected]From: Scott Wood <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 425c5b38779a860062aa62219dc920d374b13c17 ]
Avoid overhead on the majority of migrate disable/enable sequences by only manipulating scheduler data (and grabbing the relevant locks) when the task actually schedules while migrate-disabled. A kernel build showed around a 10% reduction in system time (with CONFIG_NR_CPUS=512).
Instead of cpuhp_pin_lock, CPU hotplug is handled by keeping a per-CPU count of the number of pinned tasks (including tasks which have not scheduled in the migrate-disabled section); takedown_cpu() will wait until that reaches zero (confirmed by take_cpu_down() in stop machine context to deal with races) before migrating tasks off of the cpu.
To simplify synchronization, updating cpus_mask is no longer deferred until migrate_enable(). This lets us not have to worry about migrate_enable() missing the update if it's on the fast path (didn't schedule during the migrate disabled section). It also makes the code a bit simpler and reduces deviation from mainline.
While the main motivation for this is the performance benefit, lazy migrate disable also eliminates the restriction on calling migrate_disable() while atomic but leaving the atomic region prior to calling migrate_enable() -- though this won't help with local_bh_disable() (and thus rcutorture) unless something similar is done with the recently added local_lock.
Conflicts:
include/linux/sched.h
init/init_task.c
kernel/sched/core.c
--- include/linux/cpu.h | 4 - include/linux/init_task.h | 9 +++ include/linux/sched.h | 11 +-- kernel/cpu.c | 103 ++++++++++---------------- kernel/sched/core.c | 182 +++++++++++++++++++--------------------------- kernel/sched/sched.h | 4 + lib/smp_processor_id.c | 3 + 7 files changed, 134 insertions(+), 182 deletions(-)
include/linux/cpu.h +0 -4
@@ -127,8 +127,6 @@ extern void cpu_hotplug_disable(void);extern void cpu_hotplug_enable (void );void clear_tasks_mm_cpumask (int cpu);int cpu_down (unsigned int cpu); -extern void pin_current_cpu (void ); -extern void unpin_current_cpu (void );#else /* CONFIG_HOTPLUG_CPU */
@@ -139,8 +137,6 @@ static inline void cpus_read_unlock(void) { }static inline void lockdep_assert_cpus_held (void ) { }static inline void cpu_hotplug_disable (void ) { }static inline void cpu_hotplug_enable (void ) { } -static inline void pin_current_cpu (void ) { } -static inline void unpin_current_cpu (void ) { }#endif /* !CONFIG_HOTPLUG_CPU */
include/linux/init_task.h +9 -0
@@ -225,6 +225,14 @@ extern struct cred init_cred;#define INIT_TASK_SECURITY #endif +#if defined(CONFIG_SMP ) && defined(CONFIG_PREEMPT_RT_BASE ) && \ + defined(CONFIG_SCHED_DEBUG ) +# define INIT_LAZY_MIGRATE (tsk) \ + .pinned_on_cpu = -1, +#else +# define INIT_LAZY_MIGRATE (tsk) +#endif +/* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -243,6 +251,7 @@ extern struct cred init_cred; .cpus_ptr = &tsk.cpus_mask, \ .cpus_mask = CPU_MASK_ALL, \ .nr_cpus_allowed=NR_CPUS , \ +INIT_LAZY_MIGRATE (tsk) \ .mm =NULL , \ .active_mm = &init_mm, \ .restart_block = { \
include/linux/sched.h +6 -5
@@ -229,6 +229,8 @@ extern void io_schedule_finish(int token);extern long io_schedule_timeout (long timeout);extern void io_schedule (void ); +int cpu_nr_pinned (int cpu); +/** * struct prev_cputime - snapshot of system and user cputime * @utime: time spent in user mode
@@ -628,16 +630,13 @@ struct task_struct {cpumask_t cpus_mask;#if defined(CONFIG_SMP ) && defined(CONFIG_PREEMPT_RT_BASE )int migrate_disable; -int migrate_disable_update; -int pinned_on_cpu; +bool migrate_disable_scheduled;# ifdef CONFIG_SCHED_DEBUG -int migrate_disable_atomic; +int pinned_on_cpu;# endif -#elif !defined(CONFIG_SMP ) && defined(CONFIG_PREEMPT_RT_BASE )# ifdef CONFIG_SCHED_DEBUG int migrate_disable; -int migrate_disable_atomic;# endif #endif #ifdef CONFIG_PREEMPT_RT_FULL
@@ -1883,4 +1882,6 @@ extern long sched_getaffinity(pid_t pid, struct cpumask *mask);#define TASK_SIZE_OF (tsk) TASK_SIZE#endif +extern struct task_struct *takedown_cpu_task; +#endif
kernel/cpu.c +38 -65
148 lines not on this page · raw message
kernel/sched/core.c +74 -108
289 lines not on this page · raw message
kernel/sched/sched.h +4 -0
@@ -811,6 +811,10 @@ struct rq {/* Must be inspected within a rcu lock section */ struct cpuidle_state *idle_state;#endif + +#if defined(CONFIG_PREEMPT_RT_BASE ) && defined(CONFIG_SMP ) +int nr_pinned; +#endif };static inline int cpu_of (struct rq *rq)
lib/smp_processor_id.c +3 -0
@@ -23,6 +23,9 @@ notrace static unsigned int check_preemption_disabled(const char *what1,* Kernel threads bound to a single CPU can safely use * smp_processor_id(): */ +if (current->migrate_disable) + goto out; +if (current->nr_cpus_allowed ==1 ) goto out;
Signature · 1 line
2.14.1
PATCH 18/23 sched: migrate_enable: Use stop_one_cpu_nowait()
In reply to [email protected]From: Scott Wood <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 6b39a1fa8c53cae08dc03afdae193b7d3a78a173 ]
migrate_enable() can be called with current->state != TASK_RUNNING. Avoid clobbering the existing state by using stop_one_cpu_nowait(). Since we're stopping the current cpu, we know that we won't get past __schedule() until migration_cpu_stop() has run (at least up to the point of migrating us to another cpu).
Conflicts:
kernel/sched/core.c
--- include/linux/stop_machine.h | 2 ++ kernel/sched/core.c | 23 +++++++++++++---------- kernel/stop_machine.c | 7 +++++-- 3 files changed, 20 insertions(+), 12 deletions(-)
include/linux/stop_machine.h +2 -0
@@ -26,6 +26,8 @@ struct cpu_stop_work {cpu_stop_fn_t fn;void *arg;struct cpu_stop_done *done; +/* Did not run due to disabled stopper; for nowait debug checks */ +bool disabled; };int stop_one_cpu (unsigned int cpu,cpu_stop_fn_t fn,void *arg);
kernel/sched/core.c +13 -10
@@ -1025,6 +1025,7 @@ static struct rq *move_queued_task(struct rq *rq, struct rq_flags *rf,struct migration_arg {struct task_struct *task;int dest_cpu; +bool done; };/*
@@ -1060,6 +1061,11 @@ static int migration_cpu_stop(void *data)struct task_struct *p = arg->task;struct rq *rq =this_rq ();struct rq_flags rf; +int dest_cpu = arg->dest_cpu; + +/* We don't look at arg after this point. */ +smp_mb (); + arg->done = true;/* * The original target CPU might have gone down and we might
@@ -1082,9 +1088,9 @@ static int migration_cpu_stop(void *data)*/ if (task_rq (p) == rq) {if (task_on_rq_queued (p)) - rq =__migrate_task (rq, &rf, p, arg->dest_cpu); + rq =__migrate_task (rq, &rf, p, dest_cpu);else - p->wake_cpu = arg->dest_cpu; + p->wake_cpu = dest_cpu; }rq_unlock (rq, &rf);raw_spin_unlock (&p->pi_lock);
@@ -6995,6 +7001,7 @@ void migrate_enable(void)WARN_ON (smp_processor_id () != cpu);if (!is_cpu_allowed (p, cpu)) {struct migration_arg arg = { p }; +struct cpu_stop_work work;struct rq_flags rf; rq =task_rq_lock (p, &rf);
@@ -7002,15 +7009,11 @@ void migrate_enable(void) arg.dest_cpu =select_fallback_rq (cpu, p);task_rq_unlock (rq, p, &rf); -preempt_lazy_enable (); -preempt_enable (); - -sleeping_lock_inc (); -stop_one_cpu (task_cpu (p), migration_cpu_stop, &arg); -sleeping_lock_dec (); +stop_one_cpu_nowait (task_cpu (p), migration_cpu_stop, + &arg, &work);tlb_migrate_finish (p->mm); - -return ; +__schedule (true); +WARN_ON_ONCE (!arg.done && !work.disabled); } out:
kernel/stop_machine.c +5 -2
@@ -86,8 +86,11 @@ static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work) enabled = stopper->enabled;if (enabled)__cpu_stop_queue_work (stopper, work, &wakeq); -else if (work->done) -cpu_stop_signal_done (work->done); +else { + work->disabled = true; +if (work->done) +cpu_stop_signal_done (work->done); + }raw_spin_unlock_irqrestore (&stopper->lock, flags);wake_up_q (&wakeq);
Signature · 1 line
2.14.1
PATCH 19/23 sched/core: migrate_enable() must access takedown_cpu_task on !HOTPLUG_CPU
In reply to [email protected]From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit a61d1977f692e46bad99a100f264981ba08cb4bd ]
The variable takedown_cpu_task is never declared/used on !HOTPLUG_CPU except for migrate_enable(). This leads to a link error.
Don't use takedown_cpu_task in !HOTPLUG_CPU.
--- kernel/cpu.c | 2 ++ kernel/sched/core.c | 2 ++ 2 files changed, 4 insertions(+)
kernel/cpu.c +2 -0
@@ -858,7 +858,9 @@ static int take_cpu_down(void *_param)return 0 ; } +#ifdef CONFIG_PREEMPT_RT_BASE struct task_struct *takedown_cpu_task; +#endif static int takedown_cpu (unsigned int cpu) {
kernel/sched/core.c +2 -0
@@ -6987,9 +6987,11 @@ void migrate_enable(void) p->migrate_disable =0 ; rq->nr_pinned--; +#ifdef CONFIG_HOTPLUG_CPU if (rq->nr_pinned ==0 &&unlikely (!cpu_active (cpu)) && takedown_cpu_task)wake_up_process (takedown_cpu_task); +#endif if (!p->migrate_disable_scheduled) goto out;
Signature · 1 line
2.14.1
PATCH 20/23 lib/smp_processor_id: Adjust check_preemption_disabled()
In reply to [email protected]From: Daniel Wagner <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit af3c1c5fdf177870fb5e6e16b24e374696ab28f5 ]
The current->migrate_disable counter is not always defined leading to build failures with DEBUG_PREEMPT && !PREEMPT_RT_BASE.
Restrict the access to ->migrate_disable to same set where ->migrate_disable is modified.
--- lib/smp_processor_id.c | 2 ++ 1 file changed, 2 insertions(+)
lib/smp_processor_id.c +2 -0
@@ -23,8 +23,10 @@ notrace static unsigned int check_preemption_disabled(const char *what1,* Kernel threads bound to a single CPU can safely use * smp_processor_id(): */ +#if defined(CONFIG_PREEMPT_RT_BASE ) && (defined(CONFIG_SMP ) || defined(CONFIG_SCHED_DEBUG ))if (current->migrate_disable) goto out; +#endif if (current->nr_cpus_allowed ==1 ) goto out;
Signature · 1 line
2.14.1
PATCH 21/23 sched: migrate_enable: Busy loop until the migration request is completed
In reply to [email protected]From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit 140d7f54a5fff02898d2ca9802b39548bf7455f1 ]
If user task changes the CPU affinity mask of a running task it will dispatch migration request if the current CPU is no longer allowed. This might happen shortly before a task enters a migrate_disable() section. Upon leaving the migrate_disable() section, the task will notice that the current CPU is no longer allowed and will will dispatch its own migration request to move it off the current CPU.
While invoking __schedule() the first migration request will be processed and the task returns on the "new" CPU with "arg.done = 0". Its own migration request will be processed shortly after and will result in memory corruption if the stack memory, designed for request, was used otherwise in the meantime.
Spin until the migration request has been processed if it was accepted.
--- kernel/sched/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
kernel/sched/core.c +5 -2
@@ -7002,7 +7002,7 @@ void migrate_enable(void)WARN_ON (smp_processor_id () != cpu);if (!is_cpu_allowed (p, cpu)) { -struct migration_arg arg = { p }; +struct migration_arg arg = { .task = p };struct cpu_stop_work work;struct rq_flags rf;
@@ -7015,7 +7015,10 @@ void migrate_enable(void) &arg, &work);tlb_migrate_finish (p->mm);__schedule (true); -WARN_ON_ONCE (!arg.done && !work.disabled); +if (!work.disabled) { +while (!arg.done) +cpu_relax (); + } } out:
Signature · 1 line
2.14.1
Re: [PATCH RT 21/23] sched: migrate_enable: Busy loop until the migration request is completed
Quoted 22 lines · On Thu, 2020-02-27 at 08:33 -0600, [email protected] wrote:
From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.-----------
[ Upstream commit
140d7f54a5fff02898d2ca9802b39548bf7455f1]If user task changes the CPU affinity mask of a running task it will dispatch migration request if the current CPU is no longer allowed. This might happen shortly before a task enters a
migrate_disable()section. Upon leaving themigrate_disable()section, the task will notice that the current CPU is no longer allowed and will will dispatch its own migration request to move it off the current CPU.
While invoking__schedule()the first migration request will be processed and the task returns on the "new" CPU with "arg.done = 0". Its own migration request will be processed shortly after and will result in memory corruption if the stack memory, designed for request, was used otherwise in the meantime.
Quoted 7 lines
Spin until the migration request has been processed if it was accepted.
Signed-off-by Sebastian Andrzej Siewior <[email protected]>Signed-off-by Tom Zanussi <[email protected]>--- kernel/sched/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
As I said in https://marc.info/?l=linux-rt-users&m=158258256415340&w=2 if you take thhis you should take the followup 2dcd94b443c5dcbc ("sched:migrate_enable: Use per-cpu cpu_stop_work")
-Scott
Re: [PATCH RT 21/23] sched: migrate_enable: Busy loop until the migration request is completed
Hi Scott,
Quoted 39 lines · Scott Wood
Quoted 29 lines · On Thu, 2020-02-27 at 08:33 -0600, [email protected] wrote:
From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.-----------
[ Upstream commit
140d7f54a5fff02898d2ca9802b39548bf7455f1]If user task changes the CPU affinity mask of a running task it will
dispatch migration request if the current CPU is no longer allowed. This
might happen shortly before a task enters amigrate_disable()section.
Upon leaving themigrate_disable()section, the task will notice that
the current CPU is no longer allowed and will will dispatch its own migration request to move it off the current CPU.
While invoking__schedule()the first migration request will be processed and the task returns on the "new" CPU with "arg.done = 0". Its
own migration request will be processed shortly after and will result in
memory corruption if the stack memory, designed for request, was used
otherwise in the meantime.Quoted 8 lines
Spin until the migration request has been processed if it was accepted.
Signed-off-by Sebastian Andrzej Siewior <[email protected]>Signed-off-by Tom Zanussi <[email protected]>--- kernel/sched/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
Quoted 5 lines
As I said in https://marc.info/?l=linux-rt-users&m=158258256415340&w=
2 if
you take thhis you should take the followup2dcd94b443c5dcbc("sched:migrate_enable: Use per-cpucpu_stop_work")
Yes, I didn't forget about this, it's just that I can't apply this to 4.14-rt until 4.19-rt does, otherwise it will be seen as a regression to someone moving from 4.14-rt to 4.19-rt.
I will be keeping my eye out for when that happens and will apply it to the next backport release at that point.
Thanks for making sure it wasn't missed in any case.
Tom
Quoted 3 lines
-Scott
Re: [PATCH RT 21/23] sched: migrate_enable: Busy loop until the migration request is completed
Quoted 48 lines · Tom Zanussi
Hi Scott,
Quoted 39 lines · Scott Wood
Quoted 29 lines · On Thu, 2020-02-27 at 08:33 -0600, [email protected] wrote:
From: Sebastian Andrzej Siewior <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.-----------
[ Upstream commit
140d7f54a5fff02898d2ca9802b39548bf7455f1]If user task changes the CPU affinity mask of a running task it will
dispatch migration request if the current CPU is no longer allowed. This
might happen shortly before a task enters amigrate_disable()section.
Upon leaving themigrate_disable()section, the task will notice that
the current CPU is no longer allowed and will will dispatch its own migration request to move it off the current CPU.
While invoking__schedule()the first migration request will be processed and the task returns on the "new" CPU with "arg.done = 0". Its
own migration request will be processed shortly after and will result in
memory corruption if the stack memory, designed for request, was used
otherwise in the meantime.Quoted 8 lines
Spin until the migration request has been processed if it was accepted.
Signed-off-by Sebastian Andrzej Siewior <[email protected]>Signed-off-by Tom Zanussi <[email protected]>--- kernel/sched/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)Quoted 5 lines
As I said in https://marc.info/?l=linux-rt-users&m=158258256415340&w=
2 if
you take thhis you should take the followup2dcd94b443c5dcbc("sched:migrate_enable: Use per-cpucpu_stop_work")
Quoted 8 lines
Yes, I didn't forget about this, it's just that I can't apply this to 4.14-rt until 4.19-rt does, otherwise it will be seen as a regression to someone moving from 4.14-rt to 4.19-rt.
I will be keeping my eye out for when that happens and will apply it to the next backport release at that point.
Thanks for making sure it wasn't missed in any case.
Steven, any plans to merge that patch into 4.19-rt?
In the meantime, I guess it's a question of whether the bug fixed by patch 18/23 is worse than the (probably quite hard to hit) deadlock addressed by 2dcd94b443c5dcbc.
-Scott
Steven Rostedt
reviewerRe: [PATCH RT 21/23] sched: migrate_enable: Busy loop until the migration request is completed
Quoted 7 lines · On Tue, 03 Mar 2020 15:19:23 -0600 Scott Wood <[email protected]> wrote:
Quoted 1 line
Thanks for making sure it wasn't missed in any case.
Steven, any plans to merge that patch into 4.19-rt?
In the meantime, I guess it's a question of whether the bug fixed by patch 18/23 is worse than the (probably quite hard to hit) deadlock addressed by
2dcd94b443c5dcbc.
Yes, I plan on doing my backports thursday and friday.
-- Steve
RE: [PATCH RT 21/23] sched: migrate_enable: Busy loop until the migration request is completed
In reply to [email protected]From: [email protected]
Quoted 15 lines
Sent: 27 February 2020 14:34
[ Upstream commit140d7f54a5fff02898d2ca9802b39548bf7455f1]If user task changes the CPU affinity mask of a running task it will dispatch migration request if the current CPU is no longer allowed. This might happen shortly before a task enters a
migrate_disable()section. Upon leaving themigrate_disable()section, the task will notice that the current CPU is no longer allowed and will will dispatch its own migration request to move it off the current CPU.
While invoking__schedule()the first migration request will be processed and the task returns on the "new" CPU with "arg.done = 0". Its own migration request will be processed shortly after and will result in memory corruption if the stack memory, designed for request, was used otherwise in the meantime.
Quoted 1 line
Spin until the migration request has been processed if it was accepted.
What happens if the process changing the affinity mask is running at a higher RT priority than that of the task being changed and the new mask requires it run on the same cpu?
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCH RT 21/23] sched: migrate_enable: Busy loop until the migration request is completed
Hi David,
Quoted 23 lines · David Laight
From: [email protected]
Quoted 22 lines
Sent: 27 February 2020 14:34
[ Upstream commit140d7f54a5fff02898d2ca9802b39548bf7455f1]If user task changes the CPU affinity mask of a running task it will
dispatch migration request if the current CPU is no longer allowed. This
might happen shortly before a task enters amigrate_disable()section.
Upon leaving themigrate_disable()section, the task will notice that
the current CPU is no longer allowed and will will dispatch its own migration request to move it off the current CPU.
While invoking__schedule()the first migration request will be processed and the task returns on the "new" CPU with "arg.done = 0". Its
own migration request will be processed shortly after and will result in
memory corruption if the stack memory, designed for request, was used
otherwise in the meantime.
Quoted 9 lines
Quoted 2 lines
Spin until the migration request has been processed if it was accepted.
What happens if the process changing the affinity mask is running at a higher RT priority than that of the task being changed and the new mask requires it run on the same cpu?
David
This patch, 'sched: migrate_enable: Use per-cpu cpu_stop_work', removes the busy wait and is queued for the next update:
Thanks,
Tom
Quoted 5 lines
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
PATCH 22/23 sched/deadline: Ensure inactive_timer runs in hardirq context
In reply to [email protected]From: Juri Lelli <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
[ Upstream commit ba94e7aed7405c58251b1380e6e7d73aa8284b41 ]
SCHED_DEADLINE inactive timer needs to run in hardirq context (as dl_task_timer already does) on PREEMPT_RT
Change the mode to HRTIMER_MODE_REL_HARD.
[ tglx: Fixed up the start site, so mode debugging works ]
--- kernel/sched/deadline.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/sched/deadline.c +2 -2
@@ -252,7 +252,7 @@ static void task_non_contending(struct task_struct *p) dl_se->dl_non_contending =1 ;get_task_struct (p); -hrtimer_start (timer,ns_to_ktime (zerolag_time),HRTIMER_MODE_REL ); +hrtimer_start (timer,ns_to_ktime (zerolag_time),HRTIMER_MODE_REL_HARD ); }static void task_contending (struct sched_dl_entity *dl_se,int flags)
@@ -1234,7 +1234,7 @@ void init_dl_inactive_task_timer(struct sched_dl_entity *dl_se) {struct hrtimer *timer = &dl_se->inactive_timer; -hrtimer_init (timer,CLOCK_MONOTONIC ,HRTIMER_MODE_REL ); +hrtimer_init (timer,CLOCK_MONOTONIC ,HRTIMER_MODE_REL_HARD ); timer->function = inactive_task_timer; }
Signature · 1 line
2.14.1
PATCH 23/23 Linux 4.14.170-rt75-rc2
In reply to [email protected]From: Tom Zanussi <[email protected]>
v4.14.170-rt75-rc2 stable review patch.
If anyone has any objections, please let me know.
-----------
--- localversion-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
localversion-rt +1 -1
@@ -1 +1 @@ --rt74 +-rt75-rc2
Signature · 1 line
2.14.1