diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2014-01-31 20:37:28 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2014-02-23 12:03:21 -0500 |
commit | 7fafaac5b9ce22cc57777865390520476ad2262d (patch) | |
tree | c857b24b21d277b45803878af0715c817fb4716a /kernel/rcu/rcutorture.c | |
parent | 14562d1cf12b434da2c69b5603a4149ac43f3b48 (diff) |
rcutorture: Fix rcutorture shutdown races
Not all of the rcutorture kthreads waited for kthread_should_stop()
before returning from their top-level functions, and none of them
used torture_shutdown_absorb() properly. These problems can result in
segfaults and hangs at shutdown time, and some recent changes perturbed
timing sufficiently to make them much more probable. This commit
therefore creates a torture_kthread_stopping() function that does the
proper kthread shutdown dance in one centralized location.
Accommodate this grouping by making VERBOSE_TOROUT_STRING() capable of
taking a non-const string as its argument, which allows the new
torture_kthread_stopping() to pass its "title" argument directly to
the updated version of VERBOSE_TOROUT_STRING().
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcu/rcutorture.c')
-rw-r--r-- | kernel/rcu/rcutorture.c | 39 |
1 files changed, 11 insertions, 28 deletions
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 6e9ba51b23b9..bcaafd6cf633 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c | |||
@@ -602,12 +602,13 @@ checkwait: stutter_wait("rcu_torture_boost"); | |||
602 | } while (!torture_must_stop()); | 602 | } while (!torture_must_stop()); |
603 | 603 | ||
604 | /* Clean up and exit. */ | 604 | /* Clean up and exit. */ |
605 | VERBOSE_TOROUT_STRING("rcu_torture_boost task stopping"); | 605 | while (!kthread_should_stop() || rbi.inflight) { |
606 | torture_shutdown_absorb("rcu_torture_boost"); | 606 | torture_shutdown_absorb("rcu_torture_boost"); |
607 | while (!kthread_should_stop() || rbi.inflight) | ||
608 | schedule_timeout_uninterruptible(1); | 607 | schedule_timeout_uninterruptible(1); |
608 | } | ||
609 | smp_mb(); /* order accesses to ->inflight before stack-frame death. */ | 609 | smp_mb(); /* order accesses to ->inflight before stack-frame death. */ |
610 | destroy_rcu_head_on_stack(&rbi.rcu); | 610 | destroy_rcu_head_on_stack(&rbi.rcu); |
611 | torture_kthread_stopping("rcu_torture_boost"); | ||
611 | return 0; | 612 | return 0; |
612 | } | 613 | } |
613 | 614 | ||
@@ -638,10 +639,7 @@ rcu_torture_fqs(void *arg) | |||
638 | } | 639 | } |
639 | stutter_wait("rcu_torture_fqs"); | 640 | stutter_wait("rcu_torture_fqs"); |
640 | } while (!torture_must_stop()); | 641 | } while (!torture_must_stop()); |
641 | VERBOSE_TOROUT_STRING("rcu_torture_fqs task stopping"); | 642 | torture_kthread_stopping("rcu_torture_fqs"); |
642 | torture_shutdown_absorb("rcu_torture_fqs"); | ||
643 | while (!kthread_should_stop()) | ||
644 | schedule_timeout_uninterruptible(1); | ||
645 | return 0; | 643 | return 0; |
646 | } | 644 | } |
647 | 645 | ||
@@ -710,10 +708,7 @@ rcu_torture_writer(void *arg) | |||
710 | rcutorture_record_progress(++rcu_torture_current_version); | 708 | rcutorture_record_progress(++rcu_torture_current_version); |
711 | stutter_wait("rcu_torture_writer"); | 709 | stutter_wait("rcu_torture_writer"); |
712 | } while (!torture_must_stop()); | 710 | } while (!torture_must_stop()); |
713 | VERBOSE_TOROUT_STRING("rcu_torture_writer task stopping"); | 711 | torture_kthread_stopping("rcu_torture_writer"); |
714 | torture_shutdown_absorb("rcu_torture_writer"); | ||
715 | while (!kthread_should_stop()) | ||
716 | schedule_timeout_uninterruptible(1); | ||
717 | return 0; | 712 | return 0; |
718 | } | 713 | } |
719 | 714 | ||
@@ -748,10 +743,7 @@ rcu_torture_fakewriter(void *arg) | |||
748 | stutter_wait("rcu_torture_fakewriter"); | 743 | stutter_wait("rcu_torture_fakewriter"); |
749 | } while (!torture_must_stop()); | 744 | } while (!torture_must_stop()); |
750 | 745 | ||
751 | VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task stopping"); | 746 | torture_kthread_stopping("rcu_torture_fakewriter"); |
752 | torture_shutdown_absorb("rcu_torture_fakewriter"); | ||
753 | while (!kthread_should_stop()) | ||
754 | schedule_timeout_uninterruptible(1); | ||
755 | return 0; | 747 | return 0; |
756 | } | 748 | } |
757 | 749 | ||
@@ -892,12 +884,9 @@ rcu_torture_reader(void *arg) | |||
892 | schedule(); | 884 | schedule(); |
893 | stutter_wait("rcu_torture_reader"); | 885 | stutter_wait("rcu_torture_reader"); |
894 | } while (!torture_must_stop()); | 886 | } while (!torture_must_stop()); |
895 | VERBOSE_TOROUT_STRING("rcu_torture_reader task stopping"); | ||
896 | torture_shutdown_absorb("rcu_torture_reader"); | ||
897 | if (irqreader && cur_ops->irq_capable) | 887 | if (irqreader && cur_ops->irq_capable) |
898 | del_timer_sync(&t); | 888 | del_timer_sync(&t); |
899 | while (!kthread_should_stop()) | 889 | torture_kthread_stopping("rcu_torture_reader"); |
900 | schedule_timeout_uninterruptible(1); | ||
901 | return 0; | 890 | return 0; |
902 | } | 891 | } |
903 | 892 | ||
@@ -1010,7 +999,7 @@ rcu_torture_stats(void *arg) | |||
1010 | rcu_torture_stats_print(); | 999 | rcu_torture_stats_print(); |
1011 | torture_shutdown_absorb("rcu_torture_stats"); | 1000 | torture_shutdown_absorb("rcu_torture_stats"); |
1012 | } while (!torture_must_stop()); | 1001 | } while (!torture_must_stop()); |
1013 | VERBOSE_TOROUT_STRING("rcu_torture_stats task stopping"); | 1002 | torture_kthread_stopping("rcu_torture_stats"); |
1014 | return 0; | 1003 | return 0; |
1015 | } | 1004 | } |
1016 | 1005 | ||
@@ -1171,12 +1160,9 @@ static int rcu_torture_barrier_cbs(void *arg) | |||
1171 | if (atomic_dec_and_test(&barrier_cbs_count)) | 1160 | if (atomic_dec_and_test(&barrier_cbs_count)) |
1172 | wake_up(&barrier_wq); | 1161 | wake_up(&barrier_wq); |
1173 | } while (!torture_must_stop()); | 1162 | } while (!torture_must_stop()); |
1174 | VERBOSE_TOROUT_STRING("rcu_torture_barrier_cbs task stopping"); | ||
1175 | torture_shutdown_absorb("rcu_torture_barrier_cbs"); | ||
1176 | while (!kthread_should_stop()) | ||
1177 | schedule_timeout_interruptible(1); | ||
1178 | cur_ops->cb_barrier(); | 1163 | cur_ops->cb_barrier(); |
1179 | destroy_rcu_head_on_stack(&rcu); | 1164 | destroy_rcu_head_on_stack(&rcu); |
1165 | torture_kthread_stopping("rcu_torture_barrier_cbs"); | ||
1180 | return 0; | 1166 | return 0; |
1181 | } | 1167 | } |
1182 | 1168 | ||
@@ -1207,10 +1193,7 @@ static int rcu_torture_barrier(void *arg) | |||
1207 | n_barrier_successes++; | 1193 | n_barrier_successes++; |
1208 | schedule_timeout_interruptible(HZ / 10); | 1194 | schedule_timeout_interruptible(HZ / 10); |
1209 | } while (!torture_must_stop()); | 1195 | } while (!torture_must_stop()); |
1210 | VERBOSE_TOROUT_STRING("rcu_torture_barrier task stopping"); | 1196 | torture_kthread_stopping("rcu_torture_barrier"); |
1211 | torture_shutdown_absorb("rcu_torture_barrier"); | ||
1212 | while (!kthread_should_stop()) | ||
1213 | schedule_timeout_interruptible(1); | ||
1214 | return 0; | 1197 | return 0; |
1215 | } | 1198 | } |
1216 | 1199 | ||