]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
rcu: Fix CONFIG_RCU_FANOUT_EXACT for odd fanout/leaf values
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Wed, 16 Oct 2013 15:39:10 +0000 (08:39 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Mon, 9 Dec 2013 23:12:38 +0000 (15:12 -0800)
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>
kernel/rcu/tree.c

index f8c029971bb36eb00aabca2fb9918e9b88db9e24..db1a9fdaeab8bb77a2320576f01ee3f600a3157f 100644 (file)
@@ -3259,9 +3259,9 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp)
 {
        int i;
 
-       for (i = rcu_num_lvls - 1; i > 0; i--)
+       rsp->levelspread[rcu_num_lvls - 1] = rcu_fanout_leaf;
+       for (i = rcu_num_lvls - 2; i >= 0; i--)
                rsp->levelspread[i] = CONFIG_RCU_FANOUT;
-       rsp->levelspread[0] = rcu_fanout_leaf;
 }
 #else /* #ifdef CONFIG_RCU_FANOUT_EXACT */
 static void __init rcu_init_levelspread(struct rcu_state *rsp)