diff --git a/include/linux/torture.h b/include/linux/torture.h index 428d2712be04..31d69930e5cf 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -65,7 +65,6 @@ extern struct mutex fullstop_mutex; /* Definitions for online/offline exerciser. */ int torture_onoff_init(long ooholdoff, long oointerval); -void torture_onoff_cleanup(void); char *torture_onoff_stats(char *page); bool torture_onoff_failures(void); @@ -80,14 +79,13 @@ unsigned long torture_random(struct torture_random_state *trsp); /* Task shuffler, which causes CPUs to occasionally go idle. */ void torture_shuffle_task_register(struct task_struct *tp); int torture_shuffle_init(long shuffint); -void torture_shuffle_cleanup(void); /* Shutdown task absorption, for when the tasks cannot safely be killed. */ void torture_shutdown_absorb(const char *title); /* Initialization and cleanup. */ - void torture_init_begin(char *ttype, bool v); void torture_init_end(void); +bool torture_cleanup(void); #endif /* __LINUX_TORTURE_H */ diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 93aca2f9261e..68a689fc6ffa 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1423,21 +1423,13 @@ rcu_torture_cleanup(void) int i; rcutorture_record_test_transition(); - mutex_lock(&fullstop_mutex); - if (fullstop == FULLSTOP_SHUTDOWN) { - pr_warn(/* but going down anyway, so... */ - "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); - mutex_unlock(&fullstop_mutex); - schedule_timeout_uninterruptible(10); + if (torture_cleanup()) { if (cur_ops->cb_barrier != NULL) cur_ops->cb_barrier(); return; } - fullstop = FULLSTOP_RMMOD; - mutex_unlock(&fullstop_mutex); unregister_reboot_notifier(&rcutorture_shutdown_nb); - torture_shuffle_cleanup(); /* Must be first task cleaned up. */ rcu_torture_barrier_cleanup(); rcu_torture_stall_cleanup(); if (stutter_task) { @@ -1501,7 +1493,6 @@ rcu_torture_cleanup(void) kthread_stop(shutdown_task); } shutdown_task = NULL; - torture_onoff_cleanup(); /* Wait for all RCU callbacks to fire. */ diff --git a/kernel/torture.c b/kernel/torture.c index 828d0b1a49b8..41ae5cc3c4c3 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -199,7 +199,7 @@ EXPORT_SYMBOL_GPL(torture_onoff_init); /* * Clean up after online/offline testing. */ -void torture_onoff_cleanup(void) +static void torture_onoff_cleanup(void) { #ifdef CONFIG_HOTPLUG_CPU if (onoff_task == NULL) @@ -403,7 +403,7 @@ EXPORT_SYMBOL_GPL(torture_shuffle_init); /* * Stop the shuffling. */ -void torture_shuffle_cleanup(void) +static void torture_shuffle_cleanup(void) { torture_shuffle_task_unregister_all(); if (shuffler_task) { @@ -453,3 +453,29 @@ void __init torture_init_end(void) mutex_unlock(&fullstop_mutex); } EXPORT_SYMBOL_GPL(torture_init_end); + +/* + * Clean up torture module. Please note that this is -not- invoked via + * the usual module_exit() mechanism, but rather by an explicit call from + * the client torture module. Returns true if a race with system shutdown + * is detected. + * + * This must be called before the caller starts shutting down its own + * kthreads. + */ +bool torture_cleanup(void) +{ + mutex_lock(&fullstop_mutex); + if (fullstop == FULLSTOP_SHUTDOWN) { + pr_warn("Concurrent rmmod and shutdown illegal!\n"); + mutex_unlock(&fullstop_mutex); + schedule_timeout_uninterruptible(10); + return true; + } + fullstop = FULLSTOP_RMMOD; + mutex_unlock(&fullstop_mutex); + torture_shuffle_cleanup(); + torture_onoff_cleanup(); + return false; +} +EXPORT_SYMBOL_GPL(torture_cleanup);