diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2014-01-28 18:29:21 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2014-02-23 12:01:05 -0500 |
commit | 3808dc9fab05913060626d7f0edd0f195cb9dcab (patch) | |
tree | 5db578f420dc657197fd34b3a9a2c20bf79e0de3 /kernel/rcu/rcutorture.c | |
parent | f67a33561e6e5463b548219df98130da95f2e4a7 (diff) |
rcutorture: Abstract torture_shuffle()
The torture_shuffle() function forces each CPU in turn to go idle
periodically in order to check for problems interacting with per-CPU
variables and with dyntick-idle mode. Because this sort of debugging
is not specific to RCU, this commit abstracts that functionality.
This in turn requires abstracting some additional infrastructure.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'kernel/rcu/rcutorture.c')
-rw-r--r-- | kernel/rcu/rcutorture.c | 124 |
1 files changed, 15 insertions, 109 deletions
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index a868758a6f9c..0380696f1844 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c | |||
@@ -106,7 +106,6 @@ static struct task_struct *writer_task; | |||
106 | static struct task_struct **fakewriter_tasks; | 106 | static struct task_struct **fakewriter_tasks; |
107 | static struct task_struct **reader_tasks; | 107 | static struct task_struct **reader_tasks; |
108 | static struct task_struct *stats_task; | 108 | static struct task_struct *stats_task; |
109 | static struct task_struct *shuffler_task; | ||
110 | static struct task_struct *stutter_task; | 109 | static struct task_struct *stutter_task; |
111 | static struct task_struct *fqs_task; | 110 | static struct task_struct *fqs_task; |
112 | static struct task_struct *boost_tasks[NR_CPUS]; | 111 | static struct task_struct *boost_tasks[NR_CPUS]; |
@@ -161,7 +160,6 @@ static int max_online; | |||
161 | static long n_barrier_attempts; | 160 | static long n_barrier_attempts; |
162 | static long n_barrier_successes; | 161 | static long n_barrier_successes; |
163 | static struct list_head rcu_torture_removed; | 162 | static struct list_head rcu_torture_removed; |
164 | static cpumask_var_t shuffle_tmp_mask; | ||
165 | 163 | ||
166 | static int stutter_pause_test; | 164 | static int stutter_pause_test; |
167 | 165 | ||
@@ -1080,90 +1078,6 @@ rcu_torture_stats(void *arg) | |||
1080 | return 0; | 1078 | return 0; |
1081 | } | 1079 | } |
1082 | 1080 | ||
1083 | static int rcu_idle_cpu; /* Force all torture tasks off this CPU */ | ||
1084 | |||
1085 | /* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case | ||
1086 | * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs. | ||
1087 | */ | ||
1088 | static void rcu_torture_shuffle_tasks(void) | ||
1089 | { | ||
1090 | int i; | ||
1091 | |||
1092 | cpumask_setall(shuffle_tmp_mask); | ||
1093 | get_online_cpus(); | ||
1094 | |||
1095 | /* No point in shuffling if there is only one online CPU (ex: UP) */ | ||
1096 | if (num_online_cpus() == 1) { | ||
1097 | put_online_cpus(); | ||
1098 | return; | ||
1099 | } | ||
1100 | |||
1101 | if (rcu_idle_cpu != -1) | ||
1102 | cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask); | ||
1103 | |||
1104 | set_cpus_allowed_ptr(current, shuffle_tmp_mask); | ||
1105 | |||
1106 | if (reader_tasks) { | ||
1107 | for (i = 0; i < nrealreaders; i++) | ||
1108 | if (reader_tasks[i]) | ||
1109 | set_cpus_allowed_ptr(reader_tasks[i], | ||
1110 | shuffle_tmp_mask); | ||
1111 | } | ||
1112 | if (fakewriter_tasks) { | ||
1113 | for (i = 0; i < nfakewriters; i++) | ||
1114 | if (fakewriter_tasks[i]) | ||
1115 | set_cpus_allowed_ptr(fakewriter_tasks[i], | ||
1116 | shuffle_tmp_mask); | ||
1117 | } | ||
1118 | if (writer_task) | ||
1119 | set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask); | ||
1120 | if (stats_task) | ||
1121 | set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask); | ||
1122 | if (stutter_task) | ||
1123 | set_cpus_allowed_ptr(stutter_task, shuffle_tmp_mask); | ||
1124 | if (fqs_task) | ||
1125 | set_cpus_allowed_ptr(fqs_task, shuffle_tmp_mask); | ||
1126 | if (shutdown_task) | ||
1127 | set_cpus_allowed_ptr(shutdown_task, shuffle_tmp_mask); | ||
1128 | #ifdef CONFIG_HOTPLUG_CPU | ||
1129 | if (onoff_task) | ||
1130 | set_cpus_allowed_ptr(onoff_task, shuffle_tmp_mask); | ||
1131 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ | ||
1132 | if (stall_task) | ||
1133 | set_cpus_allowed_ptr(stall_task, shuffle_tmp_mask); | ||
1134 | if (barrier_cbs_tasks) | ||
1135 | for (i = 0; i < n_barrier_cbs; i++) | ||
1136 | if (barrier_cbs_tasks[i]) | ||
1137 | set_cpus_allowed_ptr(barrier_cbs_tasks[i], | ||
1138 | shuffle_tmp_mask); | ||
1139 | if (barrier_task) | ||
1140 | set_cpus_allowed_ptr(barrier_task, shuffle_tmp_mask); | ||
1141 | |||
1142 | if (rcu_idle_cpu == -1) | ||
1143 | rcu_idle_cpu = num_online_cpus() - 1; | ||
1144 | else | ||
1145 | rcu_idle_cpu--; | ||
1146 | |||
1147 | put_online_cpus(); | ||
1148 | } | ||
1149 | |||
1150 | /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the | ||
1151 | * system to become idle at a time and cut off its timer ticks. This is meant | ||
1152 | * to test the support for such tickless idle CPU in RCU. | ||
1153 | */ | ||
1154 | static int | ||
1155 | rcu_torture_shuffle(void *arg) | ||
1156 | { | ||
1157 | VERBOSE_TOROUT_STRING("rcu_torture_shuffle task started"); | ||
1158 | do { | ||
1159 | schedule_timeout_interruptible(shuffle_interval * HZ); | ||
1160 | rcu_torture_shuffle_tasks(); | ||
1161 | torture_shutdown_absorb("rcu_torture_shuffle"); | ||
1162 | } while (!kthread_should_stop()); | ||
1163 | VERBOSE_TOROUT_STRING("rcu_torture_shuffle task stopping"); | ||
1164 | return 0; | ||
1165 | } | ||
1166 | |||
1167 | /* Cause the rcutorture test to "stutter", starting and stopping all | 1081 | /* Cause the rcutorture test to "stutter", starting and stopping all |
1168 | * threads periodically. | 1082 | * threads periodically. |
1169 | */ | 1083 | */ |
@@ -1397,6 +1311,7 @@ rcu_torture_onoff_init(void) | |||
1397 | onoff_task = NULL; | 1311 | onoff_task = NULL; |
1398 | return ret; | 1312 | return ret; |
1399 | } | 1313 | } |
1314 | torture_shuffle_task_register(onoff_task); | ||
1400 | return 0; | 1315 | return 0; |
1401 | } | 1316 | } |
1402 | 1317 | ||
@@ -1468,6 +1383,7 @@ static int __init rcu_torture_stall_init(void) | |||
1468 | stall_task = NULL; | 1383 | stall_task = NULL; |
1469 | return ret; | 1384 | return ret; |
1470 | } | 1385 | } |
1386 | torture_shuffle_task_register(stall_task); | ||
1471 | return 0; | 1387 | return 0; |
1472 | } | 1388 | } |
1473 | 1389 | ||
@@ -1594,6 +1510,7 @@ static int rcu_torture_barrier_init(void) | |||
1594 | barrier_cbs_tasks[i] = NULL; | 1510 | barrier_cbs_tasks[i] = NULL; |
1595 | return ret; | 1511 | return ret; |
1596 | } | 1512 | } |
1513 | torture_shuffle_task_register(barrier_cbs_tasks[i]); | ||
1597 | } | 1514 | } |
1598 | barrier_task = kthread_run(rcu_torture_barrier, NULL, | 1515 | barrier_task = kthread_run(rcu_torture_barrier, NULL, |
1599 | "rcu_torture_barrier"); | 1516 | "rcu_torture_barrier"); |
@@ -1602,6 +1519,7 @@ static int rcu_torture_barrier_init(void) | |||
1602 | VERBOSE_TOROUT_ERRSTRING("Failed to create rcu_torture_barrier"); | 1519 | VERBOSE_TOROUT_ERRSTRING("Failed to create rcu_torture_barrier"); |
1603 | barrier_task = NULL; | 1520 | barrier_task = NULL; |
1604 | } | 1521 | } |
1522 | torture_shuffle_task_register(barrier_task); | ||
1605 | return 0; | 1523 | return 0; |
1606 | } | 1524 | } |
1607 | 1525 | ||
@@ -1674,6 +1592,8 @@ rcu_torture_cleanup(void) | |||
1674 | fullstop = FULLSTOP_RMMOD; | 1592 | fullstop = FULLSTOP_RMMOD; |
1675 | mutex_unlock(&fullstop_mutex); | 1593 | mutex_unlock(&fullstop_mutex); |
1676 | unregister_reboot_notifier(&rcutorture_shutdown_nb); | 1594 | unregister_reboot_notifier(&rcutorture_shutdown_nb); |
1595 | |||
1596 | torture_shuffle_cleanup(); /* Must be first task cleaned up. */ | ||
1677 | rcu_torture_barrier_cleanup(); | 1597 | rcu_torture_barrier_cleanup(); |
1678 | rcu_torture_stall_cleanup(); | 1598 | rcu_torture_stall_cleanup(); |
1679 | if (stutter_task) { | 1599 | if (stutter_task) { |
@@ -1681,12 +1601,6 @@ rcu_torture_cleanup(void) | |||
1681 | kthread_stop(stutter_task); | 1601 | kthread_stop(stutter_task); |
1682 | } | 1602 | } |
1683 | stutter_task = NULL; | 1603 | stutter_task = NULL; |
1684 | if (shuffler_task) { | ||
1685 | VERBOSE_TOROUT_STRING("Stopping rcu_torture_shuffle task"); | ||
1686 | kthread_stop(shuffler_task); | ||
1687 | free_cpumask_var(shuffle_tmp_mask); | ||
1688 | } | ||
1689 | shuffler_task = NULL; | ||
1690 | 1604 | ||
1691 | if (writer_task) { | 1605 | if (writer_task) { |
1692 | VERBOSE_TOROUT_STRING("Stopping rcu_torture_writer task"); | 1606 | VERBOSE_TOROUT_STRING("Stopping rcu_torture_writer task"); |
@@ -1904,6 +1818,7 @@ rcu_torture_init(void) | |||
1904 | writer_task = NULL; | 1818 | writer_task = NULL; |
1905 | goto unwind; | 1819 | goto unwind; |
1906 | } | 1820 | } |
1821 | torture_shuffle_task_register(writer_task); | ||
1907 | wake_up_process(writer_task); | 1822 | wake_up_process(writer_task); |
1908 | fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]), | 1823 | fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]), |
1909 | GFP_KERNEL); | 1824 | GFP_KERNEL); |
@@ -1922,6 +1837,7 @@ rcu_torture_init(void) | |||
1922 | fakewriter_tasks[i] = NULL; | 1837 | fakewriter_tasks[i] = NULL; |
1923 | goto unwind; | 1838 | goto unwind; |
1924 | } | 1839 | } |
1840 | torture_shuffle_task_register(fakewriter_tasks[i]); | ||
1925 | } | 1841 | } |
1926 | reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]), | 1842 | reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]), |
1927 | GFP_KERNEL); | 1843 | GFP_KERNEL); |
@@ -1940,6 +1856,7 @@ rcu_torture_init(void) | |||
1940 | reader_tasks[i] = NULL; | 1856 | reader_tasks[i] = NULL; |
1941 | goto unwind; | 1857 | goto unwind; |
1942 | } | 1858 | } |
1859 | torture_shuffle_task_register(reader_tasks[i]); | ||
1943 | } | 1860 | } |
1944 | if (stat_interval > 0) { | 1861 | if (stat_interval > 0) { |
1945 | VERBOSE_TOROUT_STRING("Creating rcu_torture_stats task"); | 1862 | VERBOSE_TOROUT_STRING("Creating rcu_torture_stats task"); |
@@ -1951,26 +1868,12 @@ rcu_torture_init(void) | |||
1951 | stats_task = NULL; | 1868 | stats_task = NULL; |
1952 | goto unwind; | 1869 | goto unwind; |
1953 | } | 1870 | } |
1871 | torture_shuffle_task_register(stats_task); | ||
1954 | } | 1872 | } |
1955 | if (test_no_idle_hz) { | 1873 | if (test_no_idle_hz) { |
1956 | rcu_idle_cpu = num_online_cpus() - 1; | 1874 | firsterr = torture_shuffle_init(shuffle_interval * HZ); |
1957 | 1875 | if (firsterr) | |
1958 | if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) { | ||
1959 | firsterr = -ENOMEM; | ||
1960 | VERBOSE_TOROUT_ERRSTRING("Failed to alloc mask"); | ||
1961 | goto unwind; | 1876 | goto unwind; |
1962 | } | ||
1963 | |||
1964 | /* Create the shuffler thread */ | ||
1965 | shuffler_task = kthread_run(rcu_torture_shuffle, NULL, | ||
1966 | "rcu_torture_shuffle"); | ||
1967 | if (IS_ERR(shuffler_task)) { | ||
1968 | free_cpumask_var(shuffle_tmp_mask); | ||
1969 | firsterr = PTR_ERR(shuffler_task); | ||
1970 | VERBOSE_TOROUT_ERRSTRING("Failed to create shuffler"); | ||
1971 | shuffler_task = NULL; | ||
1972 | goto unwind; | ||
1973 | } | ||
1974 | } | 1877 | } |
1975 | if (stutter < 0) | 1878 | if (stutter < 0) |
1976 | stutter = 0; | 1879 | stutter = 0; |
@@ -1984,6 +1887,7 @@ rcu_torture_init(void) | |||
1984 | stutter_task = NULL; | 1887 | stutter_task = NULL; |
1985 | goto unwind; | 1888 | goto unwind; |
1986 | } | 1889 | } |
1890 | torture_shuffle_task_register(stutter_task); | ||
1987 | } | 1891 | } |
1988 | if (fqs_duration < 0) | 1892 | if (fqs_duration < 0) |
1989 | fqs_duration = 0; | 1893 | fqs_duration = 0; |
@@ -1997,6 +1901,7 @@ rcu_torture_init(void) | |||
1997 | fqs_task = NULL; | 1901 | fqs_task = NULL; |
1998 | goto unwind; | 1902 | goto unwind; |
1999 | } | 1903 | } |
1904 | torture_shuffle_task_register(fqs_task); | ||
2000 | } | 1905 | } |
2001 | if (test_boost_interval < 1) | 1906 | if (test_boost_interval < 1) |
2002 | test_boost_interval = 1; | 1907 | test_boost_interval = 1; |
@@ -2027,6 +1932,7 @@ rcu_torture_init(void) | |||
2027 | shutdown_task = NULL; | 1932 | shutdown_task = NULL; |
2028 | goto unwind; | 1933 | goto unwind; |
2029 | } | 1934 | } |
1935 | torture_shuffle_task_register(shutdown_task); | ||
2030 | wake_up_process(shutdown_task); | 1936 | wake_up_process(shutdown_task); |
2031 | } | 1937 | } |
2032 | i = rcu_torture_onoff_init(); | 1938 | i = rcu_torture_onoff_init(); |