diff options
author | Len Brown <len.brown@intel.com> | 2009-01-09 03:39:43 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-01-09 03:39:43 -0500 |
commit | b2576e1d4408e134e2188c967b1f28af39cd79d4 (patch) | |
tree | 004f3c82faab760f304ce031d6d2f572e7746a50 /kernel/rcutorture.c | |
parent | 3cc8a5f4ba91f67bbdb81a43a99281a26aab8d77 (diff) | |
parent | 2150edc6c5cf00f7adb54538b9ea2a3e9cedca3f (diff) |
Merge branch 'linus' into release
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r-- | kernel/rcutorture.c | 91 |
1 files changed, 69 insertions, 22 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 85cb90588a55..1cff28db56b6 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/moduleparam.h> | 39 | #include <linux/moduleparam.h> |
40 | #include <linux/percpu.h> | 40 | #include <linux/percpu.h> |
41 | #include <linux/notifier.h> | 41 | #include <linux/notifier.h> |
42 | #include <linux/reboot.h> | ||
42 | #include <linux/freezer.h> | 43 | #include <linux/freezer.h> |
43 | #include <linux/cpu.h> | 44 | #include <linux/cpu.h> |
44 | #include <linux/delay.h> | 45 | #include <linux/delay.h> |
@@ -108,7 +109,6 @@ struct rcu_torture { | |||
108 | int rtort_mbtest; | 109 | int rtort_mbtest; |
109 | }; | 110 | }; |
110 | 111 | ||
111 | static int fullstop = 0; /* stop generating callbacks at test end. */ | ||
112 | static LIST_HEAD(rcu_torture_freelist); | 112 | static LIST_HEAD(rcu_torture_freelist); |
113 | static struct rcu_torture *rcu_torture_current = NULL; | 113 | static struct rcu_torture *rcu_torture_current = NULL; |
114 | static long rcu_torture_current_version = 0; | 114 | static long rcu_torture_current_version = 0; |
@@ -136,6 +136,28 @@ 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. */ | ||
140 | #define FULLSTOP_CLEANUP 2 /* Orderly shutdown. */ | ||
141 | static int fullstop; /* stop generating callbacks at test end. */ | ||
142 | DEFINE_MUTEX(fullstop_mutex); /* protect fullstop transitions and */ | ||
143 | /* spawning of kthreads. */ | ||
144 | |||
145 | /* | ||
146 | * Detect and respond to a signal-based shutdown. | ||
147 | */ | ||
148 | static int | ||
149 | rcutorture_shutdown_notify(struct notifier_block *unused1, | ||
150 | unsigned long unused2, void *unused3) | ||
151 | { | ||
152 | if (fullstop) | ||
153 | return NOTIFY_DONE; | ||
154 | mutex_lock(&fullstop_mutex); | ||
155 | if (!fullstop) | ||
156 | fullstop = FULLSTOP_SHUTDOWN; | ||
157 | mutex_unlock(&fullstop_mutex); | ||
158 | return NOTIFY_DONE; | ||
159 | } | ||
160 | |||
139 | /* | 161 | /* |
140 | * Allocate an element from the rcu_tortures pool. | 162 | * Allocate an element from the rcu_tortures pool. |
141 | */ | 163 | */ |
@@ -199,11 +221,12 @@ rcu_random(struct rcu_random_state *rrsp) | |||
199 | static void | 221 | static void |
200 | rcu_stutter_wait(void) | 222 | rcu_stutter_wait(void) |
201 | { | 223 | { |
202 | while (stutter_pause_test || !rcutorture_runnable) | 224 | while ((stutter_pause_test || !rcutorture_runnable) && !fullstop) { |
203 | if (rcutorture_runnable) | 225 | if (rcutorture_runnable) |
204 | schedule_timeout_interruptible(1); | 226 | schedule_timeout_interruptible(1); |
205 | else | 227 | else |
206 | schedule_timeout_interruptible(round_jiffies_relative(HZ)); | 228 | schedule_timeout_interruptible(round_jiffies_relative(HZ)); |
229 | } | ||
207 | } | 230 | } |
208 | 231 | ||
209 | /* | 232 | /* |
@@ -599,7 +622,7 @@ rcu_torture_writer(void *arg) | |||
599 | rcu_stutter_wait(); | 622 | rcu_stutter_wait(); |
600 | } while (!kthread_should_stop() && !fullstop); | 623 | } while (!kthread_should_stop() && !fullstop); |
601 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); | 624 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); |
602 | while (!kthread_should_stop()) | 625 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) |
603 | schedule_timeout_uninterruptible(1); | 626 | schedule_timeout_uninterruptible(1); |
604 | return 0; | 627 | return 0; |
605 | } | 628 | } |
@@ -624,7 +647,7 @@ rcu_torture_fakewriter(void *arg) | |||
624 | } while (!kthread_should_stop() && !fullstop); | 647 | } while (!kthread_should_stop() && !fullstop); |
625 | 648 | ||
626 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); | 649 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); |
627 | while (!kthread_should_stop()) | 650 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) |
628 | schedule_timeout_uninterruptible(1); | 651 | schedule_timeout_uninterruptible(1); |
629 | return 0; | 652 | return 0; |
630 | } | 653 | } |
@@ -734,7 +757,7 @@ rcu_torture_reader(void *arg) | |||
734 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); | 757 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); |
735 | if (irqreader && cur_ops->irqcapable) | 758 | if (irqreader && cur_ops->irqcapable) |
736 | del_timer_sync(&t); | 759 | del_timer_sync(&t); |
737 | while (!kthread_should_stop()) | 760 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) |
738 | schedule_timeout_uninterruptible(1); | 761 | schedule_timeout_uninterruptible(1); |
739 | return 0; | 762 | return 0; |
740 | } | 763 | } |
@@ -831,7 +854,7 @@ rcu_torture_stats(void *arg) | |||
831 | do { | 854 | do { |
832 | schedule_timeout_interruptible(stat_interval * HZ); | 855 | schedule_timeout_interruptible(stat_interval * HZ); |
833 | rcu_torture_stats_print(); | 856 | rcu_torture_stats_print(); |
834 | } while (!kthread_should_stop()); | 857 | } while (!kthread_should_stop() && !fullstop); |
835 | VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping"); | 858 | VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping"); |
836 | return 0; | 859 | return 0; |
837 | } | 860 | } |
@@ -843,49 +866,52 @@ static int rcu_idle_cpu; /* Force all torture tasks off this CPU */ | |||
843 | */ | 866 | */ |
844 | static void rcu_torture_shuffle_tasks(void) | 867 | static void rcu_torture_shuffle_tasks(void) |
845 | { | 868 | { |
846 | cpumask_t tmp_mask; | 869 | cpumask_var_t tmp_mask; |
847 | int i; | 870 | int i; |
848 | 871 | ||
849 | cpus_setall(tmp_mask); | 872 | if (!alloc_cpumask_var(&tmp_mask, GFP_KERNEL)) |
873 | BUG(); | ||
874 | |||
875 | cpumask_setall(tmp_mask); | ||
850 | get_online_cpus(); | 876 | get_online_cpus(); |
851 | 877 | ||
852 | /* No point in shuffling if there is only one online CPU (ex: UP) */ | 878 | /* No point in shuffling if there is only one online CPU (ex: UP) */ |
853 | if (num_online_cpus() == 1) { | 879 | if (num_online_cpus() == 1) |
854 | put_online_cpus(); | 880 | goto out; |
855 | return; | ||
856 | } | ||
857 | 881 | ||
858 | if (rcu_idle_cpu != -1) | 882 | if (rcu_idle_cpu != -1) |
859 | cpu_clear(rcu_idle_cpu, tmp_mask); | 883 | cpumask_clear_cpu(rcu_idle_cpu, tmp_mask); |
860 | 884 | ||
861 | set_cpus_allowed_ptr(current, &tmp_mask); | 885 | set_cpus_allowed_ptr(current, tmp_mask); |
862 | 886 | ||
863 | if (reader_tasks) { | 887 | if (reader_tasks) { |
864 | for (i = 0; i < nrealreaders; i++) | 888 | for (i = 0; i < nrealreaders; i++) |
865 | if (reader_tasks[i]) | 889 | if (reader_tasks[i]) |
866 | set_cpus_allowed_ptr(reader_tasks[i], | 890 | set_cpus_allowed_ptr(reader_tasks[i], |
867 | &tmp_mask); | 891 | tmp_mask); |
868 | } | 892 | } |
869 | 893 | ||
870 | if (fakewriter_tasks) { | 894 | if (fakewriter_tasks) { |
871 | for (i = 0; i < nfakewriters; i++) | 895 | for (i = 0; i < nfakewriters; i++) |
872 | if (fakewriter_tasks[i]) | 896 | if (fakewriter_tasks[i]) |
873 | set_cpus_allowed_ptr(fakewriter_tasks[i], | 897 | set_cpus_allowed_ptr(fakewriter_tasks[i], |
874 | &tmp_mask); | 898 | tmp_mask); |
875 | } | 899 | } |
876 | 900 | ||
877 | if (writer_task) | 901 | if (writer_task) |
878 | set_cpus_allowed_ptr(writer_task, &tmp_mask); | 902 | set_cpus_allowed_ptr(writer_task, tmp_mask); |
879 | 903 | ||
880 | if (stats_task) | 904 | if (stats_task) |
881 | set_cpus_allowed_ptr(stats_task, &tmp_mask); | 905 | set_cpus_allowed_ptr(stats_task, tmp_mask); |
882 | 906 | ||
883 | if (rcu_idle_cpu == -1) | 907 | if (rcu_idle_cpu == -1) |
884 | rcu_idle_cpu = num_online_cpus() - 1; | 908 | rcu_idle_cpu = num_online_cpus() - 1; |
885 | else | 909 | else |
886 | rcu_idle_cpu--; | 910 | rcu_idle_cpu--; |
887 | 911 | ||
912 | out: | ||
888 | put_online_cpus(); | 913 | put_online_cpus(); |
914 | free_cpumask_var(tmp_mask); | ||
889 | } | 915 | } |
890 | 916 | ||
891 | /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the | 917 | /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the |
@@ -899,7 +925,7 @@ rcu_torture_shuffle(void *arg) | |||
899 | do { | 925 | do { |
900 | schedule_timeout_interruptible(shuffle_interval * HZ); | 926 | schedule_timeout_interruptible(shuffle_interval * HZ); |
901 | rcu_torture_shuffle_tasks(); | 927 | rcu_torture_shuffle_tasks(); |
902 | } while (!kthread_should_stop()); | 928 | } while (!kthread_should_stop() && !fullstop); |
903 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); | 929 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); |
904 | return 0; | 930 | return 0; |
905 | } | 931 | } |
@@ -914,10 +940,10 @@ rcu_torture_stutter(void *arg) | |||
914 | do { | 940 | do { |
915 | schedule_timeout_interruptible(stutter * HZ); | 941 | schedule_timeout_interruptible(stutter * HZ); |
916 | stutter_pause_test = 1; | 942 | stutter_pause_test = 1; |
917 | if (!kthread_should_stop()) | 943 | if (!kthread_should_stop() && !fullstop) |
918 | schedule_timeout_interruptible(stutter * HZ); | 944 | schedule_timeout_interruptible(stutter * HZ); |
919 | stutter_pause_test = 0; | 945 | stutter_pause_test = 0; |
920 | } while (!kthread_should_stop()); | 946 | } while (!kthread_should_stop() && !fullstop); |
921 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); | 947 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); |
922 | return 0; | 948 | return 0; |
923 | } | 949 | } |
@@ -934,12 +960,27 @@ rcu_torture_print_module_parms(char *tag) | |||
934 | stutter, irqreader); | 960 | stutter, irqreader); |
935 | } | 961 | } |
936 | 962 | ||
963 | static struct notifier_block rcutorture_nb = { | ||
964 | .notifier_call = rcutorture_shutdown_notify, | ||
965 | }; | ||
966 | |||
937 | static void | 967 | static void |
938 | rcu_torture_cleanup(void) | 968 | rcu_torture_cleanup(void) |
939 | { | 969 | { |
940 | int i; | 970 | int i; |
941 | 971 | ||
942 | fullstop = 1; | 972 | mutex_lock(&fullstop_mutex); |
973 | if (!fullstop) { | ||
974 | /* If being signaled, let it happen, then exit. */ | ||
975 | mutex_unlock(&fullstop_mutex); | ||
976 | schedule_timeout_interruptible(10 * HZ); | ||
977 | if (cur_ops->cb_barrier != NULL) | ||
978 | cur_ops->cb_barrier(); | ||
979 | return; | ||
980 | } | ||
981 | fullstop = FULLSTOP_CLEANUP; | ||
982 | mutex_unlock(&fullstop_mutex); | ||
983 | unregister_reboot_notifier(&rcutorture_nb); | ||
943 | if (stutter_task) { | 984 | if (stutter_task) { |
944 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); | 985 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); |
945 | kthread_stop(stutter_task); | 986 | kthread_stop(stutter_task); |
@@ -1015,6 +1056,8 @@ rcu_torture_init(void) | |||
1015 | { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, | 1056 | { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, |
1016 | &srcu_ops, &sched_ops, &sched_ops_sync, }; | 1057 | &srcu_ops, &sched_ops, &sched_ops_sync, }; |
1017 | 1058 | ||
1059 | mutex_lock(&fullstop_mutex); | ||
1060 | |||
1018 | /* Process args and tell the world that the torturer is on the job. */ | 1061 | /* Process args and tell the world that the torturer is on the job. */ |
1019 | for (i = 0; i < ARRAY_SIZE(torture_ops); i++) { | 1062 | for (i = 0; i < ARRAY_SIZE(torture_ops); i++) { |
1020 | cur_ops = torture_ops[i]; | 1063 | cur_ops = torture_ops[i]; |
@@ -1024,6 +1067,7 @@ rcu_torture_init(void) | |||
1024 | if (i == ARRAY_SIZE(torture_ops)) { | 1067 | if (i == ARRAY_SIZE(torture_ops)) { |
1025 | printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n", | 1068 | printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n", |
1026 | torture_type); | 1069 | torture_type); |
1070 | mutex_unlock(&fullstop_mutex); | ||
1027 | return (-EINVAL); | 1071 | return (-EINVAL); |
1028 | } | 1072 | } |
1029 | if (cur_ops->init) | 1073 | if (cur_ops->init) |
@@ -1146,9 +1190,12 @@ rcu_torture_init(void) | |||
1146 | goto unwind; | 1190 | goto unwind; |
1147 | } | 1191 | } |
1148 | } | 1192 | } |
1193 | register_reboot_notifier(&rcutorture_nb); | ||
1194 | mutex_unlock(&fullstop_mutex); | ||
1149 | return 0; | 1195 | return 0; |
1150 | 1196 | ||
1151 | unwind: | 1197 | unwind: |
1198 | mutex_unlock(&fullstop_mutex); | ||
1152 | rcu_torture_cleanup(); | 1199 | rcu_torture_cleanup(); |
1153 | return firsterr; | 1200 | return firsterr; |
1154 | } | 1201 | } |