diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2014-01-31 23:52:13 +0100 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2014-02-23 18:03:18 +0100 |
commit | e991dbc0770b01b7dc7d6d7660442e83ebd11828 (patch) | |
tree | e95081adbe3c4e85daeae774a9736af2fcfc1f46 /kernel/torture.c | |
parent | rcutorture: Apply ACCESS_ONCE() to racy fullstop accesses (diff) | |
download | linux-e991dbc0770b01b7dc7d6d7660442e83ebd11828.tar.xz linux-e991dbc0770b01b7dc7d6d7660442e83ebd11828.zip |
rcutorture: Abstract torture_shutdown()
Because auto-shutdown of torture testing is not specific to RCU,
this commit moves the auto-shutdown function to kernel/torture.c.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'kernel/torture.c')
-rw-r--r-- | kernel/torture.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/kernel/torture.c b/kernel/torture.c index 1bafd02d1eed..df2c700e96e4 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -419,6 +419,15 @@ static void torture_shuffle_cleanup(void) EXPORT_SYMBOL_GPL(torture_shuffle_cleanup); /* + * Variables for auto-shutdown. This allows "lights out" torture runs + * to be fully scripted. + */ +static int shutdown_secs; /* desired test duration in seconds. */ +static struct task_struct *shutdown_task; +static unsigned long shutdown_time; /* jiffies to system shutdown. */ +static void (*torture_shutdown_hook)(void); + +/* * Absorb kthreads into a kernel function that won't return, so that * they won't ever access module text or data again. */ @@ -433,6 +442,81 @@ void torture_shutdown_absorb(const char *title) EXPORT_SYMBOL_GPL(torture_shutdown_absorb); /* + * Cause the torture test to shutdown the system after the test has + * run for the time specified by the shutdown_secs parameter. + */ +static int torture_shutdown(void *arg) +{ + long delta; + unsigned long jiffies_snap; + + VERBOSE_TOROUT_STRING("torture_shutdown task started"); + jiffies_snap = jiffies; + while (ULONG_CMP_LT(jiffies_snap, shutdown_time) && + !torture_must_stop()) { + delta = shutdown_time - jiffies_snap; + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_shutdown task: %lu jiffies remaining\n", + torture_type, delta); + schedule_timeout_interruptible(delta); + jiffies_snap = jiffies; + } + if (torture_must_stop()) { + VERBOSE_TOROUT_STRING("torture_shutdown task stopping"); + return 0; + } + + /* OK, shut down the system. */ + + VERBOSE_TOROUT_STRING("torture_shutdown task shutting down system"); + shutdown_task = NULL; /* Avoid self-kill deadlock. */ + torture_shutdown_hook();/* Shut down the enclosing torture test. */ + kernel_power_off(); /* Shut down the system. */ + return 0; +} + +/* + * Start up the shutdown task. + */ +int torture_shutdown_init(int ssecs, void (*cleanup)(void)) +{ + int ret; + + shutdown_secs = ssecs; + torture_shutdown_hook = cleanup; + if (shutdown_secs > 0) { + shutdown_time = jiffies + shutdown_secs * HZ; + shutdown_task = kthread_create(torture_shutdown, NULL, + "torture_shutdown"); + if (IS_ERR(shutdown_task)) { + ret = PTR_ERR(shutdown_task); + VERBOSE_TOROUT_ERRSTRING("Failed to create shutdown"); + shutdown_task = NULL; + return ret; + } + torture_shuffle_task_register(shutdown_task); + wake_up_process(shutdown_task); + } + return 0; +} +EXPORT_SYMBOL_GPL(torture_shutdown_init); + +/* + * Shut down the shutdown task. Say what??? Heh! This can happen if + * the torture module gets an rmmod before the shutdown time arrives. ;-) + */ +void torture_shutdown_cleanup(void) +{ + if (shutdown_task != NULL) { + VERBOSE_TOROUT_STRING("Stopping torture_shutdown task"); + kthread_stop(shutdown_task); + } + shutdown_task = NULL; +} +EXPORT_SYMBOL_GPL(torture_shutdown_cleanup); + +/* * Detect and respond to a system shutdown. */ static int torture_shutdown_notify(struct notifier_block *unused1, |