rcu: Warn on for_each_leaf_node_cpu_mask() from non-leaf
authorPaul E. McKenney <paulmck@kernel.org>
Sun, 15 Dec 2019 19:38:57 +0000 (11:38 -0800)
committerPaul E. McKenney <paulmck@kernel.org>
Thu, 20 Feb 2020 23:58:21 +0000 (15:58 -0800)
The for_each_leaf_node_cpu_mask() and for_each_leaf_node_possible_cpu()
macros must be invoked only on leaf rcu_node structures.  Failing to
abide by this restriction can result in infinite loops on systems with
more than 64 CPUs (or for more than 32 CPUs on 32-bit systems).  This
commit therefore adds WARN_ON_ONCE() calls to make misuse of these two
macros easier to debug.

Reported-by: Qian Cai <cai@lca.pw>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
kernel/rcu/rcu.h

index 05f936e..f6ce173 100644 (file)
@@ -325,7 +325,8 @@ static inline void rcu_init_levelspread(int *levelspread, const int *levelcnt)
  * Iterate over all possible CPUs in a leaf RCU node.
  */
 #define for_each_leaf_node_possible_cpu(rnp, cpu) \
-       for ((cpu) = cpumask_next((rnp)->grplo - 1, cpu_possible_mask); \
+       for (WARN_ON_ONCE(!rcu_is_leaf_node(rnp)), \
+            (cpu) = cpumask_next((rnp)->grplo - 1, cpu_possible_mask); \
             (cpu) <= rnp->grphi; \
             (cpu) = cpumask_next((cpu), cpu_possible_mask))
 
@@ -335,7 +336,8 @@ static inline void rcu_init_levelspread(int *levelspread, const int *levelcnt)
 #define rcu_find_next_bit(rnp, cpu, mask) \
        ((rnp)->grplo + find_next_bit(&(mask), BITS_PER_LONG, (cpu)))
 #define for_each_leaf_node_cpu_mask(rnp, cpu, mask) \
-       for ((cpu) = rcu_find_next_bit((rnp), 0, (mask)); \
+       for (WARN_ON_ONCE(!rcu_is_leaf_node(rnp)), \
+            (cpu) = rcu_find_next_bit((rnp), 0, (mask)); \
             (cpu) <= rnp->grphi; \
             (cpu) = rcu_find_next_bit((rnp), (cpu) + 1 - (rnp->grplo), (mask)))