torture: Address race in module cleanup
authorDavidlohr Bueso <dave@stgolabs.net>
Fri, 12 Sep 2014 03:40:21 +0000 (20:40 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Tue, 16 Sep 2014 20:41:06 +0000 (13:41 -0700)
When performing module cleanups by calling torture_cleanup() the
'torture_type' string in nullified However, callers are not necessarily
done, and might still need to reference the variable. This impacts
both rcutorture and locktorture, causing printing things like:

[   94.226618] (null)-torture: Stopping lock_torture_writer task
[   94.226624] (null)-torture: Stopping lock_torture_stats task

Thus delay this operation until the very end of the cleanup process.
The consequence (which shouldn't matter for this kid of program) is,
of course, that we delay the window between rmmod and modprobing,
for instance in module_torture_begin().

Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
include/linux/torture.h
kernel/locking/locktorture.c
kernel/rcu/rcutorture.c
kernel/torture.c

index fec46f8c08eb1c0f6eb42196c0c1d355f4dd0786..7759fc3c622d4af42753175a89b7dad0bd6898ec 100644 (file)
@@ -77,7 +77,8 @@ int torture_stutter_init(int s);
 /* Initialization and cleanup. */
 bool torture_init_begin(char *ttype, bool v, int *runnable);
 void torture_init_end(void);
-bool torture_cleanup(void);
+bool torture_cleanup_begin(void);
+void torture_cleanup_end(void);
 bool torture_must_stop(void);
 bool torture_must_stop_irq(void);
 void torture_kthread_stopping(char *title);
index de703a769c1dae1cd61aff14906dd2844423e5c1..988267cc92c1da2952f20637331f62327e3a798c 100644 (file)
@@ -361,7 +361,7 @@ static void lock_torture_cleanup(void)
 {
        int i;
 
-       if (torture_cleanup())
+       if (torture_cleanup_begin())
                return;
 
        if (writer_tasks) {
@@ -384,6 +384,7 @@ static void lock_torture_cleanup(void)
        else
                lock_torture_print_module_parms(cur_ops,
                                                "End of test: SUCCESS");
+       torture_cleanup_end();
 }
 
 static int __init lock_torture_init(void)
index 6d1509500d2be3925607f1d9d47d2fadd323f4d2..04c4b5afb759b4f02878b81ab8382c3ea650ae4a 100644 (file)
@@ -1514,7 +1514,7 @@ rcu_torture_cleanup(void)
        int i;
 
        rcutorture_record_test_transition();
-       if (torture_cleanup()) {
+       if (torture_cleanup_begin()) {
                if (cur_ops->cb_barrier != NULL)
                        cur_ops->cb_barrier();
                return;
@@ -1566,6 +1566,7 @@ rcu_torture_cleanup(void)
                                               "End of test: RCU_HOTPLUG");
        else
                rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
+       torture_cleanup_end();
 }
 
 #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
index ede8b25ec1ae3e76a76e93798a2081b6309fef9a..dd70993c266c38785510ab09f0315d1f1775d05b 100644 (file)
@@ -633,8 +633,13 @@ EXPORT_SYMBOL_GPL(torture_init_end);
  *
  * This must be called before the caller starts shutting down its own
  * kthreads.
+ *
+ * Both torture_cleanup_begin() and torture_cleanup_end() must be paired,
+ * in order to correctly perform the cleanup. They are separated because
+ * threads can still need to reference the torture_type type, thus nullify
+ * only after completing all other relevant calls.
  */
-bool torture_cleanup(void)
+bool torture_cleanup_begin(void)
 {
        mutex_lock(&fullstop_mutex);
        if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
@@ -649,12 +654,17 @@ bool torture_cleanup(void)
        torture_shuffle_cleanup();
        torture_stutter_cleanup();
        torture_onoff_cleanup();
+       return false;
+}
+EXPORT_SYMBOL_GPL(torture_cleanup_begin);
+
+void torture_cleanup_end(void)
+{
        mutex_lock(&fullstop_mutex);
        torture_type = NULL;
        mutex_unlock(&fullstop_mutex);
-       return false;
 }
-EXPORT_SYMBOL_GPL(torture_cleanup);
+EXPORT_SYMBOL_GPL(torture_cleanup_end);
 
 /*
  * Is it time for the current torture test to stop?