aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutorture.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2011-11-04 14:44:12 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2011-12-11 13:31:46 -0500
commitd5f546d834ddc44539651e9955eb3577b0a3eb8b (patch)
tree8262c6af876ff49d7f60772690255588b8833bd5 /kernel/rcutorture.c
parentb807fbff3102bcac76ed9157d834dc20bb3d133b (diff)
rcu: Add rcutorture system-shutdown capability
Although it is easy to run rcutorture tests under KVM, there is currently no nice way to run such a test for a fixed time period, collect all of the rcutorture data, and then shut the system down cleanly. This commit therefore adds an rcutorture module parameter named "shutdown_secs" that specified the run duration in seconds, after which rcutorture terminates the test and powers the system down. The default value for "shutdown_secs" is zero, which disables shutdown. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r--kernel/rcutorture.c68
1 files changed, 64 insertions, 4 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index df35228e743..ce84091291b 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);