From e991dbc0770b01b7dc7d6d7660442e83ebd11828 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 31 Jan 2014 14:52:13 -0800 Subject: 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 Reviewed-by: Josh Triplett --- kernel/rcu/rcutorture.c | 63 +++---------------------------------- kernel/torture.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 58 deletions(-) (limited to 'kernel') diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 4329ad14f8dc..897b0f91f899 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -105,7 +105,6 @@ static struct task_struct **reader_tasks; static struct task_struct *stats_task; static struct task_struct *fqs_task; static struct task_struct *boost_tasks[NR_CPUS]; -static struct task_struct *shutdown_task; static struct task_struct *stall_task; static struct task_struct **barrier_cbs_tasks; static struct task_struct *barrier_task; @@ -173,7 +172,6 @@ static u64 notrace rcu_trace_clock_local(void) } #endif /* #else #ifdef CONFIG_RCU_TRACE */ -static unsigned long shutdown_time; /* jiffies to system shutdown. */ static unsigned long boost_starttime; /* jiffies of next boost test start. */ DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ /* and boost task create/destroy. */ @@ -183,9 +181,6 @@ static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */ static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */ static DECLARE_WAIT_QUEUE_HEAD(barrier_wq); -/* Forward reference. */ -static void rcu_torture_cleanup(void); - /* * Allocate an element from the rcu_tortures pool. */ @@ -1086,42 +1081,6 @@ static int rcutorture_booster_init(int cpu) return 0; } -/* - * Cause the rcutorture test to shutdown the system after the test has - * run for the time specified by the shutdown_secs module parameter. - */ -static int -rcu_torture_shutdown(void *arg) -{ - long delta; - unsigned long jiffies_snap; - - VERBOSE_TOROUT_STRING("rcu_torture_shutdown task started"); - jiffies_snap = ACCESS_ONCE(jiffies); - while (ULONG_CMP_LT(jiffies_snap, shutdown_time) && - !kthread_should_stop()) { - delta = shutdown_time - jiffies_snap; - if (verbose) - pr_alert("%s" TORTURE_FLAG - "rcu_torture_shutdown task: %lu jiffies remaining\n", - torture_type, delta); - schedule_timeout_interruptible(delta); - jiffies_snap = ACCESS_ONCE(jiffies); - } - if (kthread_should_stop()) { - VERBOSE_TOROUT_STRING("rcu_torture_shutdown task stopping"); - return 0; - } - - /* OK, shut down the system. */ - - VERBOSE_TOROUT_STRING("rcu_torture_shutdown task shutting down system"); - shutdown_task = NULL; /* Avoid self-kill deadlock. */ - rcu_torture_cleanup(); /* Get the success/failure message. */ - kernel_power_off(); /* Shut down the system. */ - return 0; -} - /* * CPU-stall kthread. It waits as specified by stall_cpu_holdoff, then * induces a CPU stall for the time specified by stall_cpu. @@ -1421,11 +1380,7 @@ rcu_torture_cleanup(void) for_each_possible_cpu(i) rcutorture_booster_cleanup(i); } - if (shutdown_task != NULL) { - VERBOSE_TOROUT_STRING("Stopping rcu_torture_shutdown task"); - kthread_stop(shutdown_task); - } - shutdown_task = NULL; + torture_shutdown_cleanup(); /* Wait for all RCU callbacks to fire. */ @@ -1681,18 +1636,10 @@ rcu_torture_init(void) } } } - if (shutdown_secs > 0) { - shutdown_time = jiffies + shutdown_secs * HZ; - shutdown_task = kthread_create(rcu_torture_shutdown, NULL, - "rcu_torture_shutdown"); - if (IS_ERR(shutdown_task)) { - firsterr = PTR_ERR(shutdown_task); - VERBOSE_TOROUT_ERRSTRING("Failed to create shutdown"); - shutdown_task = NULL; - goto unwind; - } - torture_shuffle_task_register(shutdown_task); - wake_up_process(shutdown_task); + i = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup); + if (i != 0) { + firsterr = i; + goto unwind; } i = torture_onoff_init(onoff_holdoff * HZ, onoff_interval * HZ); if (i != 0) { diff --git a/kernel/torture.c b/kernel/torture.c index 1bafd02d1eed..df2c700e96e4 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -418,6 +418,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. @@ -432,6 +441,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. */ -- cgit v1.2.3-59-g8ed1b