rcutorture: Add grace period after CPU offline
authorPaul E. McKenney <paulmck@linux.ibm.com>
Mon, 10 Dec 2018 17:44:52 +0000 (09:44 -0800)
committerPaul E. McKenney <paulmck@linux.ibm.com>
Fri, 25 Jan 2019 23:37:10 +0000 (15:37 -0800)
Beyond a certain point in the CPU-hotplug offline process, timers get
stranded on the outgoing CPU, and won't fire until that CPU comes back
online, which might well be never.  This commit therefore adds a hook
in torture_onoff_init() that is invoked from torture_offline(), which
rcutorture uses to occasionally wait for a grace period.  This should
result in failures for RCU implementations that rely on stranded timers
eventually firing in the absence of the CPU coming back online.

Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
include/linux/torture.h
kernel/locking/locktorture.c
kernel/rcu/rcutorture.c
kernel/torture.c

index 48fad21..f2d3bcb 100644 (file)
        do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0)
 
 /* Definitions for online/offline exerciser. */
+typedef void torture_ofl_func(void);
 bool torture_offline(int cpu, long *n_onl_attempts, long *n_onl_successes,
                     unsigned long *sum_offl, int *min_onl, int *max_onl);
 bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes,
                    unsigned long *sum_onl, int *min_onl, int *max_onl);
-int torture_onoff_init(long ooholdoff, long oointerval);
+int torture_onoff_init(long ooholdoff, long oointerval, torture_ofl_func *f);
 void torture_onoff_stats(void);
 bool torture_onoff_failures(void);
 
index 7d0b0ed..c8b3480 100644 (file)
@@ -970,7 +970,7 @@ static int __init lock_torture_init(void)
        /* Prepare torture context. */
        if (onoff_interval > 0) {
                firsterr = torture_onoff_init(onoff_holdoff * HZ,
-                                             onoff_interval * HZ);
+                                             onoff_interval * HZ, NULL);
                if (firsterr)
                        goto unwind;
        }
index 0955f3a..9eb9235 100644 (file)
@@ -2243,6 +2243,14 @@ static void rcu_test_debug_objects(void)
 #endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 }
 
+static void rcutorture_sync(void)
+{
+       static unsigned long n;
+
+       if (cur_ops->sync && !(++n & 0xfff))
+               cur_ops->sync();
+}
+
 static int __init
 rcu_torture_init(void)
 {
@@ -2404,7 +2412,8 @@ rcu_torture_init(void)
        firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup);
        if (firsterr)
                goto unwind;
-       firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval);
+       firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval,
+                                     rcutorture_sync);
        if (firsterr)
                goto unwind;
        firsterr = rcu_torture_stall_init();
index bbf6d47..a03ff72 100644 (file)
@@ -75,6 +75,7 @@ static DEFINE_MUTEX(fullstop_mutex);
 static struct task_struct *onoff_task;
 static long onoff_holdoff;
 static long onoff_interval;
+static torture_ofl_func *onoff_f;
 static long n_offline_attempts;
 static long n_offline_successes;
 static unsigned long sum_offline;
@@ -118,6 +119,8 @@ bool torture_offline(int cpu, long *n_offl_attempts, long *n_offl_successes,
                        pr_alert("%s" TORTURE_FLAG
                                 "torture_onoff task: offlined %d\n",
                                 torture_type, cpu);
+               if (onoff_f)
+                       onoff_f();
                (*n_offl_successes)++;
                delta = jiffies - starttime;
                *sum_offl += delta;
@@ -243,11 +246,12 @@ stop:
 /*
  * Initiate online-offline handling.
  */
-int torture_onoff_init(long ooholdoff, long oointerval)
+int torture_onoff_init(long ooholdoff, long oointerval, torture_ofl_func *f)
 {
 #ifdef CONFIG_HOTPLUG_CPU
        onoff_holdoff = ooholdoff;
        onoff_interval = oointerval;
+       onoff_f = f;
        if (onoff_interval <= 0)
                return 0;
        return torture_create_kthread(torture_onoff, NULL, onoff_task);