Linux 4.9.65-rt57-rc1
Subsystems (10)
cover Linux 4.9.65-rt57-rc1
[ Sorry for the duplicate, I tried to cancel sending, but quilt decided
to send anyway :-p ]
Dear RT Folks,
This is the RT stable review cycle of patch 4.9.65-rt57-rc1.
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 12/5/2017.
Enjoy,
-- Steve
To build 4.9.65-rt57-rc1 directly, the following patches should be applied:
http://www.kernel.org/pub/linux/kernel/v4.x/linux-4.9.tar.xz
http://www.kernel.org/pub/linux/kernel/v4.x/patch-4.9.65.xz
http://www.kernel.org/pub/linux/kernel/projects/rt/4.9/patch-4.9.65-rt57-rc1.patch.xz
You can also build from 4.9.65-rt56 by applying the incremental patch:
http://www.kernel.org/pub/linux/kernel/projects/rt/4.9/incr/patch-4.9.65-rt56-rt57-rc1.patch.xz
Changes from 4.9.65-rt56:
---
Alex Shi (1):
cpu_pm: replace raw_notifier to atomic_notifier
Mike Galbraith (2):
rtmutex: Fix lock stealing logic
kernel/hrtimer/hotplug: don't wake ktimersoftd while holding the hrtimer base lock
Sebastian Andrzej Siewior (10):
Revert "fs: jbd2: pull your plug when waiting for space"
posixtimer: init timer only with CONFIG_POSIX_TIMERS enabled PM / CPU: replace raw_notifier with atomic_notifier (fixup) kernel/hrtimer: migrate deferred timer on CPU down
net: take the tcp_sk_lock lock with BH disabled kernel/hrtimer: don't wakeup a process while holding the hrtimer base lock
Bluetooth: avoid recursive locking in hci_send_to_channel() iommu/amd: Use raw_cpu_ptr() instead of get_cpu_ptr() for ->flush_queue rt/locking: allow recursive local_trylock()
locking/rtmutex: don't drop the wait_lock twice
Steven Rostedt (VMware) (2):
Revert "memcontrol: Prevent scheduling while atomic in cgroup code" Linux 4.9.65-rt57-rc1
----
drivers/iommu/amd_iommu.c | 4 +-- fs/jbd2/checkpoint.c | 2 -- include/linux/init_task.h | 2 +- include/linux/locallock.h | 9 ++++++ kernel/cpu_pm.c | 50 +++++++++----------------------- kernel/locking/rtmutex.c | 74 +++++++++++++++++++++++------------------------ kernel/time/hrtimer.c | 35 ++++++++++++++++------ localversion-rt | 2 +- mm/memcontrol.c | 13 ++++----- net/bluetooth/hci_sock.c | 17 +++++++---- net/ipv4/tcp_ipv4.c | 8 ++--- 11 files changed, 108 insertions(+), 108 deletions(-)
PATCH 1/15 Revert "memcontrol: Prevent scheduling while atomic in cgroup code"
4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <[email protected]>
The commit "memcontrol: Prevent scheduling while atomic in cgroup code" fixed this issue:
refill_stock()
get_cpu_var()
drain_stock()
res_counter_uncharge()
res_counter_uncharge_until()
spin_lock() <== boomBut commit 3e32cb2e0a12b ("mm: memcontrol: lockless page counters") replaced the calls to res_counter_uncharge() in drain_stock() to the lockless function page_counter_uncharge(). There is no more spin lock there and no more reason to have that local lock.
[bigeasy: That upstream commit appeared in v3.19 and the patch in
question in v3.18.7-rt2 and v3.18 seems still to be maintained. So I guess that v3.18 would need the locallocks that we are about to remove here. I am not sure if any earlier versions have the patch backported.
The stable tag here is because Haiyang reported (and debugged) a crash in 4.4-RT with this patch applied (which has get_cpu_light() instead the locallocks it gained in v4.9-RT).
https://lkml.kernel.org/r/[email protected]
]
--- mm/memcontrol.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
mm/memcontrol.c +6 -7
@@ -1698,7 +1698,6 @@ struct memcg_stock_pcp {#define FLUSHING_CACHED_CHARGE 0 }; static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock); -static DEFINE_LOCAL_IRQ_LOCK (memcg_stock_ll);static DEFINE_MUTEX (percpu_charge_mutex);/**
@@ -1721,7 +1720,7 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages)if (nr_pages >CHARGE_BATCH )return ret; -local_lock_irqsave (memcg_stock_ll, flags); +local_irq_save (flags); stock =this_cpu_ptr (&memcg_stock);if (memcg == stock->cached && stock->nr_pages >= nr_pages) {
@@ -1729,7 +1728,7 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) ret = true; } -local_unlock_irqrestore (memcg_stock_ll, flags); +local_irq_restore (flags);return ret; }
@@ -1756,13 +1755,13 @@ static void drain_local_stock(struct work_struct *dummy)struct memcg_stock_pcp *stock;unsigned long flags; -local_lock_irqsave (memcg_stock_ll, flags); +local_irq_save (flags); stock =this_cpu_ptr (&memcg_stock);drain_stock (stock);clear_bit (FLUSHING_CACHED_CHARGE , &stock->flags); -local_unlock_irqrestore (memcg_stock_ll, flags); +local_irq_restore (flags); }/*
@@ -1774,7 +1773,7 @@ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)struct memcg_stock_pcp *stock;unsigned long flags; -local_lock_irqsave (memcg_stock_ll, flags); +local_irq_save (flags); stock =this_cpu_ptr (&memcg_stock);if (stock->cached != memcg) {/* reset if necessary */
@@ -1783,7 +1782,7 @@ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) } stock->nr_pages += nr_pages; -local_unlock_irqrestore (memcg_stock_ll, flags); +local_irq_restore (flags); }/*
Signature · 1 line
2.13.2
PATCH 2/15 Revert "fs: jbd2: pull your plug when waiting for space"
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
This reverts commit "fs: jbd2: pull your plug when waiting for space". This was a duct-tape fix which shouldn't be needed since commit "locking/rt-mutex: fix deadlock in device mapper / block-IO".
--- fs/jbd2/checkpoint.c | 2 -- 1 file changed, 2 deletions(-)
fs/jbd2/checkpoint.c +0 -2
@@ -116,8 +116,6 @@ void __jbd2_log_wait_for_space(journal_t *journal) nblocks =jbd2_space_needed (journal);while (jbd2_log_space_left (journal) < nblocks) {write_unlock (&journal->j_state_lock); -if (current->plug) -io_schedule ();mutex_lock (&journal->j_checkpoint_mutex);/*
Signature · 1 line
2.13.2
PATCH 3/15 rtmutex: Fix lock stealing logic
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Mike Galbraith <[email protected]>
1. When trying to acquire an rtmutex, we first try to grab it without queueing the waiter, and explicitly check for that initial attempt in the !waiter path of __try_to_take_rt_mutex(). Checking whether the lock taker is top waiter before allowing a steal attempt in that path is a thinko: the lock taker has not yet blocked.
2. It seems wrong to change the definition of rt_mutex_waiter_less() to mean less or perhaps equal when we have an rt_mutex_waiter_equal().
Remove the thinko, restore rt_mutex_waiter_less(), implement and use rt_mutex_steal() based upon rt_mutex_waiter_less/equal(), moving all qualification criteria into the function itself.
--- kernel/locking/rtmutex.c | 73 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 37 deletions(-)
kernel/locking/rtmutex.c +36 -37
@@ -235,25 +235,18 @@ static inline bool unlock_rt_mutex_safe(struct rt_mutex *lock, }#endif -#define STEAL_NORMAL 0 -#define STEAL_LATERAL 1/* * Only use with rt_mutex_waiter_{less,equal}() */ -#define task_to_waiter (p) \ - &(struct rt_mutex_waiter){ .prio = (p)->prio, .deadline = (p)->dl.deadline } +#define task_to_waiter (p) &(struct rt_mutex_waiter) \ + { .prio = (p)->prio, .deadline = (p)->dl.deadline, .task = (p) }static inline int rt_mutex_waiter_less (struct rt_mutex_waiter *left, -struct rt_mutex_waiter *right,int mode) +struct rt_mutex_waiter *right) { -if (mode ==STEAL_NORMAL ) { -if (left->prio < right->prio) -return 1 ; - }else { -if (left->prio <= right->prio) -return 1 ; - } +if (left->prio < right->prio) +return 1 ;/* * If both waiters have dl_prio(), we check the deadlines of the
@@ -286,6 +279,27 @@ rt_mutex_waiter_equal(struct rt_mutex_waiter *left,return 1 ; } +#define STEAL_NORMAL 0 +#define STEAL_LATERAL 1 + +static inline int +rt_mutex_steal (struct rt_mutex *lock,struct rt_mutex_waiter *waiter,int mode) +{ +struct rt_mutex_waiter *top_waiter =rt_mutex_top_waiter (lock); + +if (waiter == top_waiter ||rt_mutex_waiter_less (waiter, top_waiter)) +return 1 ; + +/* +* Note that RT tasks are excluded from lateral-steals +* to prevent the introduction of an unbounded latency. +*/ +if (mode ==STEAL_NORMAL ||rt_task (waiter->task)) +return 0 ; + +return rt_mutex_waiter_equal (waiter, top_waiter); +} +static void rt_mutex_enqueue (struct rt_mutex *lock,struct rt_mutex_waiter *waiter) {
@@ -297,7 +311,7 @@ rt_mutex_enqueue(struct rt_mutex *lock, struct rt_mutex_waiter *waiter)while (*link) { parent = *link; entry = rb_entry(parent, struct rt_mutex_waiter, tree_entry); -if (rt_mutex_waiter_less (waiter, entry,STEAL_NORMAL )) { +if (rt_mutex_waiter_less (waiter, entry)) { link = &parent->rb_left; }else { link = &parent->rb_right;
@@ -336,7 +350,7 @@ rt_mutex_enqueue_pi(struct task_struct *task, struct rt_mutex_waiter *waiter)while (*link) { parent = *link; entry = rb_entry(parent, struct rt_mutex_waiter, pi_tree_entry); -if (rt_mutex_waiter_less (waiter, entry,STEAL_NORMAL )) { +if (rt_mutex_waiter_less (waiter, entry)) { link = &parent->rb_left; }else { link = &parent->rb_right;
@@ -847,6 +861,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,* @task: The task which wants to acquire the lock * @waiter: The waiter that is queued to the lock's wait tree if the * callsite called task_blocked_on_lock(), otherwise NULL +* @mode: Lock steal mode (STEAL_NORMAL, STEAL_LATERAL) */ static int __try_to_take_rt_mutex(struct rt_mutex *lock, struct task_struct *task,
@@ -886,14 +901,11 @@ static int __try_to_take_rt_mutex(struct rt_mutex *lock,*/ if (waiter) {/* -* If waiter is not the highest priority waiter of -* @lock, give up. +* If waiter is not the highest priority waiter of @lock, +* or its peer when lateral steal is allowed, give up. */ -if (waiter !=rt_mutex_top_waiter (lock)) { -/* XXX rt_mutex_waiter_less() ? */ +if (!rt_mutex_steal (lock, waiter, mode))return 0 ; - } -/* * We can acquire the lock. Remove the waiter from the * lock waiters tree.
@@ -910,25 +922,12 @@ static int __try_to_take_rt_mutex(struct rt_mutex *lock,* not need to be dequeued. */ if (rt_mutex_has_waiters (lock)) { -struct task_struct *pown =rt_mutex_top_waiter (lock)->task; - -if (task != pown) -return 0 ; - -/* -* Note that RT tasks are excluded from lateral-steals -* to prevent the introduction of an unbounded latency. -*/ -if (rt_task (task)) - mode =STEAL_NORMAL ;/* -* If @task->prio is greater than or equal to -* the top waiter priority (kernel view), -* @task lost. +* If @task->prio is greater than the top waiter +* priority (kernel view), or equal to it when a +* lateral steal is forbidden, @task lost. */ -if (!rt_mutex_waiter_less (task_to_waiter (task), -rt_mutex_top_waiter (lock), - mode)) +if (!rt_mutex_steal (lock,task_to_waiter (task), mode))return 0 ;/* * The current top waiter stays enqueued. We
Signature · 1 line
2.13.2
PATCH 4/15 posixtimer: init timer only with CONFIG_POSIX_TIMERS enabled
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
In v4.11 it is possible to disable the posix timers and so we must not attempt to initialize the task_struct on RT with !POSIX_TIMERS. This patch does so.
--- include/linux/init_task.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/init_task.h +1 -1
@@ -150,7 +150,7 @@ extern struct task_group root_task_group;# define INIT_PERF_EVENTS (tsk)#endif -#ifdef CONFIG_PREEMPT_RT_BASE +#if defined(CONFIG_POSIX_TIMERS ) && defined(CONFIG_PREEMPT_RT_BASE )# define INIT_TIMER_LIST .posix_timer_list = NULL,#else # define INIT_TIMER_LIST
Signature · 1 line
2.13.2
Re: [PATCH RT 04/15] posixtimer: init timer only with CONFIG_POSIX_TIMERS enabled
Quoted 10 lines · On Fri, 01 Dec 2017 10:50:03 -0500 Steven Rostedt <[email protected]> wrote:
4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.------------------
From: Sebastian Andrzej Siewior <[email protected]>
In v4.11 it is possible to disable the posix timers and so we must not attempt to initialize the
task_structon RT with !POSIX_TIMERS. This patch does so.
Hmm, I may have been too greedy in pulling in this patch. I'm going to remove it from the list, and post a -rc2.
-- Steve
Quoted 19 lines
Signed-off-by Sebastian Andrzej Siewior <[email protected]>--- include/linux/init_task.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)include/linux/init_task.h +1
-1@@ -150,7 +150,7 @@ extern struct task_group root_task_group;# define INIT_PERF_EVENTS (tsk)#endif -#ifdef CONFIG_PREEMPT_RT_BASE +#if defined(CONFIG_POSIX_TIMERS ) && defined(CONFIG_PREEMPT_RT_BASE )# define INIT_TIMER_LIST .posix_timer_list = NULL,#else # define INIT_TIMER_LIST
PATCH 5/15 cpu_pm: replace raw_notifier to atomic_notifier
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Alex Shi <[email protected]>
This patch replace a rwlock and raw notifier by atomic notifier which protected by spin_lock and rcu.
The first to reason to have this replace is due to a 'scheduling while
atomic' bug of RT kernel on arm/arm64 platform. On arm/arm64, rwlockcpu_pm_notifier_lock in cpu_pm cause a potential schedule after irq disable in idle call chain:
cpu_startup_entry
cpu_idle_loop
local_irq_disable()
cpuidle_idle_call
call_cpuidle
cpuidle_enter
cpuidle_enter_state
->enter :arm_enter_idle_state
cpu_pm_enter/exit
CPU_PM_CPU_IDLE_ENTER
read_lock(&cpu_pm_notifier_lock); <-- sleep in idle
__rt_spin_lock();
schedule();The kernel panic is here:
[ 4.609601] BUG: scheduling while atomic: swapper/1/0/0x00000002 [ 4.609608] [<ffff0000086fae70>] arm_enter_idle_state+0x18/0x70 [ 4.609614] Modules linked in: [ 4.609615] [<ffff0000086f9298>] cpuidle_enter_state+0xf0/0x218 [ 4.609620] [<ffff0000086f93f8>] cpuidle_enter+0x18/0x20 [ 4.609626] Preemption disabled at: [ 4.609627] [<ffff0000080fa234>] call_cpuidle+0x24/0x40 [ 4.609635] [<ffff000008882fa4>] schedule_preempt_disabled+0x1c/0x28 [ 4.609639] [<ffff0000080fa49c>] cpu_startup_entry+0x154/0x1f8 [ 4.609645] [<ffff00000808e004>] secondary_start_kernel+0x15c/0x1a0
Daniel Lezcano said this notification is needed on arm/arm64 platforms. Sebastian suggested using atomic_notifier instead of rwlock, which is not only removing the sleeping in idle, but also getting better latency improvement.
This patch passed Fengguang's 0day testing.
--- kernel/cpu_pm.c | 43 ++++++------------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-)
kernel/cpu_pm.c +6 -37
@@ -22,14 +22,13 @@#include <linux/spinlock.h> #include <linux/syscore_ops.h> -static DEFINE_RWLOCK (cpu_pm_notifier_lock); -static RAW_NOTIFIER_HEAD (cpu_pm_notifier_chain); +static ATOMIC_NOTIFIER_HEAD (cpu_pm_notifier_chain);static int cpu_pm_notify (enum cpu_pm_event event,int nr_to_call,int *nr_calls) {int ret; - ret =__raw_notifier_call_chain (&cpu_pm_notifier_chain, event,NULL , + ret =__atomic_notifier_call_chain (&cpu_pm_notifier_chain, event,NULL , nr_to_call, nr_calls);return notifier_to_errno (ret);
@@ -47,14 +46,7 @@ static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)*/ int cpu_pm_register_notifier (struct notifier_block *nb) { -unsigned long flags; -int ret; - -write_lock_irqsave (&cpu_pm_notifier_lock, flags); - ret =raw_notifier_chain_register (&cpu_pm_notifier_chain, nb); -write_unlock_irqrestore (&cpu_pm_notifier_lock, flags); - -return ret; +return atomic_notifier_chain_register (&cpu_pm_notifier_chain, nb); }EXPORT_SYMBOL_GPL (cpu_pm_register_notifier);
@@ -69,14 +61,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);*/ int cpu_pm_unregister_notifier (struct notifier_block *nb) { -unsigned long flags; -int ret; - -write_lock_irqsave (&cpu_pm_notifier_lock, flags); - ret =raw_notifier_chain_unregister (&cpu_pm_notifier_chain, nb); -write_unlock_irqrestore (&cpu_pm_notifier_lock, flags); - -return ret; +return atomic_notifier_chain_unregister (&cpu_pm_notifier_chain, nb); }EXPORT_SYMBOL_GPL (cpu_pm_unregister_notifier);
@@ -100,7 +85,6 @@ int cpu_pm_enter(void)int nr_calls;int ret =0 ; -read_lock (&cpu_pm_notifier_lock); ret =cpu_pm_notify (CPU_PM_ENTER ,-1 , &nr_calls);if (ret)/*
@@ -108,7 +92,6 @@ int cpu_pm_enter(void)* PM entry who are notified earlier to prepare for it. */ cpu_pm_notify (CPU_PM_ENTER_FAILED , nr_calls -1 ,NULL ); -read_unlock (&cpu_pm_notifier_lock);return ret; }
@@ -128,13 +111,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_enter);*/ int cpu_pm_exit (void ) { -int ret; - -read_lock (&cpu_pm_notifier_lock); - ret =cpu_pm_notify (CPU_PM_EXIT ,-1 ,NULL ); -read_unlock (&cpu_pm_notifier_lock); - -return ret; +return cpu_pm_notify (CPU_PM_EXIT ,-1 ,NULL ); }EXPORT_SYMBOL_GPL (cpu_pm_exit);
@@ -159,7 +136,6 @@ int cpu_cluster_pm_enter(void)int nr_calls;int ret =0 ; -read_lock (&cpu_pm_notifier_lock); ret =cpu_pm_notify (CPU_CLUSTER_PM_ENTER ,-1 , &nr_calls);if (ret)/*
@@ -167,7 +143,6 @@ int cpu_cluster_pm_enter(void)* PM entry who are notified earlier to prepare for it. */ cpu_pm_notify (CPU_CLUSTER_PM_ENTER_FAILED , nr_calls -1 ,NULL ); -read_unlock (&cpu_pm_notifier_lock);return ret; }
@@ -190,13 +165,7 @@ EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);*/ int cpu_cluster_pm_exit (void ) { -int ret; - -read_lock (&cpu_pm_notifier_lock); - ret =cpu_pm_notify (CPU_CLUSTER_PM_EXIT ,-1 ,NULL ); -read_unlock (&cpu_pm_notifier_lock); - -return ret; +return cpu_pm_notify (CPU_CLUSTER_PM_EXIT ,-1 ,NULL ); }EXPORT_SYMBOL_GPL (cpu_cluster_pm_exit);
Signature · 1 line
2.13.2
PATCH 6/15 PM / CPU: replace raw_notifier with atomic_notifier (fixup)
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
The original patch changed betwen its posting and what finally went into Rafael's tree so here is the delta.
--- kernel/cpu_pm.c | 7 +++++++ 1 file changed, 7 insertions(+)
kernel/cpu_pm.c +7 -0
@@ -28,8 +28,15 @@ static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls) {int ret; +/* +* __atomic_notifier_call_chain has a RCU read critical section, which +* could be disfunctional in cpu idle. Copy RCU_NONIDLE code to let +* RCU know this. +*/ +rcu_irq_enter_irqson (); ret =__atomic_notifier_call_chain (&cpu_pm_notifier_chain, event,NULL , nr_to_call, nr_calls); +rcu_irq_exit_irqson ();return notifier_to_errno (ret); }
Signature · 1 line
2.13.2
PATCH 7/15 kernel/hrtimer: migrate deferred timer on CPU down
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
hrtimers, which were deferred to the softirq context, and expire between softirq shutdown and hrtimer migration are dangling around. If the CPU goes back up the list head will be initialized and this corrupts the timer's list. It will remain unnoticed until a hrtimer_cancel(). This moves those timers so they will expire.
--- kernel/time/hrtimer.c | 5 +++++ 1 file changed, 5 insertions(+)
kernel/time/hrtimer.c +5 -0
@@ -1860,6 +1860,11 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,*/ enqueue_hrtimer (timer, new_base); } +#ifdef CONFIG_PREEMPT_RT_BASE +list_splice_tail (&old_base->expired, &new_base->expired); +if (!list_empty (&new_base->expired)) +raise_softirq_irqoff (HRTIMER_SOFTIRQ ); +#endif }int hrtimers_dead_cpu (unsigned int scpu)
Signature · 1 line
2.13.2
PATCH 8/15 net: take the tcp_sk_lock lock with BH disabled
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
Lockdep may complain about an unsafe locking scenario:
| CPU0 CPU1 | ---- ---- | lock((tcp_sk_lock).lock); | lock(&per_cpu(local_softirq_locks[i], __cpu).lock); | lock((tcp_sk_lock).lock); | lock(&per_cpu(local_softirq_locks[i], __cpu).lock);
in the call paths:
do_current_softirqs -> tcp_v4_send_ack() vs tcp_v4_send_reset -> do_current_softirqs().
This should not happen since local_softirq_locks is per CPU. Reversing the order makes lockdep happy.
--- net/ipv4/tcp_ipv4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/ipv4/tcp_ipv4.c +4 -4
@@ -698,8 +698,8 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) arg.tos =ip_hdr (skb)->tos; -local_lock (tcp_sk_lock);local_bh_disable (); +local_lock (tcp_sk_lock); ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), skb, &TCP_SKB_CB(skb)->header.h4.opt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
@@ -707,8 +707,8 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)__TCP_INC_STATS (net,TCP_MIB_OUTSEGS );__TCP_INC_STATS (net,TCP_MIB_OUTRSTS ); -local_bh_enable ();local_unlock (tcp_sk_lock); +local_bh_enable ();#ifdef CONFIG_TCP_MD5SIG out:
@@ -784,16 +784,16 @@ static void tcp_v4_send_ack(struct net *net,if (oif) arg.bound_dev_if = oif; arg.tos = tos; -local_lock (tcp_sk_lock);local_bh_disable (); +local_lock (tcp_sk_lock);ip_send_unicast_reply (*this_cpu_ptr (net->ipv4.tcp_sk), skb, &TCP_SKB_CB (skb)->header.h4.opt,ip_hdr (skb)->saddr,ip_hdr (skb)->daddr, &arg, arg.iov[0 ].iov_len);__TCP_INC_STATS (net,TCP_MIB_OUTSEGS ); -local_bh_enable ();local_unlock (tcp_sk_lock); +local_bh_enable (); }static void tcp_v4_timewait_ack (struct sock *sk,struct sk_buff *skb)
Signature · 1 line
2.13.2
PATCH 9/15 kernel/hrtimer: dont wakeup a process while holding the hrtimer base lock
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
We must not wake any process (and thus acquire the pi->lock) while holding the hrtimer's base lock. This does not happen usually because the hrtimer-callback is invoked in IRQ-context and so raise_softirq_irqoff() does not wakeup a process.
However during CPU-hotplug it might get called from hrtimers_dead_cpu() which would wakeup the thread immediately.
--- kernel/time/hrtimer.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
kernel/time/hrtimer.c +10 -5
@@ -1440,7 +1440,7 @@ static inline int hrtimer_rt_defer(struct hrtimer *timer) { return 0; }static enum hrtimer_restart hrtimer_wakeup (struct hrtimer *timer); -static void __hrtimer_run_queues (struct hrtimer_cpu_base *cpu_base,ktime_t now) +static int __hrtimer_run_queues (struct hrtimer_cpu_base *cpu_base,ktime_t now) {struct hrtimer_clock_base *base = cpu_base->clock_base;unsigned int active = cpu_base->active_bases;
@@ -1490,8 +1490,7 @@ static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) raise =1 ; } } -if (raise) -raise_softirq_irqoff (HRTIMER_SOFTIRQ ); +return raise; }#ifdef CONFIG_HIGH_RES_TIMERS
@@ -1505,6 +1504,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)struct hrtimer_cpu_base *cpu_base =this_cpu_ptr (&hrtimer_bases);ktime_t expires_next, now, entry_time, delta;int retries =0 ; +int raise;BUG_ON (!cpu_base->hres_active); cpu_base->nr_events++;
@@ -1523,7 +1523,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)*/ cpu_base->expires_next.tv64 =KTIME_MAX ; -__hrtimer_run_queues (cpu_base, now); + raise =__hrtimer_run_queues (cpu_base, now);/* Reevaluate the clock bases for the next expiry */ expires_next =__hrtimer_get_next_event (cpu_base);
@@ -1534,6 +1534,8 @@ void hrtimer_interrupt(struct clock_event_device *dev) cpu_base->expires_next = expires_next; cpu_base->in_hrtirq =0 ;raw_spin_unlock (&cpu_base->lock); +if (raise) +raise_softirq_irqoff (HRTIMER_SOFTIRQ );/* Reprogramming necessary ? */ if (!tick_program_event (expires_next,0 )) {
@@ -1613,6 +1615,7 @@ void hrtimer_run_queues(void) {struct hrtimer_cpu_base *cpu_base =this_cpu_ptr (&hrtimer_bases);ktime_t now; +int raise;if (__hrtimer_hres_active (cpu_base))return ;
@@ -1631,8 +1634,10 @@ void hrtimer_run_queues(void)raw_spin_lock (&cpu_base->lock); now =hrtimer_update_base (cpu_base); -__hrtimer_run_queues (cpu_base, now); + raise =__hrtimer_run_queues (cpu_base, now);raw_spin_unlock (&cpu_base->lock); +if (raise) +raise_softirq_irqoff (HRTIMER_SOFTIRQ ); }/*
Signature · 1 line
2.13.2
PATCH 10/15 kernel/hrtimer/hotplug: dont wake ktimersoftd while holding the hrtimer base lock
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Mike Galbraith <[email protected]>
kernel/hrtimer: don't wakeup a process while holding the hrtimer base lock missed a path, namely hrtimers_dead_cpu() -> migrate_hrtimer_list(). Defer raising softirq until after base lock has been released there as well.
--- kernel/time/hrtimer.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
kernel/time/hrtimer.c +13 -6
@@ -1837,7 +1837,7 @@ int hrtimers_prepare_cpu(unsigned int cpu)#ifdef CONFIG_HOTPLUG_CPU -static void migrate_hrtimer_list (struct hrtimer_clock_base *old_base, +static int migrate_hrtimer_list (struct hrtimer_clock_base *old_base,struct hrtimer_clock_base *new_base) {struct hrtimer *timer;
@@ -1867,15 +1867,19 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, }#ifdef CONFIG_PREEMPT_RT_BASE list_splice_tail (&old_base->expired, &new_base->expired); -if (!list_empty (&new_base->expired)) -raise_softirq_irqoff (HRTIMER_SOFTIRQ ); +/* +* Tell the caller to raise HRTIMER_SOFTIRQ. We can't safely +* acquire ktimersoftd->pi_lock while the base lock is held. +*/ +return !list_empty (&new_base->expired);#endif +return 0 ; }int hrtimers_dead_cpu (unsigned int scpu) {struct hrtimer_cpu_base *old_base, *new_base; -int i; +int i, raise =0 ;BUG_ON (cpu_online (scpu));tick_cancel_sched_timer (scpu);
@@ -1891,13 +1895,16 @@ int hrtimers_dead_cpu(unsigned int scpu)raw_spin_lock_nested (&old_base->lock,SINGLE_DEPTH_NESTING );for (i =0 ; i <HRTIMER_MAX_CLOCK_BASES ; i++) { -migrate_hrtimer_list (&old_base->clock_base[i], - &new_base->clock_base[i]); + raise |=migrate_hrtimer_list (&old_base->clock_base[i], + &new_base->clock_base[i]); }raw_spin_unlock (&old_base->lock);raw_spin_unlock (&new_base->lock); +if (raise) +raise_softirq_irqoff (HRTIMER_SOFTIRQ ); +/* Check, if we got expired work to do */ __hrtimer_peek_ahead_timers ();local_irq_enable ();
Signature · 1 line
2.13.2
PATCH 11/15 Bluetooth: avoid recursive locking in hci_send_to_channel()
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
Mart reported a deadlock in -RT in the call path:
hci_send_monitor_ctrl_event() -> hci_send_to_channel()
because both functions acquire the same read lock hci_sk_list.lock. This is also a mainline issue because the qrwlock implementation is writer fair (the traditional rwlock implementation is reader biased).
To avoid the deadlock there is now __hci_send_to_channel() which expects the readlock to be held.
--- net/bluetooth/hci_sock.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
net/bluetooth/hci_sock.c +11 -6
@@ -251,15 +251,13 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) }/* Send frame to sockets with specific channel */ -void hci_send_to_channel (unsigned short channel,struct sk_buff *skb, -int flag,struct sock *skip_sk) +static void __hci_send_to_channel (unsigned short channel,struct sk_buff *skb, +int flag,struct sock *skip_sk) {struct sock *sk;BT_DBG ("channel %u len %d" , channel, skb->len); -read_lock (&hci_sk_list.lock); -sk_for_each (sk, &hci_sk_list.head) {struct sk_buff *nskb;
@@ -285,6 +283,13 @@ void hci_send_to_channel(unsigned short channel, struct sk_buff *skb,kfree_skb (nskb); } +} + +void hci_send_to_channel (unsigned short channel,struct sk_buff *skb, +int flag,struct sock *skip_sk) +{ +read_lock (&hci_sk_list.lock); +__hci_send_to_channel (channel, skb, flag, skip_sk);read_unlock (&hci_sk_list.lock); }
@@ -388,8 +393,8 @@ void hci_send_monitor_ctrl_event(struct hci_dev *hdev, u16 event, hdr->index = index; hdr->len =cpu_to_le16 (skb->len -HCI_MON_HDR_SIZE ); -hci_send_to_channel (HCI_CHANNEL_MONITOR , skb, -HCI_SOCK_TRUSTED ,NULL ); +__hci_send_to_channel (HCI_CHANNEL_MONITOR , skb, +HCI_SOCK_TRUSTED ,NULL );kfree_skb (skb); }
Signature · 1 line
2.13.2
PATCH 12/15 iommu/amd: Use raw_cpu_ptr() instead of get_cpu_ptr() for ->flush_queue
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
get_cpu_ptr() disabled preemption and returns the ->flush_queue object of the current CPU. raw_cpu_ptr() does the same except that it not disable preemption which means the scheduler can move it to another CPU after it obtained the per-CPU object.
In this case this is not bad because the data structure itself is protected with a spin_lock. This change shouldn't matter however on RT it does because the sleeping lock can't be accessed with disabled preemption.
--- drivers/iommu/amd_iommu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/iommu/amd_iommu.c +1 -3
@@ -2283,7 +2283,7 @@ static void queue_add(struct dma_ops_domain *dma_dom, pages =__roundup_pow_of_two (pages); address >>=PAGE_SHIFT ; - queue =get_cpu_ptr (&flush_queue); + queue =raw_cpu_ptr (&flush_queue);spin_lock_irqsave (&queue->lock, flags);if (queue->next ==FLUSH_QUEUE_SIZE )
@@ -2300,8 +2300,6 @@ static void queue_add(struct dma_ops_domain *dma_dom,if (atomic_cmpxchg (&queue_timer_on,0 ,1 ) ==0 )mod_timer (&queue_timer, jiffies +msecs_to_jiffies (10 )); - -put_cpu_ptr (&flush_queue); }
Signature · 1 line
2.13.2
PATCH 13/15 rt/locking: allow recursive local_trylock()
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
required for following networking patch which does recursive try-lock. While at it, add the !RT version of it because it did not yet exist.
--- include/linux/locallock.h | 9 +++++++++ 1 file changed, 9 insertions(+)
include/linux/locallock.h +9 -0
@@ -77,6 +77,9 @@ static inline int __local_trylock(struct local_irq_lock *lv) lv->owner = current; lv->nestcnt =1 ;return 1 ; + }else if (lv->owner == current) { + lv->nestcnt++; +return 1 ; }return 0 ; }
@@ -250,6 +253,12 @@ static inline int __local_unlock_irqrestore(struct local_irq_lock *lv,static inline void local_irq_lock_init (int lvar) { } +#define local_trylock (lvar) \ + ({ \ + preempt_disable(); \ + 1; \ + }) +#define local_lock (lvar) preempt_disable()#define local_unlock (lvar) preempt_enable()#define local_lock_irq (lvar) local_irq_disable()
Signature · 1 line
2.13.2
PATCH 14/15 locking/rtmutex: dont drop the wait_lock twice
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
Since the futex rework, __rt_mutex_start_proxy_lock() does no longer acquire the wait_lock so it must not drop it. Otherwise the lock is not only unlocked twice but also the preemption counter is underflown.
It is okay to remove that line because this function does not disable interrupts nor does it acquire the ->wait_lock. The caller does this so it is wrong do it here (after the futex rework).
--- kernel/locking/rtmutex.c | 1 - 1 file changed, 1 deletion(-)
kernel/locking/rtmutex.c +0 -1
@@ -2312,7 +2312,6 @@ int __rt_mutex_start_proxy_lock(struct rt_mutex *lock,raw_spin_lock (&task->pi_lock);if (task->pi_blocked_on) {raw_spin_unlock (&task->pi_lock); -raw_spin_unlock_irq (&lock->wait_lock);return -EAGAIN ; } task->pi_blocked_on =PI_REQUEUE_INPROGRESS ;
Signature · 1 line
2.13.2
PATCH 15/15 Linux 4.9.65-rt57-rc1
In reply to Steven Rostedt4.9.65-rt57-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" <[email protected]>
--- localversion-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
localversion-rt +1 -1
@@ -1 +1 @@ --rt56 +-rt57-rc1
Signature · 1 line
2.13.2