diff options
| author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2014-11-18 03:30:01 -0500 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2015-01-06 14:02:52 -0500 |
| commit | abaf3f9d275b8d856ae5e47531e40c0bfeac012b (patch) | |
| tree | 017561fdbffe2f3e840d6af7c5a7bbcf015c70c9 | |
| parent | 3ba4d0e09bf965297e97adf195e0ea246cfe5c74 (diff) | |
rcu: Revert "Allow post-unlock reference for rt_mutex" to avoid priority-inversion
The patch dfeb9765ce3c ("Allow post-unlock reference for rt_mutex")
ensured rcu-boost safe even the rt_mutex has post-unlock reference.
But rt_mutex allowing post-unlock reference is definitely a bug and it was
fixed by the commit 27e35715df54 ("rtmutex: Plug slow unlock race").
This fix made the previous patch (dfeb9765ce3c) useless.
And even worse, the priority-inversion introduced by the the previous
patch still exists.
rcu_read_unlock_special() {
rt_mutex_unlock(&rnp->boost_mtx);
/* Priority-Inversion:
* the current task had been deboosted and preempted as a low
* priority task immediately, it could wait long before reschedule in,
* and the rcu-booster also waits on this low priority task and sleeps.
* This priority-inversion makes rcu-booster can't work
* as expected.
*/
complete(&rnp->boost_completion);
}
Just revert the patch to avoid it.
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
| -rw-r--r-- | kernel/rcu/tree.h | 5 | ||||
| -rw-r--r-- | kernel/rcu/tree_plugin.h | 8 |
2 files changed, 1 insertions, 12 deletions
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index 883ebc8e2b6e..95356477d560 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h | |||
| @@ -172,11 +172,6 @@ struct rcu_node { | |||
| 172 | /* queued on this rcu_node structure that */ | 172 | /* queued on this rcu_node structure that */ |
| 173 | /* are blocking the current grace period, */ | 173 | /* are blocking the current grace period, */ |
| 174 | /* there can be no such task. */ | 174 | /* there can be no such task. */ |
| 175 | struct completion boost_completion; | ||
| 176 | /* Used to ensure that the rt_mutex used */ | ||
| 177 | /* to carry out the boosting is fully */ | ||
| 178 | /* released with no future boostee accesses */ | ||
| 179 | /* before that rt_mutex is re-initialized. */ | ||
| 180 | struct rt_mutex boost_mtx; | 175 | struct rt_mutex boost_mtx; |
| 181 | /* Used only for the priority-boosting */ | 176 | /* Used only for the priority-boosting */ |
| 182 | /* side effect, not as a lock. */ | 177 | /* side effect, not as a lock. */ |
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 1fac68220999..625e26040e6b 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h | |||
| @@ -429,10 +429,8 @@ void rcu_read_unlock_special(struct task_struct *t) | |||
| 429 | 429 | ||
| 430 | #ifdef CONFIG_RCU_BOOST | 430 | #ifdef CONFIG_RCU_BOOST |
| 431 | /* Unboost if we were boosted. */ | 431 | /* Unboost if we were boosted. */ |
| 432 | if (drop_boost_mutex) { | 432 | if (drop_boost_mutex) |
| 433 | rt_mutex_unlock(&rnp->boost_mtx); | 433 | rt_mutex_unlock(&rnp->boost_mtx); |
| 434 | complete(&rnp->boost_completion); | ||
| 435 | } | ||
| 436 | #endif /* #ifdef CONFIG_RCU_BOOST */ | 434 | #endif /* #ifdef CONFIG_RCU_BOOST */ |
| 437 | 435 | ||
| 438 | /* | 436 | /* |
| @@ -1081,15 +1079,11 @@ static int rcu_boost(struct rcu_node *rnp) | |||
| 1081 | */ | 1079 | */ |
| 1082 | t = container_of(tb, struct task_struct, rcu_node_entry); | 1080 | t = container_of(tb, struct task_struct, rcu_node_entry); |
| 1083 | rt_mutex_init_proxy_locked(&rnp->boost_mtx, t); | 1081 | rt_mutex_init_proxy_locked(&rnp->boost_mtx, t); |
| 1084 | init_completion(&rnp->boost_completion); | ||
| 1085 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 1082 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
| 1086 | /* Lock only for side effect: boosts task t's priority. */ | 1083 | /* Lock only for side effect: boosts task t's priority. */ |
| 1087 | rt_mutex_lock(&rnp->boost_mtx); | 1084 | rt_mutex_lock(&rnp->boost_mtx); |
| 1088 | rt_mutex_unlock(&rnp->boost_mtx); /* Then keep lockdep happy. */ | 1085 | rt_mutex_unlock(&rnp->boost_mtx); /* Then keep lockdep happy. */ |
| 1089 | 1086 | ||
| 1090 | /* Wait for boostee to be done w/boost_mtx before reinitializing. */ | ||
| 1091 | wait_for_completion(&rnp->boost_completion); | ||
| 1092 | |||
| 1093 | return ACCESS_ONCE(rnp->exp_tasks) != NULL || | 1087 | return ACCESS_ONCE(rnp->exp_tasks) != NULL || |
| 1094 | ACCESS_ONCE(rnp->boost_tasks) != NULL; | 1088 | ACCESS_ONCE(rnp->boost_tasks) != NULL; |
| 1095 | } | 1089 | } |
