diff options
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r-- | kernel/rcutorture.c | 113 |
1 files changed, 68 insertions, 45 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 1cff28db56b6..7c4142a79f0a 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -136,29 +136,47 @@ static int stutter_pause_test = 0; | |||
136 | #endif | 136 | #endif |
137 | int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT; | 137 | int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT; |
138 | 138 | ||
139 | #define FULLSTOP_SHUTDOWN 1 /* Bail due to system shutdown/panic. */ | 139 | /* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ |
140 | #define FULLSTOP_CLEANUP 2 /* Orderly shutdown. */ | 140 | |
141 | static int fullstop; /* stop generating callbacks at test end. */ | 141 | #define FULLSTOP_DONTSTOP 0 /* Normal operation. */ |
142 | DEFINE_MUTEX(fullstop_mutex); /* protect fullstop transitions and */ | 142 | #define FULLSTOP_SHUTDOWN 1 /* System shutdown with rcutorture running. */ |
143 | /* spawning of kthreads. */ | 143 | #define FULLSTOP_RMMOD 2 /* Normal rmmod of rcutorture. */ |
144 | static int fullstop = FULLSTOP_RMMOD; | ||
145 | DEFINE_MUTEX(fullstop_mutex); /* Protect fullstop transitions and spawning */ | ||
146 | /* of kthreads. */ | ||
144 | 147 | ||
145 | /* | 148 | /* |
146 | * Detect and respond to a signal-based shutdown. | 149 | * Detect and respond to a system shutdown. |
147 | */ | 150 | */ |
148 | static int | 151 | static int |
149 | rcutorture_shutdown_notify(struct notifier_block *unused1, | 152 | rcutorture_shutdown_notify(struct notifier_block *unused1, |
150 | unsigned long unused2, void *unused3) | 153 | unsigned long unused2, void *unused3) |
151 | { | 154 | { |
152 | if (fullstop) | ||
153 | return NOTIFY_DONE; | ||
154 | mutex_lock(&fullstop_mutex); | 155 | mutex_lock(&fullstop_mutex); |
155 | if (!fullstop) | 156 | if (fullstop == FULLSTOP_DONTSTOP) |
156 | fullstop = FULLSTOP_SHUTDOWN; | 157 | fullstop = FULLSTOP_SHUTDOWN; |
158 | else | ||
159 | printk(KERN_WARNING /* but going down anyway, so... */ | ||
160 | "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); | ||
157 | mutex_unlock(&fullstop_mutex); | 161 | mutex_unlock(&fullstop_mutex); |
158 | return NOTIFY_DONE; | 162 | return NOTIFY_DONE; |
159 | } | 163 | } |
160 | 164 | ||
161 | /* | 165 | /* |
166 | * Absorb kthreads into a kernel function that won't return, so that | ||
167 | * they won't ever access module text or data again. | ||
168 | */ | ||
169 | static void rcutorture_shutdown_absorb(char *title) | ||
170 | { | ||
171 | if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) { | ||
172 | printk(KERN_NOTICE | ||
173 | "rcutorture thread %s parking due to system shutdown\n", | ||
174 | title); | ||
175 | schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | /* | ||
162 | * Allocate an element from the rcu_tortures pool. | 180 | * Allocate an element from the rcu_tortures pool. |
163 | */ | 181 | */ |
164 | static struct rcu_torture * | 182 | static struct rcu_torture * |
@@ -219,13 +237,14 @@ rcu_random(struct rcu_random_state *rrsp) | |||
219 | } | 237 | } |
220 | 238 | ||
221 | static void | 239 | static void |
222 | rcu_stutter_wait(void) | 240 | rcu_stutter_wait(char *title) |
223 | { | 241 | { |
224 | while ((stutter_pause_test || !rcutorture_runnable) && !fullstop) { | 242 | while (stutter_pause_test || !rcutorture_runnable) { |
225 | if (rcutorture_runnable) | 243 | if (rcutorture_runnable) |
226 | schedule_timeout_interruptible(1); | 244 | schedule_timeout_interruptible(1); |
227 | else | 245 | else |
228 | schedule_timeout_interruptible(round_jiffies_relative(HZ)); | 246 | schedule_timeout_interruptible(round_jiffies_relative(HZ)); |
247 | rcutorture_shutdown_absorb(title); | ||
229 | } | 248 | } |
230 | } | 249 | } |
231 | 250 | ||
@@ -287,7 +306,7 @@ rcu_torture_cb(struct rcu_head *p) | |||
287 | int i; | 306 | int i; |
288 | struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu); | 307 | struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu); |
289 | 308 | ||
290 | if (fullstop) { | 309 | if (fullstop != FULLSTOP_DONTSTOP) { |
291 | /* Test is ending, just drop callbacks on the floor. */ | 310 | /* Test is ending, just drop callbacks on the floor. */ |
292 | /* The next initialization will pick up the pieces. */ | 311 | /* The next initialization will pick up the pieces. */ |
293 | return; | 312 | return; |
@@ -619,10 +638,11 @@ rcu_torture_writer(void *arg) | |||
619 | } | 638 | } |
620 | rcu_torture_current_version++; | 639 | rcu_torture_current_version++; |
621 | oldbatch = cur_ops->completed(); | 640 | oldbatch = cur_ops->completed(); |
622 | rcu_stutter_wait(); | 641 | rcu_stutter_wait("rcu_torture_writer"); |
623 | } while (!kthread_should_stop() && !fullstop); | 642 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); |
624 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); | 643 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); |
625 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) | 644 | rcutorture_shutdown_absorb("rcu_torture_writer"); |
645 | while (!kthread_should_stop()) | ||
626 | schedule_timeout_uninterruptible(1); | 646 | schedule_timeout_uninterruptible(1); |
627 | return 0; | 647 | return 0; |
628 | } | 648 | } |
@@ -643,11 +663,12 @@ rcu_torture_fakewriter(void *arg) | |||
643 | schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); | 663 | schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); |
644 | udelay(rcu_random(&rand) & 0x3ff); | 664 | udelay(rcu_random(&rand) & 0x3ff); |
645 | cur_ops->sync(); | 665 | cur_ops->sync(); |
646 | rcu_stutter_wait(); | 666 | rcu_stutter_wait("rcu_torture_fakewriter"); |
647 | } while (!kthread_should_stop() && !fullstop); | 667 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); |
648 | 668 | ||
649 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); | 669 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); |
650 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) | 670 | rcutorture_shutdown_absorb("rcu_torture_fakewriter"); |
671 | while (!kthread_should_stop()) | ||
651 | schedule_timeout_uninterruptible(1); | 672 | schedule_timeout_uninterruptible(1); |
652 | return 0; | 673 | return 0; |
653 | } | 674 | } |
@@ -752,12 +773,13 @@ rcu_torture_reader(void *arg) | |||
752 | preempt_enable(); | 773 | preempt_enable(); |
753 | cur_ops->readunlock(idx); | 774 | cur_ops->readunlock(idx); |
754 | schedule(); | 775 | schedule(); |
755 | rcu_stutter_wait(); | 776 | rcu_stutter_wait("rcu_torture_reader"); |
756 | } while (!kthread_should_stop() && !fullstop); | 777 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); |
757 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); | 778 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); |
779 | rcutorture_shutdown_absorb("rcu_torture_reader"); | ||
758 | if (irqreader && cur_ops->irqcapable) | 780 | if (irqreader && cur_ops->irqcapable) |
759 | del_timer_sync(&t); | 781 | del_timer_sync(&t); |
760 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) | 782 | while (!kthread_should_stop()) |
761 | schedule_timeout_uninterruptible(1); | 783 | schedule_timeout_uninterruptible(1); |
762 | return 0; | 784 | return 0; |
763 | } | 785 | } |
@@ -854,7 +876,8 @@ rcu_torture_stats(void *arg) | |||
854 | do { | 876 | do { |
855 | schedule_timeout_interruptible(stat_interval * HZ); | 877 | schedule_timeout_interruptible(stat_interval * HZ); |
856 | rcu_torture_stats_print(); | 878 | rcu_torture_stats_print(); |
857 | } while (!kthread_should_stop() && !fullstop); | 879 | rcutorture_shutdown_absorb("rcu_torture_stats"); |
880 | } while (!kthread_should_stop()); | ||
858 | VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping"); | 881 | VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping"); |
859 | return 0; | 882 | return 0; |
860 | } | 883 | } |
@@ -866,52 +889,49 @@ static int rcu_idle_cpu; /* Force all torture tasks off this CPU */ | |||
866 | */ | 889 | */ |
867 | static void rcu_torture_shuffle_tasks(void) | 890 | static void rcu_torture_shuffle_tasks(void) |
868 | { | 891 | { |
869 | cpumask_var_t tmp_mask; | 892 | cpumask_t tmp_mask; |
870 | int i; | 893 | int i; |
871 | 894 | ||
872 | if (!alloc_cpumask_var(&tmp_mask, GFP_KERNEL)) | 895 | cpus_setall(tmp_mask); |
873 | BUG(); | ||
874 | |||
875 | cpumask_setall(tmp_mask); | ||
876 | get_online_cpus(); | 896 | get_online_cpus(); |
877 | 897 | ||
878 | /* No point in shuffling if there is only one online CPU (ex: UP) */ | 898 | /* No point in shuffling if there is only one online CPU (ex: UP) */ |
879 | if (num_online_cpus() == 1) | 899 | if (num_online_cpus() == 1) { |
880 | goto out; | 900 | put_online_cpus(); |
901 | return; | ||
902 | } | ||
881 | 903 | ||
882 | if (rcu_idle_cpu != -1) | 904 | if (rcu_idle_cpu != -1) |
883 | cpumask_clear_cpu(rcu_idle_cpu, tmp_mask); | 905 | cpu_clear(rcu_idle_cpu, tmp_mask); |
884 | 906 | ||
885 | set_cpus_allowed_ptr(current, tmp_mask); | 907 | set_cpus_allowed_ptr(current, &tmp_mask); |
886 | 908 | ||
887 | if (reader_tasks) { | 909 | if (reader_tasks) { |
888 | for (i = 0; i < nrealreaders; i++) | 910 | for (i = 0; i < nrealreaders; i++) |
889 | if (reader_tasks[i]) | 911 | if (reader_tasks[i]) |
890 | set_cpus_allowed_ptr(reader_tasks[i], | 912 | set_cpus_allowed_ptr(reader_tasks[i], |
891 | tmp_mask); | 913 | &tmp_mask); |
892 | } | 914 | } |
893 | 915 | ||
894 | if (fakewriter_tasks) { | 916 | if (fakewriter_tasks) { |
895 | for (i = 0; i < nfakewriters; i++) | 917 | for (i = 0; i < nfakewriters; i++) |
896 | if (fakewriter_tasks[i]) | 918 | if (fakewriter_tasks[i]) |
897 | set_cpus_allowed_ptr(fakewriter_tasks[i], | 919 | set_cpus_allowed_ptr(fakewriter_tasks[i], |
898 | tmp_mask); | 920 | &tmp_mask); |
899 | } | 921 | } |
900 | 922 | ||
901 | if (writer_task) | 923 | if (writer_task) |
902 | set_cpus_allowed_ptr(writer_task, tmp_mask); | 924 | set_cpus_allowed_ptr(writer_task, &tmp_mask); |
903 | 925 | ||
904 | if (stats_task) | 926 | if (stats_task) |
905 | set_cpus_allowed_ptr(stats_task, tmp_mask); | 927 | set_cpus_allowed_ptr(stats_task, &tmp_mask); |
906 | 928 | ||
907 | if (rcu_idle_cpu == -1) | 929 | if (rcu_idle_cpu == -1) |
908 | rcu_idle_cpu = num_online_cpus() - 1; | 930 | rcu_idle_cpu = num_online_cpus() - 1; |
909 | else | 931 | else |
910 | rcu_idle_cpu--; | 932 | rcu_idle_cpu--; |
911 | 933 | ||
912 | out: | ||
913 | put_online_cpus(); | 934 | put_online_cpus(); |
914 | free_cpumask_var(tmp_mask); | ||
915 | } | 935 | } |
916 | 936 | ||
917 | /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the | 937 | /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the |
@@ -925,7 +945,8 @@ rcu_torture_shuffle(void *arg) | |||
925 | do { | 945 | do { |
926 | schedule_timeout_interruptible(shuffle_interval * HZ); | 946 | schedule_timeout_interruptible(shuffle_interval * HZ); |
927 | rcu_torture_shuffle_tasks(); | 947 | rcu_torture_shuffle_tasks(); |
928 | } while (!kthread_should_stop() && !fullstop); | 948 | rcutorture_shutdown_absorb("rcu_torture_shuffle"); |
949 | } while (!kthread_should_stop()); | ||
929 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); | 950 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); |
930 | return 0; | 951 | return 0; |
931 | } | 952 | } |
@@ -940,10 +961,11 @@ rcu_torture_stutter(void *arg) | |||
940 | do { | 961 | do { |
941 | schedule_timeout_interruptible(stutter * HZ); | 962 | schedule_timeout_interruptible(stutter * HZ); |
942 | stutter_pause_test = 1; | 963 | stutter_pause_test = 1; |
943 | if (!kthread_should_stop() && !fullstop) | 964 | if (!kthread_should_stop()) |
944 | schedule_timeout_interruptible(stutter * HZ); | 965 | schedule_timeout_interruptible(stutter * HZ); |
945 | stutter_pause_test = 0; | 966 | stutter_pause_test = 0; |
946 | } while (!kthread_should_stop() && !fullstop); | 967 | rcutorture_shutdown_absorb("rcu_torture_stutter"); |
968 | } while (!kthread_should_stop()); | ||
947 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); | 969 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); |
948 | return 0; | 970 | return 0; |
949 | } | 971 | } |
@@ -970,15 +992,16 @@ rcu_torture_cleanup(void) | |||
970 | int i; | 992 | int i; |
971 | 993 | ||
972 | mutex_lock(&fullstop_mutex); | 994 | mutex_lock(&fullstop_mutex); |
973 | if (!fullstop) { | 995 | if (fullstop == FULLSTOP_SHUTDOWN) { |
974 | /* If being signaled, let it happen, then exit. */ | 996 | printk(KERN_WARNING /* but going down anyway, so... */ |
997 | "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); | ||
975 | mutex_unlock(&fullstop_mutex); | 998 | mutex_unlock(&fullstop_mutex); |
976 | schedule_timeout_interruptible(10 * HZ); | 999 | schedule_timeout_uninterruptible(10); |
977 | if (cur_ops->cb_barrier != NULL) | 1000 | if (cur_ops->cb_barrier != NULL) |
978 | cur_ops->cb_barrier(); | 1001 | cur_ops->cb_barrier(); |
979 | return; | 1002 | return; |
980 | } | 1003 | } |
981 | fullstop = FULLSTOP_CLEANUP; | 1004 | fullstop = FULLSTOP_RMMOD; |
982 | mutex_unlock(&fullstop_mutex); | 1005 | mutex_unlock(&fullstop_mutex); |
983 | unregister_reboot_notifier(&rcutorture_nb); | 1006 | unregister_reboot_notifier(&rcutorture_nb); |
984 | if (stutter_task) { | 1007 | if (stutter_task) { |
@@ -1078,7 +1101,7 @@ rcu_torture_init(void) | |||
1078 | else | 1101 | else |
1079 | nrealreaders = 2 * num_online_cpus(); | 1102 | nrealreaders = 2 * num_online_cpus(); |
1080 | rcu_torture_print_module_parms("Start of test"); | 1103 | rcu_torture_print_module_parms("Start of test"); |
1081 | fullstop = 0; | 1104 | fullstop = FULLSTOP_DONTSTOP; |
1082 | 1105 | ||
1083 | /* Set up the freelist. */ | 1106 | /* Set up the freelist. */ |
1084 | 1107 | ||