aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcu/tree.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-10-16 11:39:10 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-12-09 18:12:38 -0500
commit04f34650ca5e8445aae0ab3e0ff6704f141150a8 (patch)
treeb16d8e405b078520af0c72177045864b31788ff7 /kernel/rcu/tree.c
parentf6f7ee9af7554e4d167ccd0ffe7cb8da0aa954f9 (diff)
rcu: Fix CONFIG_RCU_FANOUT_EXACT for odd fanout/leaf values
Each element of the rcu_state structure's ->levelspread[] array is intended to contain the per-level fanout, where the zero-th element corresponds to the root of the rcu_node tree, and the last element corresponds to the leaves. In the CONFIG_RCU_FANOUT_EXACT case, this means that the last element should be filled in from CONFIG_RCU_FANOUT_LEAF (or from the rcu_fanout_leaf boot parameter, if provided) and that the remaining elements should be filled in from CONFIG_RCU_FANOUT. Unfortunately, the current code in rcu_init_levelspread() takes the opposite approach, placing CONFIG_RCU_FANOUT_LEAF in the zero-th element and CONFIG_RCU_FANOUT in the remaining elements. For typical power-of-two values, this generates odd but functional rcu_node trees. However, other values, for example CONFIG_RCU_FANOUT=3 and CONFIG_RCU_FANOUT_LEAF=2, generate trees that can leave some CPUs out of the grace-period computation, resulting in too-short grace periods and therefore a broken RCU implementation. This commit therefore fixes rcu_init_levelspread() to set the last ->levelspread[] array element from CONFIG_RCU_FANOUT_LEAF and the remaining elements from CONFIG_RCU_FANOUT, thus generating the intended rcu_node trees. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcu/tree.c')
-rw-r--r--kernel/rcu/tree.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index f8c029971bb3..db1a9fdaeab8 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -3259,9 +3259,9 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp)
3259{ 3259{
3260 int i; 3260 int i;
3261 3261
3262 for (i = rcu_num_lvls - 1; i > 0; i--) 3262 rsp->levelspread[rcu_num_lvls - 1] = rcu_fanout_leaf;
3263 for (i = rcu_num_lvls - 2; i >= 0; i--)
3263 rsp->levelspread[i] = CONFIG_RCU_FANOUT; 3264 rsp->levelspread[i] = CONFIG_RCU_FANOUT;
3264 rsp->levelspread[0] = rcu_fanout_leaf;
3265} 3265}
3266#else /* #ifdef CONFIG_RCU_FANOUT_EXACT */ 3266#else /* #ifdef CONFIG_RCU_FANOUT_EXACT */
3267static void __init rcu_init_levelspread(struct rcu_state *rsp) 3267static void __init rcu_init_levelspread(struct rcu_state *rsp)