The rcutorture_one_extend_check() function's second last check assumes
that "preempt_count() & PREEMPT_MASK" is non-zero only if
RCUTORTURE_RDR_PREEMPT or RCUTORTURE_RDR_SCHED bit is set.

This works for preemptible RCU and for non-preemptible RCU running in
a non-preemptible kernel.  But it fails for non-preemptible RCU running
in a preemptible kernel because then rcu_read_lock() is just
preempt_disable(), which increases preempt count.

This commit therefore adjusts this check to take into account the case
fo non-preemptible RCU running in a preemptible kernel.

Signed-off-by: Boqun Feng <[email protected]>
---
 kernel/rcu/rcutorture.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 280bff706017..4cae119dece8 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -1901,8 +1901,16 @@ static void rcutorture_one_extend_check(char *s, int 
curstate, int new, int old,
        WARN_ONCE(cur_ops->extendables &&
                  !(curstate & (RCUTORTURE_RDR_BH | RCUTORTURE_RDR_RBH)) &&
                  (preempt_count() & SOFTIRQ_MASK), ROEC_ARGS);
-       WARN_ONCE(cur_ops->extendables &&
-                 !(curstate & (RCUTORTURE_RDR_PREEMPT | RCUTORTURE_RDR_SCHED)) 
&&
+
+       /*
+        * non-preemptible RCU in a preemptible kernel uses preempt_disable()
+        * as rcu_read_lock().
+        */
+       mask = RCUTORTURE_RDR_PREEMPT | RCUTORTURE_RDR_SCHED;
+       if (!IS_ENABLED(CONFIG_PREEMPT_RCU))
+               mask |= RCUTORTURE_RDR_RCU_1 | RCUTORTURE_RDR_RCU_2;
+
+       WARN_ONCE(cur_ops->extendables && !(curstate & mask) &&
                  (preempt_count() & PREEMPT_MASK), ROEC_ARGS);
 
        /*
-- 
2.39.5 (Apple Git-154)


Reply via email to