This commit creates counters in the rcu_torture_one_read_state_updown structure that check for a call to ->up_read() that lacks a matching call to ->down_read(). While in the area, add end-of-run cleanup code that prevents calls to rcu_torture_updown_hrt() from happening after the test has moved on. Yes, the srcu_barrier() at the end of the test will wait for them, but this could result in confusing states, statistics, and diagnostic information. So explicitly wait for them before we get to the end-of-test output. [ paulmck: Apply kernel test robot feedback. ] Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxx> Tested-by: kernel test robot <oliver.sang@xxxxxxxxx> --- kernel/rcu/rcutorture.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index fcdd6271f435c..a0786b3c223be 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -2439,6 +2439,8 @@ struct rcu_torture_one_read_state_updown { struct hrtimer rtorsu_hrt; bool rtorsu_inuse; unsigned long rtorsu_j; + unsigned long rtorsu_ndowns; + unsigned long rtorsu_nups; struct torture_random_state rtorsu_trs; struct rcu_torture_one_read_state rtorsu_rtors; }; @@ -2453,6 +2455,8 @@ static enum hrtimer_restart rcu_torture_updown_hrt(struct hrtimer *hrtp) rtorsup = container_of(hrtp, struct rcu_torture_one_read_state_updown, rtorsu_hrt); rcu_torture_one_read_end(&rtorsup->rtorsu_rtors, &rtorsup->rtorsu_trs, -1); + WARN_ONCE(rtorsup->rtorsu_nups >= rtorsup->rtorsu_ndowns, "%s: Up without matching down #%zu.\n", __func__, rtorsup - updownreaders); + rtorsup->rtorsu_nups++; smp_store_release(&rtorsup->rtorsu_inuse, false); return HRTIMER_NORESTART; } @@ -2499,7 +2503,12 @@ static void rcu_torture_updown_cleanup(void) if (!smp_load_acquire(&rtorsup->rtorsu_inuse)) continue; (void)hrtimer_cancel(&rtorsup->rtorsu_hrt); - WARN_ON_ONCE(rtorsup->rtorsu_inuse); + if (WARN_ON_ONCE(rtorsup->rtorsu_inuse)) { + rcu_torture_one_read_end(&rtorsup->rtorsu_rtors, &rtorsup->rtorsu_trs, -1); + WARN_ONCE(rtorsup->rtorsu_nups >= rtorsup->rtorsu_ndowns, "%s: Up without matching down #%zu.\n", __func__, rtorsup - updownreaders); + rtorsup->rtorsu_nups++; + smp_store_release(&rtorsup->rtorsu_inuse, false); + } } kfree(updownreaders); @@ -2515,11 +2524,14 @@ static void rcu_torture_updown_one(struct rcu_torture_one_read_state_updown *rto init_rcu_torture_one_read_state(&rtorsup->rtorsu_rtors, &rtorsup->rtorsu_trs); rawidx = cur_ops->down_read(); + rtorsup->rtorsu_ndowns++; idx = (rawidx << RCUTORTURE_RDR_SHIFT_1) & RCUTORTURE_RDR_MASK_1; rtorsup->rtorsu_rtors.readstate = idx | RCUTORTURE_RDR_UPDOWN; rtorsup->rtorsu_rtors.rtrsp++; if (!rcu_torture_one_read_start(&rtorsup->rtorsu_rtors, &rtorsup->rtorsu_trs, -1)) { cur_ops->up_read(rawidx); + rtorsup->rtorsu_nups++; + WARN_ONCE(rtorsup->rtorsu_nups >= rtorsup->rtorsu_ndowns, "%s: Up without matching down #%zu.\n", __func__, rtorsup - updownreaders); schedule_timeout_idle(HZ); return; } -- 2.40.1