aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTiejun Chen <tiejun.chen@windriver.com>2013-12-18 17:51:49 +0800
committerSebastian Andrzej Siewior <bigeasy@linutronix.de>2016-02-13 00:36:09 +0100
commit9fb86a49361eda6ed615a8506ba4eb597297e224 (patch)
treee3eb7b1f93714f594b10b69f4fc77b7313ca446d
parent842b1983f15a70ce956190d29e69caa35bd88e62 (diff)
downloadrt-linux-9fb86a49361eda6ed615a8506ba4eb597297e224.tar.gz
rcutree/rcu_bh_qs: Disable irq while calling rcu_preempt_qs()
Any callers to the function rcu_preempt_qs() must disable irqs in order to protect the assignment to ->rcu_read_unlock_special. In RT case, rcu_bh_qs() as the wrapper of rcu_preempt_qs() is called in some scenarios where irq is enabled, like this path, do_single_softirq() | + local_irq_enable(); + handle_softirq() | | | + rcu_bh_qs() | | | + rcu_preempt_qs() | + local_irq_disable() So here we'd better disable irq directly inside of rcu_bh_qs() to fix this, otherwise the kernel may be freezable sometimes as observed. And especially this way is also kind and safe for the potential rcu_bh_qs() usage elsewhere in the future. Signed-off-by: Tiejun Chen <tiejun.chen@windriver.com> Signed-off-by: Bin Jiang <bin.jiang@windriver.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-rw-r--r--kernel/rcu/tree.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index eadbeb631f55d..136eb95331487 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -271,7 +271,12 @@ static void rcu_preempt_qs(void);
void rcu_bh_qs(void)
{
+ unsigned long flags;
+
+ /* Callers to this function, rcu_preempt_qs(), must disable irqs. */
+ local_irq_save(flags);
rcu_preempt_qs();
+ local_irq_restore(flags);
}
#else
void rcu_bh_qs(void)