The Slow-deboost detector in rcu_torture_one_read() checks for a still-
boosted task immediately after the outer rcu_read_unlock() returns.
Sub-microsecond checking is unrealistic for any async deboost mechanism
(irq_work, softirq dispatch).  As, even with a delay in deboosting of
just 50us, the check beats  it.

Therefore, poll the boost state for up to 500us before declaring the
deboost tardy.

Signed-off-by: Joel Fernandes <[email protected]>
---
 kernel/rcu/rcutorture.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index e0bea4039c42..12813b5381d6 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -2601,15 +2601,26 @@ static bool rcu_torture_one_read(struct 
torture_random_state *trsp, long myid)
        // of arch_irq_work_raise()).  On such systems, RCU cannot
        // guarantee to immediately deboost RCU readers when the outermost
        // rcu_read_unlock() does not end the full segmented RCU read-side
-       // critical section.
-       if (WARN_ON_ONCE(cur_ops->is_task_rcu_boosted && 
cur_ops->is_task_rcu_boosted() &&
-                        preempt_count() == 0 && !irqs_disabled() &&
-                        rcu_preempt_depth() == 0) &&
-           READ_ONCE(firsttime) && xchg(&firsttime, 0)) {
-               nsegs = rtors.rtrsp - rtors.rtseg;
-               nsegs = clamp_val(nsegs, 0, RCUTORTURE_RDR_MAX_SEGS);
-               pr_alert("Slow-deboost rcutorture reader segments:\n");
-               rcu_torture_dump_read_segs(rtors.rtseg, nsegs);
+       // critical section.  Allow up to 500us for an async deboost
+       // mechanism (e.g. irq work, timers etc) to fire before
+       // declaring the deboost tardy.
+       if (cur_ops->is_task_rcu_boosted && cur_ops->is_task_rcu_boosted() &&
+           preempt_count() == 0 && !irqs_disabled() &&
+           rcu_preempt_depth() == 0) {
+               int wait_us;
+
+               for (wait_us = 0; wait_us < 500; wait_us += 10) {
+                       udelay(10);
+                       if (!cur_ops->is_task_rcu_boosted())
+                               break;
+               }
+               if (WARN_ON_ONCE(cur_ops->is_task_rcu_boosted()) &&
+                   READ_ONCE(firsttime) && xchg(&firsttime, 0)) {
+                       nsegs = rtors.rtrsp - rtors.rtseg;
+                       nsegs = clamp_val(nsegs, 0, RCUTORTURE_RDR_MAX_SEGS);
+                       pr_alert("Slow-deboost rcutorture reader segments:\n");
+                       rcu_torture_dump_read_segs(rtors.rtseg, nsegs);
+               }
        }
        return true;
 }
-- 
2.34.1


Reply via email to