diff options
-rw-r--r-- | Documentation/RCU/torture.txt | 8 | ||||
-rw-r--r-- | kernel/rcutorture.c | 117 |
2 files changed, 120 insertions, 5 deletions
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index af40929e1cb0..d67068d0d2b9 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt | |||
@@ -61,6 +61,14 @@ nreaders This is the number of RCU reading threads supported. | |||
61 | To properly exercise RCU implementations with preemptible | 61 | To properly exercise RCU implementations with preemptible |
62 | read-side critical sections. | 62 | read-side critical sections. |
63 | 63 | ||
64 | onoff_interval | ||
65 | The number of seconds between each attempt to execute a | ||
66 | randomly selected CPU-hotplug operation. Defaults to | ||
67 | zero, which disables CPU hotplugging. In HOTPLUG_CPU=n | ||
68 | kernels, rcutorture will silently refuse to do any | ||
69 | CPU-hotplug operations regardless of what value is | ||
70 | specified for onoff_interval. | ||
71 | |||
64 | shuffle_interval | 72 | shuffle_interval |
65 | The number of seconds to keep the test threads affinitied | 73 | The number of seconds to keep the test threads affinitied |
66 | to a particular subset of the CPUs, defaults to 3 seconds. | 74 | to a particular subset of the CPUs, defaults to 3 seconds. |
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index eed9f46eb0a5..1e422ae1506b 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -64,6 +64,7 @@ static int irqreader = 1; /* RCU readers from irq (timers). */ | |||
64 | static int fqs_duration; /* Duration of bursts (us), 0 to disable. */ | 64 | static int fqs_duration; /* Duration of bursts (us), 0 to disable. */ |
65 | static int fqs_holdoff; /* Hold time within burst (us). */ | 65 | static int fqs_holdoff; /* Hold time within burst (us). */ |
66 | static int fqs_stutter = 3; /* Wait time between bursts (s). */ | 66 | static int fqs_stutter = 3; /* Wait time between bursts (s). */ |
67 | static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ | ||
67 | static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ | 68 | static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ |
68 | static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */ | 69 | static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */ |
69 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ | 70 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ |
@@ -92,6 +93,8 @@ module_param(fqs_holdoff, int, 0444); | |||
92 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); | 93 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); |
93 | module_param(fqs_stutter, int, 0444); | 94 | module_param(fqs_stutter, int, 0444); |
94 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); | 95 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); |
96 | module_param(onoff_interval, int, 0444); | ||
97 | MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); | ||
95 | module_param(shutdown_secs, int, 0444); | 98 | module_param(shutdown_secs, int, 0444); |
96 | MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable."); | 99 | MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable."); |
97 | module_param(test_boost, int, 0444); | 100 | module_param(test_boost, int, 0444); |
@@ -123,6 +126,9 @@ static struct task_struct *stutter_task; | |||
123 | static struct task_struct *fqs_task; | 126 | static struct task_struct *fqs_task; |
124 | static struct task_struct *boost_tasks[NR_CPUS]; | 127 | static struct task_struct *boost_tasks[NR_CPUS]; |
125 | static struct task_struct *shutdown_task; | 128 | static struct task_struct *shutdown_task; |
129 | #ifdef CONFIG_HOTPLUG_CPU | ||
130 | static struct task_struct *onoff_task; | ||
131 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ | ||
126 | 132 | ||
127 | #define RCU_TORTURE_PIPE_LEN 10 | 133 | #define RCU_TORTURE_PIPE_LEN 10 |
128 | 134 | ||
@@ -153,6 +159,10 @@ static long n_rcu_torture_boost_rterror; | |||
153 | static long n_rcu_torture_boost_failure; | 159 | static long n_rcu_torture_boost_failure; |
154 | static long n_rcu_torture_boosts; | 160 | static long n_rcu_torture_boosts; |
155 | static long n_rcu_torture_timers; | 161 | static long n_rcu_torture_timers; |
162 | static long n_offline_attempts; | ||
163 | static long n_offline_successes; | ||
164 | static long n_online_attempts; | ||
165 | static long n_online_successes; | ||
156 | static struct list_head rcu_torture_removed; | 166 | static struct list_head rcu_torture_removed; |
157 | static cpumask_var_t shuffle_tmp_mask; | 167 | static cpumask_var_t shuffle_tmp_mask; |
158 | 168 | ||
@@ -1084,7 +1094,8 @@ rcu_torture_printk(char *page) | |||
1084 | cnt += sprintf(&page[cnt], | 1094 | cnt += sprintf(&page[cnt], |
1085 | "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d " | 1095 | "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d " |
1086 | "rtmbe: %d rtbke: %ld rtbre: %ld " | 1096 | "rtmbe: %d rtbke: %ld rtbre: %ld " |
1087 | "rtbf: %ld rtb: %ld nt: %ld", | 1097 | "rtbf: %ld rtb: %ld nt: %ld " |
1098 | "onoff: %ld/%ld:%ld/%ld", | ||
1088 | rcu_torture_current, | 1099 | rcu_torture_current, |
1089 | rcu_torture_current_version, | 1100 | rcu_torture_current_version, |
1090 | list_empty(&rcu_torture_freelist), | 1101 | list_empty(&rcu_torture_freelist), |
@@ -1096,7 +1107,11 @@ rcu_torture_printk(char *page) | |||
1096 | n_rcu_torture_boost_rterror, | 1107 | n_rcu_torture_boost_rterror, |
1097 | n_rcu_torture_boost_failure, | 1108 | n_rcu_torture_boost_failure, |
1098 | n_rcu_torture_boosts, | 1109 | n_rcu_torture_boosts, |
1099 | n_rcu_torture_timers); | 1110 | n_rcu_torture_timers, |
1111 | n_online_successes, | ||
1112 | n_online_attempts, | ||
1113 | n_offline_successes, | ||
1114 | n_offline_attempts); | ||
1100 | if (atomic_read(&n_rcu_torture_mberror) != 0 || | 1115 | if (atomic_read(&n_rcu_torture_mberror) != 0 || |
1101 | n_rcu_torture_boost_ktrerror != 0 || | 1116 | n_rcu_torture_boost_ktrerror != 0 || |
1102 | n_rcu_torture_boost_rterror != 0 || | 1117 | n_rcu_torture_boost_rterror != 0 || |
@@ -1260,12 +1275,14 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, char *tag) | |||
1260 | "shuffle_interval=%d stutter=%d irqreader=%d " | 1275 | "shuffle_interval=%d stutter=%d irqreader=%d " |
1261 | "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d " | 1276 | "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d " |
1262 | "test_boost=%d/%d test_boost_interval=%d " | 1277 | "test_boost=%d/%d test_boost_interval=%d " |
1263 | "test_boost_duration=%d shutdown_secs=%d\n", | 1278 | "test_boost_duration=%d shutdown_secs=%d " |
1279 | "onoff_interval=%d\n", | ||
1264 | torture_type, tag, nrealreaders, nfakewriters, | 1280 | torture_type, tag, nrealreaders, nfakewriters, |
1265 | stat_interval, verbose, test_no_idle_hz, shuffle_interval, | 1281 | stat_interval, verbose, test_no_idle_hz, shuffle_interval, |
1266 | stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter, | 1282 | stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter, |
1267 | test_boost, cur_ops->can_boost, | 1283 | test_boost, cur_ops->can_boost, |
1268 | test_boost_interval, test_boost_duration, shutdown_secs); | 1284 | test_boost_interval, test_boost_duration, shutdown_secs, |
1285 | onoff_interval); | ||
1269 | } | 1286 | } |
1270 | 1287 | ||
1271 | static struct notifier_block rcutorture_shutdown_nb = { | 1288 | static struct notifier_block rcutorture_shutdown_nb = { |
@@ -1338,7 +1355,7 @@ rcu_torture_shutdown(void *arg) | |||
1338 | schedule_timeout_interruptible(delta); | 1355 | schedule_timeout_interruptible(delta); |
1339 | jiffies_snap = ACCESS_ONCE(jiffies); | 1356 | jiffies_snap = ACCESS_ONCE(jiffies); |
1340 | } | 1357 | } |
1341 | if (ULONG_CMP_LT(jiffies, shutdown_time)) { | 1358 | if (kthread_should_stop()) { |
1342 | VERBOSE_PRINTK_STRING("rcu_torture_shutdown task stopping"); | 1359 | VERBOSE_PRINTK_STRING("rcu_torture_shutdown task stopping"); |
1343 | return 0; | 1360 | return 0; |
1344 | } | 1361 | } |
@@ -1352,6 +1369,94 @@ rcu_torture_shutdown(void *arg) | |||
1352 | return 0; | 1369 | return 0; |
1353 | } | 1370 | } |
1354 | 1371 | ||
1372 | #ifdef CONFIG_HOTPLUG_CPU | ||
1373 | |||
1374 | /* | ||
1375 | * Execute random CPU-hotplug operations at the interval specified | ||
1376 | * by the onoff_interval. | ||
1377 | */ | ||
1378 | static int | ||
1379 | rcu_torture_onoff(void *arg) | ||
1380 | { | ||
1381 | int cpu; | ||
1382 | int maxcpu = -1; | ||
1383 | DEFINE_RCU_RANDOM(rand); | ||
1384 | |||
1385 | VERBOSE_PRINTK_STRING("rcu_torture_onoff task started"); | ||
1386 | for_each_online_cpu(cpu) | ||
1387 | maxcpu = cpu; | ||
1388 | WARN_ON(maxcpu < 0); | ||
1389 | while (!kthread_should_stop()) { | ||
1390 | cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1); | ||
1391 | if (cpu_online(cpu)) { | ||
1392 | if (verbose) | ||
1393 | printk(KERN_ALERT "%s" TORTURE_FLAG | ||
1394 | "rcu_torture_onoff task: offlining %d\n", | ||
1395 | torture_type, cpu); | ||
1396 | n_offline_attempts++; | ||
1397 | if (cpu_down(cpu) == 0) { | ||
1398 | if (verbose) | ||
1399 | printk(KERN_ALERT "%s" TORTURE_FLAG | ||
1400 | "rcu_torture_onoff task: " | ||
1401 | "offlined %d\n", | ||
1402 | torture_type, cpu); | ||
1403 | n_offline_successes++; | ||
1404 | } | ||
1405 | } else { | ||
1406 | if (verbose) | ||
1407 | printk(KERN_ALERT "%s" TORTURE_FLAG | ||
1408 | "rcu_torture_onoff task: onlining %d\n", | ||
1409 | torture_type, cpu); | ||
1410 | n_online_attempts++; | ||
1411 | if (cpu_up(cpu) == 0) { | ||
1412 | if (verbose) | ||
1413 | printk(KERN_ALERT "%s" TORTURE_FLAG | ||
1414 | "rcu_torture_onoff task: " | ||
1415 | "onlined %d\n", | ||
1416 | torture_type, cpu); | ||
1417 | n_online_successes++; | ||
1418 | } | ||
1419 | } | ||
1420 | schedule_timeout_interruptible(onoff_interval * HZ); | ||
1421 | } | ||
1422 | VERBOSE_PRINTK_STRING("rcu_torture_onoff task stopping"); | ||
1423 | return 0; | ||
1424 | } | ||
1425 | |||
1426 | static int | ||
1427 | rcu_torture_onoff_init(void) | ||
1428 | { | ||
1429 | if (onoff_interval <= 0) | ||
1430 | return 0; | ||
1431 | onoff_task = kthread_run(rcu_torture_onoff, NULL, "rcu_torture_onoff"); | ||
1432 | if (IS_ERR(onoff_task)) { | ||
1433 | onoff_task = NULL; | ||
1434 | return PTR_ERR(onoff_task); | ||
1435 | } | ||
1436 | return 0; | ||
1437 | } | ||
1438 | |||
1439 | static void rcu_torture_onoff_cleanup(void) | ||
1440 | { | ||
1441 | if (onoff_task == NULL) | ||
1442 | return; | ||
1443 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_onoff task"); | ||
1444 | kthread_stop(onoff_task); | ||
1445 | } | ||
1446 | |||
1447 | #else /* #ifdef CONFIG_HOTPLUG_CPU */ | ||
1448 | |||
1449 | static void | ||
1450 | rcu_torture_onoff_init(void) | ||
1451 | { | ||
1452 | } | ||
1453 | |||
1454 | static void rcu_torture_onoff_cleanup(void) | ||
1455 | { | ||
1456 | } | ||
1457 | |||
1458 | #endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ | ||
1459 | |||
1355 | static int rcutorture_cpu_notify(struct notifier_block *self, | 1460 | static int rcutorture_cpu_notify(struct notifier_block *self, |
1356 | unsigned long action, void *hcpu) | 1461 | unsigned long action, void *hcpu) |
1357 | { | 1462 | { |
@@ -1460,6 +1565,7 @@ rcu_torture_cleanup(void) | |||
1460 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_shutdown task"); | 1565 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_shutdown task"); |
1461 | kthread_stop(shutdown_task); | 1566 | kthread_stop(shutdown_task); |
1462 | } | 1567 | } |
1568 | rcu_torture_onoff_cleanup(); | ||
1463 | 1569 | ||
1464 | /* Wait for all RCU callbacks to fire. */ | 1570 | /* Wait for all RCU callbacks to fire. */ |
1465 | 1571 | ||
@@ -1687,6 +1793,7 @@ rcu_torture_init(void) | |||
1687 | goto unwind; | 1793 | goto unwind; |
1688 | } | 1794 | } |
1689 | } | 1795 | } |
1796 | rcu_torture_onoff_init(); | ||
1690 | register_reboot_notifier(&rcutorture_shutdown_nb); | 1797 | register_reboot_notifier(&rcutorture_shutdown_nb); |
1691 | rcutorture_record_test_transition(); | 1798 | rcutorture_record_test_transition(); |
1692 | mutex_unlock(&fullstop_mutex); | 1799 | mutex_unlock(&fullstop_mutex); |