| Subject: rcu: rcutiny: Prevent RCU stall |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue, 16 Oct 2012 18:36:51 +0200 |
| |
| rcu_read_unlock_special() checks in_serving_softirq() and leaves early |
| when true. On RT this is obviously wrong as softirq processing context |
| can be preempted and therefor such a task can be on the gp_tasks |
| list. Leaving early here will leave the task on the list and therefor |
| block RCU processing forever. |
| |
| This cannot happen on mainline because softirq processing context |
| cannot be preempted and therefor this can never happen at all. |
| |
| In fact this check looks quite questionable in general. Neither irq |
| context nor softirq processing context in mainline can ever be |
| preempted in mainline so the special unlock case should not ever be |
| invoked in such context. Now the only explanation might be a |
| rcu_read_unlock() being interrupted and therefor leave the rcu nest |
| count at 0 before the special unlock bit has been cleared. That looks |
| fragile. At least it's missing a big fat comment. Paul ???? |
| |
| See mainline commits: ec433f0c5 and 8762705a for further enlightment. |
| |
| Reported-by: Kristian Lehmann <krleit00@hs-esslingen.de> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Cc: stable-rt@vger.kernel.org |
| |
| --- |
| kernel/rcutiny_plugin.h | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/kernel/rcutiny_plugin.h |
| +++ b/kernel/rcutiny_plugin.h |
| @@ -560,7 +560,7 @@ void rcu_read_unlock_special(struct task |
| rcu_preempt_cpu_qs(); |
| |
| /* Hardware IRQ handlers cannot block. */ |
| - if (in_irq() || in_serving_softirq()) { |
| + if (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_OFFSET)) { |
| local_irq_restore(flags); |
| return; |
| } |