diff options
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r-- | kernel/rcutorture.c | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 31dea01c85fd..e1f3a8c96724 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/stat.h> | 46 | #include <linux/stat.h> |
47 | #include <linux/srcu.h> | 47 | #include <linux/srcu.h> |
48 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
49 | #include <linux/trace_clock.h> | ||
49 | #include <asm/byteorder.h> | 50 | #include <asm/byteorder.h> |
50 | 51 | ||
51 | MODULE_LICENSE("GPL"); | 52 | MODULE_LICENSE("GPL"); |
@@ -207,6 +208,20 @@ MODULE_PARM_DESC(rcutorture_runnable, "Start rcutorture at boot"); | |||
207 | #define rcu_can_boost() 0 | 208 | #define rcu_can_boost() 0 |
208 | #endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ | 209 | #endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ |
209 | 210 | ||
211 | #ifdef CONFIG_RCU_TRACE | ||
212 | static u64 notrace rcu_trace_clock_local(void) | ||
213 | { | ||
214 | u64 ts = trace_clock_local(); | ||
215 | unsigned long __maybe_unused ts_rem = do_div(ts, NSEC_PER_USEC); | ||
216 | return ts; | ||
217 | } | ||
218 | #else /* #ifdef CONFIG_RCU_TRACE */ | ||
219 | static u64 notrace rcu_trace_clock_local(void) | ||
220 | { | ||
221 | return 0ULL; | ||
222 | } | ||
223 | #endif /* #else #ifdef CONFIG_RCU_TRACE */ | ||
224 | |||
210 | static unsigned long shutdown_time; /* jiffies to system shutdown. */ | 225 | static unsigned long shutdown_time; /* jiffies to system shutdown. */ |
211 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ | 226 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ |
212 | DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ | 227 | DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ |
@@ -845,7 +860,7 @@ static int rcu_torture_boost(void *arg) | |||
845 | /* Wait for the next test interval. */ | 860 | /* Wait for the next test interval. */ |
846 | oldstarttime = boost_starttime; | 861 | oldstarttime = boost_starttime; |
847 | while (ULONG_CMP_LT(jiffies, oldstarttime)) { | 862 | while (ULONG_CMP_LT(jiffies, oldstarttime)) { |
848 | schedule_timeout_uninterruptible(1); | 863 | schedule_timeout_interruptible(oldstarttime - jiffies); |
849 | rcu_stutter_wait("rcu_torture_boost"); | 864 | rcu_stutter_wait("rcu_torture_boost"); |
850 | if (kthread_should_stop() || | 865 | if (kthread_should_stop() || |
851 | fullstop != FULLSTOP_DONTSTOP) | 866 | fullstop != FULLSTOP_DONTSTOP) |
@@ -1028,7 +1043,6 @@ void rcutorture_trace_dump(void) | |||
1028 | return; | 1043 | return; |
1029 | if (atomic_xchg(&beenhere, 1) != 0) | 1044 | if (atomic_xchg(&beenhere, 1) != 0) |
1030 | return; | 1045 | return; |
1031 | do_trace_rcu_torture_read(cur_ops->name, (struct rcu_head *)~0UL); | ||
1032 | ftrace_dump(DUMP_ALL); | 1046 | ftrace_dump(DUMP_ALL); |
1033 | } | 1047 | } |
1034 | 1048 | ||
@@ -1042,13 +1056,16 @@ static void rcu_torture_timer(unsigned long unused) | |||
1042 | { | 1056 | { |
1043 | int idx; | 1057 | int idx; |
1044 | int completed; | 1058 | int completed; |
1059 | int completed_end; | ||
1045 | static DEFINE_RCU_RANDOM(rand); | 1060 | static DEFINE_RCU_RANDOM(rand); |
1046 | static DEFINE_SPINLOCK(rand_lock); | 1061 | static DEFINE_SPINLOCK(rand_lock); |
1047 | struct rcu_torture *p; | 1062 | struct rcu_torture *p; |
1048 | int pipe_count; | 1063 | int pipe_count; |
1064 | unsigned long long ts; | ||
1049 | 1065 | ||
1050 | idx = cur_ops->readlock(); | 1066 | idx = cur_ops->readlock(); |
1051 | completed = cur_ops->completed(); | 1067 | completed = cur_ops->completed(); |
1068 | ts = rcu_trace_clock_local(); | ||
1052 | p = rcu_dereference_check(rcu_torture_current, | 1069 | p = rcu_dereference_check(rcu_torture_current, |
1053 | rcu_read_lock_bh_held() || | 1070 | rcu_read_lock_bh_held() || |
1054 | rcu_read_lock_sched_held() || | 1071 | rcu_read_lock_sched_held() || |
@@ -1058,7 +1075,6 @@ static void rcu_torture_timer(unsigned long unused) | |||
1058 | cur_ops->readunlock(idx); | 1075 | cur_ops->readunlock(idx); |
1059 | return; | 1076 | return; |
1060 | } | 1077 | } |
1061 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
1062 | if (p->rtort_mbtest == 0) | 1078 | if (p->rtort_mbtest == 0) |
1063 | atomic_inc(&n_rcu_torture_mberror); | 1079 | atomic_inc(&n_rcu_torture_mberror); |
1064 | spin_lock(&rand_lock); | 1080 | spin_lock(&rand_lock); |
@@ -1071,10 +1087,14 @@ static void rcu_torture_timer(unsigned long unused) | |||
1071 | /* Should not happen, but... */ | 1087 | /* Should not happen, but... */ |
1072 | pipe_count = RCU_TORTURE_PIPE_LEN; | 1088 | pipe_count = RCU_TORTURE_PIPE_LEN; |
1073 | } | 1089 | } |
1074 | if (pipe_count > 1) | 1090 | completed_end = cur_ops->completed(); |
1091 | if (pipe_count > 1) { | ||
1092 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts, | ||
1093 | completed, completed_end); | ||
1075 | rcutorture_trace_dump(); | 1094 | rcutorture_trace_dump(); |
1095 | } | ||
1076 | __this_cpu_inc(rcu_torture_count[pipe_count]); | 1096 | __this_cpu_inc(rcu_torture_count[pipe_count]); |
1077 | completed = cur_ops->completed() - completed; | 1097 | completed = completed_end - completed; |
1078 | if (completed > RCU_TORTURE_PIPE_LEN) { | 1098 | if (completed > RCU_TORTURE_PIPE_LEN) { |
1079 | /* Should not happen, but... */ | 1099 | /* Should not happen, but... */ |
1080 | completed = RCU_TORTURE_PIPE_LEN; | 1100 | completed = RCU_TORTURE_PIPE_LEN; |
@@ -1094,11 +1114,13 @@ static int | |||
1094 | rcu_torture_reader(void *arg) | 1114 | rcu_torture_reader(void *arg) |
1095 | { | 1115 | { |
1096 | int completed; | 1116 | int completed; |
1117 | int completed_end; | ||
1097 | int idx; | 1118 | int idx; |
1098 | DEFINE_RCU_RANDOM(rand); | 1119 | DEFINE_RCU_RANDOM(rand); |
1099 | struct rcu_torture *p; | 1120 | struct rcu_torture *p; |
1100 | int pipe_count; | 1121 | int pipe_count; |
1101 | struct timer_list t; | 1122 | struct timer_list t; |
1123 | unsigned long long ts; | ||
1102 | 1124 | ||
1103 | VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); | 1125 | VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); |
1104 | set_user_nice(current, 19); | 1126 | set_user_nice(current, 19); |
@@ -1112,6 +1134,7 @@ rcu_torture_reader(void *arg) | |||
1112 | } | 1134 | } |
1113 | idx = cur_ops->readlock(); | 1135 | idx = cur_ops->readlock(); |
1114 | completed = cur_ops->completed(); | 1136 | completed = cur_ops->completed(); |
1137 | ts = rcu_trace_clock_local(); | ||
1115 | p = rcu_dereference_check(rcu_torture_current, | 1138 | p = rcu_dereference_check(rcu_torture_current, |
1116 | rcu_read_lock_bh_held() || | 1139 | rcu_read_lock_bh_held() || |
1117 | rcu_read_lock_sched_held() || | 1140 | rcu_read_lock_sched_held() || |
@@ -1122,7 +1145,6 @@ rcu_torture_reader(void *arg) | |||
1122 | schedule_timeout_interruptible(HZ); | 1145 | schedule_timeout_interruptible(HZ); |
1123 | continue; | 1146 | continue; |
1124 | } | 1147 | } |
1125 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
1126 | if (p->rtort_mbtest == 0) | 1148 | if (p->rtort_mbtest == 0) |
1127 | atomic_inc(&n_rcu_torture_mberror); | 1149 | atomic_inc(&n_rcu_torture_mberror); |
1128 | cur_ops->read_delay(&rand); | 1150 | cur_ops->read_delay(&rand); |
@@ -1132,10 +1154,14 @@ rcu_torture_reader(void *arg) | |||
1132 | /* Should not happen, but... */ | 1154 | /* Should not happen, but... */ |
1133 | pipe_count = RCU_TORTURE_PIPE_LEN; | 1155 | pipe_count = RCU_TORTURE_PIPE_LEN; |
1134 | } | 1156 | } |
1135 | if (pipe_count > 1) | 1157 | completed_end = cur_ops->completed(); |
1158 | if (pipe_count > 1) { | ||
1159 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, | ||
1160 | ts, completed, completed_end); | ||
1136 | rcutorture_trace_dump(); | 1161 | rcutorture_trace_dump(); |
1162 | } | ||
1137 | __this_cpu_inc(rcu_torture_count[pipe_count]); | 1163 | __this_cpu_inc(rcu_torture_count[pipe_count]); |
1138 | completed = cur_ops->completed() - completed; | 1164 | completed = completed_end - completed; |
1139 | if (completed > RCU_TORTURE_PIPE_LEN) { | 1165 | if (completed > RCU_TORTURE_PIPE_LEN) { |
1140 | /* Should not happen, but... */ | 1166 | /* Should not happen, but... */ |
1141 | completed = RCU_TORTURE_PIPE_LEN; | 1167 | completed = RCU_TORTURE_PIPE_LEN; |
@@ -1301,19 +1327,35 @@ static void rcu_torture_shuffle_tasks(void) | |||
1301 | set_cpus_allowed_ptr(reader_tasks[i], | 1327 | set_cpus_allowed_ptr(reader_tasks[i], |
1302 | shuffle_tmp_mask); | 1328 | shuffle_tmp_mask); |
1303 | } | 1329 | } |
1304 | |||
1305 | if (fakewriter_tasks) { | 1330 | if (fakewriter_tasks) { |
1306 | for (i = 0; i < nfakewriters; i++) | 1331 | for (i = 0; i < nfakewriters; i++) |
1307 | if (fakewriter_tasks[i]) | 1332 | if (fakewriter_tasks[i]) |
1308 | set_cpus_allowed_ptr(fakewriter_tasks[i], | 1333 | set_cpus_allowed_ptr(fakewriter_tasks[i], |
1309 | shuffle_tmp_mask); | 1334 | shuffle_tmp_mask); |
1310 | } | 1335 | } |
1311 | |||
1312 | if (writer_task) | 1336 | if (writer_task) |
1313 | set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask); | 1337 | set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask); |
1314 | |||
1315 | if (stats_task) | 1338 | if (stats_task) |
1316 | set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask); | 1339 | set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask); |
1340 | if (stutter_task) | ||
1341 | set_cpus_allowed_ptr(stutter_task, shuffle_tmp_mask); | ||
1342 | if (fqs_task) | ||
1343 | set_cpus_allowed_ptr(fqs_task, shuffle_tmp_mask); | ||
1344 | if (shutdown_task) | ||
1345 | set_cpus_allowed_ptr(shutdown_task, shuffle_tmp_mask); | ||
1346 | #ifdef CONFIG_HOTPLUG_CPU | ||
1347 | if (onoff_task) | ||
1348 | set_cpus_allowed_ptr(onoff_task, shuffle_tmp_mask); | ||
1349 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ | ||
1350 | if (stall_task) | ||
1351 | set_cpus_allowed_ptr(stall_task, shuffle_tmp_mask); | ||
1352 | if (barrier_cbs_tasks) | ||
1353 | for (i = 0; i < n_barrier_cbs; i++) | ||
1354 | if (barrier_cbs_tasks[i]) | ||
1355 | set_cpus_allowed_ptr(barrier_cbs_tasks[i], | ||
1356 | shuffle_tmp_mask); | ||
1357 | if (barrier_task) | ||
1358 | set_cpus_allowed_ptr(barrier_task, shuffle_tmp_mask); | ||
1317 | 1359 | ||
1318 | if (rcu_idle_cpu == -1) | 1360 | if (rcu_idle_cpu == -1) |
1319 | rcu_idle_cpu = num_online_cpus() - 1; | 1361 | rcu_idle_cpu = num_online_cpus() - 1; |
@@ -1749,7 +1791,7 @@ static int rcu_torture_barrier_init(void) | |||
1749 | barrier_cbs_wq = | 1791 | barrier_cbs_wq = |
1750 | kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]), | 1792 | kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]), |
1751 | GFP_KERNEL); | 1793 | GFP_KERNEL); |
1752 | if (barrier_cbs_tasks == NULL || barrier_cbs_wq == 0) | 1794 | if (barrier_cbs_tasks == NULL || !barrier_cbs_wq) |
1753 | return -ENOMEM; | 1795 | return -ENOMEM; |
1754 | for (i = 0; i < n_barrier_cbs; i++) { | 1796 | for (i = 0; i < n_barrier_cbs; i++) { |
1755 | init_waitqueue_head(&barrier_cbs_wq[i]); | 1797 | init_waitqueue_head(&barrier_cbs_wq[i]); |