aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/RCU/torture.txt5
-rw-r--r--kernel/rcutorture.c68
2 files changed, 69 insertions, 4 deletions
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index 783d6c134d3f..af40929e1cb0 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -66,6 +66,11 @@ shuffle_interval
66 to a particular subset of the CPUs, defaults to 3 seconds. 66 to a particular subset of the CPUs, defaults to 3 seconds.
67 Used in conjunction with test_no_idle_hz. 67 Used in conjunction with test_no_idle_hz.
68 68
69shutdown_secs The number of seconds to run the test before terminating
70 the test and powering off the system. The default is
71 zero, which disables test termination and system shutdown.
72 This capability is useful for automated testing.
73
69stat_interval The number of seconds between output of torture 74stat_interval The number of seconds between output of torture
70 statistics (via printk()). Regardless of the interval, 75 statistics (via printk()). Regardless of the interval,
71 statistics are printed when the module is unloaded. 76 statistics are printed when the module is unloaded.
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index df35228e743b..ce84091291b5 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -61,9 +61,10 @@ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */
61static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ 61static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
62static int stutter = 5; /* Start/stop testing interval (in sec) */ 62static int stutter = 5; /* Start/stop testing interval (in sec) */
63static int irqreader = 1; /* RCU readers from irq (timers). */ 63static int irqreader = 1; /* RCU readers from irq (timers). */
64static int fqs_duration = 0; /* Duration of bursts (us), 0 to disable. */ 64static int fqs_duration; /* Duration of bursts (us), 0 to disable. */
65static int fqs_holdoff = 0; /* Hold time within burst (us). */ 65static int fqs_holdoff; /* Hold time within burst (us). */
66static int fqs_stutter = 3; /* Wait time between bursts (s). */ 66static int fqs_stutter = 3; /* Wait time between bursts (s). */
67static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */
67static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */ 68static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */
68static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ 69static int test_boost_interval = 7; /* Interval between boost tests, seconds. */
69static int test_boost_duration = 4; /* Duration of each boost test, seconds. */ 70static int test_boost_duration = 4; /* Duration of each boost test, seconds. */
@@ -91,6 +92,8 @@ module_param(fqs_holdoff, int, 0444);
91MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); 92MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
92module_param(fqs_stutter, int, 0444); 93module_param(fqs_stutter, int, 0444);
93MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); 94MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
95module_param(shutdown_secs, int, 0444);
96MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable.");
94module_param(test_boost, int, 0444); 97module_param(test_boost, int, 0444);
95MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes."); 98MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
96module_param(test_boost_interval, int, 0444); 99module_param(test_boost_interval, int, 0444);
@@ -119,6 +122,7 @@ static struct task_struct *shuffler_task;
119static struct task_struct *stutter_task; 122static struct task_struct *stutter_task;
120static struct task_struct *fqs_task; 123static struct task_struct *fqs_task;
121static struct task_struct *boost_tasks[NR_CPUS]; 124static struct task_struct *boost_tasks[NR_CPUS];
125static struct task_struct *shutdown_task;
122 126
123#define RCU_TORTURE_PIPE_LEN 10 127#define RCU_TORTURE_PIPE_LEN 10
124 128
@@ -167,6 +171,7 @@ int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
167#define rcu_can_boost() 0 171#define rcu_can_boost() 0
168#endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ 172#endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
169 173
174static unsigned long shutdown_time; /* jiffies to system shutdown. */
170static unsigned long boost_starttime; /* jiffies of next boost test start. */ 175static unsigned long boost_starttime; /* jiffies of next boost test start. */
171DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ 176DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */
172 /* and boost task create/destroy. */ 177 /* and boost task create/destroy. */
@@ -182,6 +187,9 @@ static int fullstop = FULLSTOP_RMMOD;
182 */ 187 */
183static DEFINE_MUTEX(fullstop_mutex); 188static DEFINE_MUTEX(fullstop_mutex);
184 189
190/* Forward reference. */
191static void rcu_torture_cleanup(void);
192
185/* 193/*
186 * Detect and respond to a system shutdown. 194 * Detect and respond to a system shutdown.
187 */ 195 */
@@ -1250,12 +1258,12 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, char *tag)
1250 "shuffle_interval=%d stutter=%d irqreader=%d " 1258 "shuffle_interval=%d stutter=%d irqreader=%d "
1251 "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d " 1259 "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
1252 "test_boost=%d/%d test_boost_interval=%d " 1260 "test_boost=%d/%d test_boost_interval=%d "
1253 "test_boost_duration=%d\n", 1261 "test_boost_duration=%d shutdown_secs=%d\n",
1254 torture_type, tag, nrealreaders, nfakewriters, 1262 torture_type, tag, nrealreaders, nfakewriters,
1255 stat_interval, verbose, test_no_idle_hz, shuffle_interval, 1263 stat_interval, verbose, test_no_idle_hz, shuffle_interval,
1256 stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter, 1264 stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
1257 test_boost, cur_ops->can_boost, 1265 test_boost, cur_ops->can_boost,
1258 test_boost_interval, test_boost_duration); 1266 test_boost_interval, test_boost_duration, shutdown_secs);
1259} 1267}
1260 1268
1261static struct notifier_block rcutorture_shutdown_nb = { 1269static struct notifier_block rcutorture_shutdown_nb = {
@@ -1305,6 +1313,43 @@ static int rcutorture_booster_init(int cpu)
1305 return 0; 1313 return 0;
1306} 1314}
1307 1315
1316/*
1317 * Cause the rcutorture test to shutdown the system after the test has
1318 * run for the time specified by the shutdown_secs module parameter.
1319 */
1320static int
1321rcu_torture_shutdown(void *arg)
1322{
1323 long delta;
1324 unsigned long jiffies_snap;
1325
1326 VERBOSE_PRINTK_STRING("rcu_torture_shutdown task started");
1327 jiffies_snap = ACCESS_ONCE(jiffies);
1328 while (ULONG_CMP_LT(jiffies_snap, shutdown_time) &&
1329 !kthread_should_stop()) {
1330 delta = shutdown_time - jiffies_snap;
1331 if (verbose)
1332 printk(KERN_ALERT "%s" TORTURE_FLAG
1333 "rcu_torture_shutdown task: %lu "
1334 "jiffies remaining\n",
1335 torture_type, delta);
1336 schedule_timeout_interruptible(delta);
1337 jiffies_snap = ACCESS_ONCE(jiffies);
1338 }
1339 if (ULONG_CMP_LT(jiffies, shutdown_time)) {
1340 VERBOSE_PRINTK_STRING("rcu_torture_shutdown task stopping");
1341 return 0;
1342 }
1343
1344 /* OK, shut down the system. */
1345
1346 VERBOSE_PRINTK_STRING("rcu_torture_shutdown task shutting down system");
1347 shutdown_task = NULL; /* Avoid self-kill deadlock. */
1348 rcu_torture_cleanup(); /* Get the success/failure message. */
1349 kernel_power_off(); /* Shut down the system. */
1350 return 0;
1351}
1352
1308static int rcutorture_cpu_notify(struct notifier_block *self, 1353static int rcutorture_cpu_notify(struct notifier_block *self,
1309 unsigned long action, void *hcpu) 1354 unsigned long action, void *hcpu)
1310{ 1355{
@@ -1409,6 +1454,10 @@ rcu_torture_cleanup(void)
1409 for_each_possible_cpu(i) 1454 for_each_possible_cpu(i)
1410 rcutorture_booster_cleanup(i); 1455 rcutorture_booster_cleanup(i);
1411 } 1456 }
1457 if (shutdown_task != NULL) {
1458 VERBOSE_PRINTK_STRING("Stopping rcu_torture_shutdown task");
1459 kthread_stop(shutdown_task);
1460 }
1412 1461
1413 /* Wait for all RCU callbacks to fire. */ 1462 /* Wait for all RCU callbacks to fire. */
1414 1463
@@ -1625,6 +1674,17 @@ rcu_torture_init(void)
1625 } 1674 }
1626 } 1675 }
1627 } 1676 }
1677 if (shutdown_secs > 0) {
1678 shutdown_time = jiffies + shutdown_secs * HZ;
1679 shutdown_task = kthread_run(rcu_torture_shutdown, NULL,
1680 "rcu_torture_shutdown");
1681 if (IS_ERR(shutdown_task)) {
1682 firsterr = PTR_ERR(shutdown_task);
1683 VERBOSE_PRINTK_ERRSTRING("Failed to create shutdown");
1684 shutdown_task = NULL;
1685 goto unwind;
1686 }
1687 }
1628 register_reboot_notifier(&rcutorture_shutdown_nb); 1688 register_reboot_notifier(&rcutorture_shutdown_nb);
1629 rcutorture_record_test_transition(); 1689 rcutorture_record_test_transition();
1630 mutex_unlock(&fullstop_mutex); 1690 mutex_unlock(&fullstop_mutex);