The stutter_wait() function is supposed to return true if it actually waits and false otherwise, but it instead unconditionally returns false. Which hides a bug in rcu_torture_writer() that fails to account for the fact that one of the rcu_tortures[] array elements will normally be referenced by rcu_torture_current, and thus not be on the freelist. This commit therefore corrects the stutter_wait() return value and adds a check for rcu_torture_current to rcu_torture_writer()'s check that things get freed after everything goes quiescent. In addition, this commit causes torture_stutter() to give a bit more than one second (instead of only one jiffy) warning of the end of the stutter interval. Finally, this commit disables long-delay readers and aggressive update-side forward-progress checks while forward-progress testing is in flight.
Unified · Split
| @@ -1010,10 +1010,13 @@ rcu_torture_writer(void *arg) · 1009 unmodified lines | |||
| 1010 | !rcu_gp_is_normal(); | 1010 | !rcu_gp_is_normal(); |
| 1011 | } | 1011 | } |
| 1012 | rcu_torture_writer_state = RTWS_STUTTER; | 1012 | rcu_torture_writer_state = RTWS_STUTTER; |
| 1013 | if (stutter_wait("rcu_torture_writer")) | 1013 | if (stutter_wait("rcu_torture_writer") && |
| 1014 | !READ_ONCE(rcu_fwd_cb_nodelay)) | ||
| 1014 | for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) | 1015 | for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) |
| 1015 | if (list_empty(&rcu_tortures[i].rtort_free)) | 1016 | if (list_empty(&rcu_tortures[i].rtort_free) && |
| 1016 | WARN_ON_ONCE(1); | 1017 | rcu_access_pointer(rcu_torture_current) != |
| 1018 | &rcu_tortures[i]) | ||
| 1019 | WARN(1, "%s: rtort_pipe_count: %d\n", __func__, rcu_tortures[i].rtort_pipe_count); | ||
| 1017 | } while (!torture_must_stop()); | 1020 | } while (!torture_must_stop()); |
| 1018 | /* Reset expediting back to unexpedited. */ | 1021 | /* Reset expediting back to unexpedited. */ |
| 1019 | if (expediting > 0) | 1022 | if (expediting > 0) |
| @@ -1709,6 +1712,8 @@ static void rcu_torture_fwd_prog_nr(int *tested, int *tested_tries) · 689 unmodified lines | |||
| 1709 | } | 1712 | } |
| 1710 | 1713 | ||
| 1711 | /* Tight loop containing cond_resched(). */ | 1714 | /* Tight loop containing cond_resched(). */ |
| 1715 | WRITE_ONCE(rcu_fwd_cb_nodelay, true); | ||
| 1716 | cur_ops->sync(); /* Later readers see above write. */ | ||
| 1712 | if (selfpropcb) { | 1717 | if (selfpropcb) { |
| 1713 | WRITE_ONCE(fcs.stop, 0); | 1718 | WRITE_ONCE(fcs.stop, 0); |
| 1714 | cur_ops->call(&fcs.rh, rcu_torture_fwd_prog_cb); | 1719 | cur_ops->call(&fcs.rh, rcu_torture_fwd_prog_cb); |
| @@ -1747,6 +1752,8 @@ static void rcu_torture_fwd_prog_nr(int *tested, int *tested_tries) · 32 unmodified lines | |||
| 1747 | WARN_ON(READ_ONCE(fcs.stop) != 2); | 1752 | WARN_ON(READ_ONCE(fcs.stop) != 2); |
| 1748 | destroy_rcu_head_on_stack(&fcs.rh); | 1753 | destroy_rcu_head_on_stack(&fcs.rh); |
| 1749 | } | 1754 | } |
| 1755 | schedule_timeout_uninterruptible(HZ / 10); /* Let kthreads recover. */ | ||
| 1756 | WRITE_ONCE(rcu_fwd_cb_nodelay, false); | ||
| 1750 | } | 1757 | } |
| 1751 | 1758 | ||
| 1752 | /* Carry out call_rcu() forward-progress testing. */ | 1759 | /* Carry out call_rcu() forward-progress testing. */ |
| @@ -1816,7 +1823,6 @@ static void rcu_torture_fwd_prog_cr(void) · 63 unmodified lines | |||
| 1816 | cur_ops->cb_barrier(); /* Wait for callbacks to be invoked. */ | 1823 | cur_ops->cb_barrier(); /* Wait for callbacks to be invoked. */ |
| 1817 | (void)rcu_torture_fwd_prog_cbfree(); | 1824 | (void)rcu_torture_fwd_prog_cbfree(); |
| 1818 | 1825 | ||
| 1819 | WRITE_ONCE(rcu_fwd_cb_nodelay, false); | ||
| 1820 | if (!torture_must_stop() && !READ_ONCE(rcu_fwd_emergency_stop)) { | 1826 | if (!torture_must_stop() && !READ_ONCE(rcu_fwd_emergency_stop)) { |
| 1821 | WARN_ON(n_max_gps < MIN_FWD_CBS_LAUNDERED); | 1827 | WARN_ON(n_max_gps < MIN_FWD_CBS_LAUNDERED); |
| 1822 | pr_alert("%s Duration %lu barrier: %lu pending %ld n_launders: %ld n_launders_sa: %ld n_max_gps: %ld n_max_cbs: %ld cver %ld gps %ld\n", | 1828 | pr_alert("%s Duration %lu barrier: %lu pending %ld n_launders: %ld n_launders_sa: %ld n_max_gps: %ld n_max_cbs: %ld cver %ld gps %ld\n", |
| @@ -1827,6 +1833,8 @@ static void rcu_torture_fwd_prog_cr(void) · 4 unmodified lines | |||
| 1827 | n_max_gps, n_max_cbs, cver, gps); | 1833 | n_max_gps, n_max_cbs, cver, gps); |
| 1828 | rcu_torture_fwd_cb_hist(); | 1834 | rcu_torture_fwd_cb_hist(); |
| 1829 | } | 1835 | } |
| 1836 | schedule_timeout_uninterruptible(HZ); /* Let CBs drain. */ | ||
| 1837 | WRITE_ONCE(rcu_fwd_cb_nodelay, false); | ||
| 1830 | } | 1838 | } |
| 1831 | 1839 | ||
| 1832 | 1840 | ||
| @@ -578,10 +578,12 @@ static int stutter; · 577 unmodified lines | |||
| 578 | bool stutter_wait(const char *title) | 578 | bool stutter_wait(const char *title) |
| 579 | { | 579 | { |
| 580 | int spt; | 580 | int spt; |
| 581 | bool ret = false; | ||
| 581 | 582 | ||
| 582 | cond_resched_tasks_rcu_qs(); | 583 | cond_resched_tasks_rcu_qs(); |
| 583 | spt = READ_ONCE(stutter_pause_test); | 584 | spt = READ_ONCE(stutter_pause_test); |
| 584 | for (; spt; spt = READ_ONCE(stutter_pause_test)) { | 585 | for (; spt; spt = READ_ONCE(stutter_pause_test)) { |
| 586 | ret = true; | ||
| 585 | if (spt == 1) { | 587 | if (spt == 1) { |
| 586 | schedule_timeout_interruptible(1); | 588 | schedule_timeout_interruptible(1); |
| 587 | } else if (spt == 2) { | 589 | } else if (spt == 2) { |
| @@ -592,7 +594,7 @@ bool stutter_wait(const char *title) · 4 unmodified lines | |||
| 592 | } | 594 | } |
| 593 | torture_shutdown_absorb(title); | 595 | torture_shutdown_absorb(title); |
| 594 | } | 596 | } |
| 595 | return !!spt; | 597 | return ret; |
| 596 | } | 598 | } |
| 597 | EXPORT_SYMBOL_GPL(stutter_wait); | 599 | EXPORT_SYMBOL_GPL(stutter_wait); |
| 598 | 600 | ||
| @@ -602,13 +604,20 @@ EXPORT_SYMBOL_GPL(stutter_wait); · 3 unmodified lines | |||
| 602 | */ | 604 | */ |
| 603 | static int torture_stutter(void *arg) | 605 | static int torture_stutter(void *arg) |
| 604 | { | 606 | { |
| 607 | int wtime; | ||
| 608 | |||
| 605 | VERBOSE_TOROUT_STRING("torture_stutter task started"); | 609 | VERBOSE_TOROUT_STRING("torture_stutter task started"); |
| 606 | do { | 610 | do { |
| 607 | if (!torture_must_stop() && stutter > 1) { | 611 | if (!torture_must_stop() && stutter > 1) { |
| 608 | WRITE_ONCE(stutter_pause_test, 1); | 612 | wtime = stutter; |
| 609 | schedule_timeout_interruptible(stutter - 1); | 613 | if (stutter > HZ + 1) { |
| 614 | WRITE_ONCE(stutter_pause_test, 1); | ||
| 615 | wtime = stutter - HZ - 1; | ||
| 616 | schedule_timeout_interruptible(wtime); | ||
| 617 | wtime = HZ + 1; | ||
| 618 | } | ||
| 610 | WRITE_ONCE(stutter_pause_test, 2); | 619 | WRITE_ONCE(stutter_pause_test, 2); |
| 611 | schedule_timeout_interruptible(1); | 620 | schedule_timeout_interruptible(wtime); |
| 612 | } | 621 | } |
| 613 | WRITE_ONCE(stutter_pause_test, 0); | 622 | WRITE_ONCE(stutter_pause_test, 0); |
| 614 | if (!torture_must_stop()) | 623 | if (!torture_must_stop()) |