diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2011-11-04 14:44:12 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-12-11 13:31:46 -0500 |
commit | d5f546d834ddc44539651e9955eb3577b0a3eb8b (patch) | |
tree | 8262c6af876ff49d7f60772690255588b8833bd5 /kernel/rcutorture.c | |
parent | b807fbff3102bcac76ed9157d834dc20bb3d133b (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.c | 68 |
1 files changed, 64 insertions, 4 deletions
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. */ | |||
61 | static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ | 61 | static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ |
62 | static int stutter = 5; /* Start/stop testing interval (in sec) */ | 62 | static int stutter = 5; /* Start/stop testing interval (in sec) */ |
63 | static int irqreader = 1; /* RCU readers from irq (timers). */ | 63 | static int irqreader = 1; /* RCU readers from irq (timers). */ |
64 | static int fqs_duration = 0; /* Duration of bursts (us), 0 to disable. */ | 64 | static int fqs_duration; /* Duration of bursts (us), 0 to disable. */ |
65 | static int fqs_holdoff = 0; /* 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 shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ | ||
67 | static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */ | 68 | static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */ |
68 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ | 69 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ |
69 | static int test_boost_duration = 4; /* Duration of each boost test, seconds. */ | 70 | static int test_boost_duration = 4; /* Duration of each boost test, seconds. */ |
@@ -91,6 +92,8 @@ module_param(fqs_holdoff, int, 0444); | |||
91 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); | 92 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); |
92 | module_param(fqs_stutter, int, 0444); | 93 | module_param(fqs_stutter, int, 0444); |
93 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); | 94 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); |
95 | module_param(shutdown_secs, int, 0444); | ||
96 | MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable."); | ||
94 | module_param(test_boost, int, 0444); | 97 | module_param(test_boost, int, 0444); |
95 | MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes."); | 98 | MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes."); |
96 | module_param(test_boost_interval, int, 0444); | 99 | module_param(test_boost_interval, int, 0444); |
@@ -119,6 +122,7 @@ static struct task_struct *shuffler_task; | |||
119 | static struct task_struct *stutter_task; | 122 | static struct task_struct *stutter_task; |
120 | static struct task_struct *fqs_task; | 123 | static struct task_struct *fqs_task; |
121 | static struct task_struct *boost_tasks[NR_CPUS]; | 124 | static struct task_struct *boost_tasks[NR_CPUS]; |
125 | static 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 | ||
174 | static unsigned long shutdown_time; /* jiffies to system shutdown. */ | ||
170 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ | 175 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ |
171 | DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ | 176 | DEFINE_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 | */ |
183 | static DEFINE_MUTEX(fullstop_mutex); | 188 | static DEFINE_MUTEX(fullstop_mutex); |
184 | 189 | ||
190 | /* Forward reference. */ | ||
191 | static 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 | ||
1261 | static struct notifier_block rcutorture_shutdown_nb = { | 1269 | static 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 | */ | ||
1320 | static int | ||
1321 | rcu_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 | |||
1308 | static int rcutorture_cpu_notify(struct notifier_block *self, | 1353 | static 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); |