rcutorture: Add grace period after CPU offline

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>
This commit is contained in:
Paul E. McKenney 2018-12-10 09:44:52 -08:00
parent 0d8a9ea976
commit 3a6cb58f15
4 changed files with 18 additions and 4 deletions

View File

@ -50,11 +50,12 @@
do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0) do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0)
/* Definitions for online/offline exerciser. */ /* Definitions for online/offline exerciser. */
typedef void torture_ofl_func(void);
bool torture_offline(int cpu, long *n_onl_attempts, long *n_onl_successes, bool torture_offline(int cpu, long *n_onl_attempts, long *n_onl_successes,
unsigned long *sum_offl, int *min_onl, int *max_onl); unsigned long *sum_offl, int *min_onl, int *max_onl);
bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes, bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes,
unsigned long *sum_onl, int *min_onl, int *max_onl); 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); void torture_onoff_stats(void);
bool torture_onoff_failures(void); bool torture_onoff_failures(void);

View File

@ -970,7 +970,7 @@ static int __init lock_torture_init(void)
/* Prepare torture context. */ /* Prepare torture context. */
if (onoff_interval > 0) { if (onoff_interval > 0) {
firsterr = torture_onoff_init(onoff_holdoff * HZ, firsterr = torture_onoff_init(onoff_holdoff * HZ,
onoff_interval * HZ); onoff_interval * HZ, NULL);
if (firsterr) if (firsterr)
goto unwind; goto unwind;
} }

View File

@ -2243,6 +2243,14 @@ static void rcu_test_debug_objects(void)
#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ #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 static int __init
rcu_torture_init(void) rcu_torture_init(void)
{ {
@ -2404,7 +2412,8 @@ rcu_torture_init(void)
firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup); firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup);
if (firsterr) if (firsterr)
goto unwind; goto unwind;
firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval); firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval,
rcutorture_sync);
if (firsterr) if (firsterr)
goto unwind; goto unwind;
firsterr = rcu_torture_stall_init(); firsterr = rcu_torture_stall_init();

View File

@ -75,6 +75,7 @@ static DEFINE_MUTEX(fullstop_mutex);
static struct task_struct *onoff_task; static struct task_struct *onoff_task;
static long onoff_holdoff; static long onoff_holdoff;
static long onoff_interval; static long onoff_interval;
static torture_ofl_func *onoff_f;
static long n_offline_attempts; static long n_offline_attempts;
static long n_offline_successes; static long n_offline_successes;
static unsigned long sum_offline; 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 pr_alert("%s" TORTURE_FLAG
"torture_onoff task: offlined %d\n", "torture_onoff task: offlined %d\n",
torture_type, cpu); torture_type, cpu);
if (onoff_f)
onoff_f();
(*n_offl_successes)++; (*n_offl_successes)++;
delta = jiffies - starttime; delta = jiffies - starttime;
*sum_offl += delta; *sum_offl += delta;
@ -243,11 +246,12 @@ stop:
/* /*
* Initiate online-offline handling. * 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 #ifdef CONFIG_HOTPLUG_CPU
onoff_holdoff = ooholdoff; onoff_holdoff = ooholdoff;
onoff_interval = oointerval; onoff_interval = oointerval;
onoff_f = f;
if (onoff_interval <= 0) if (onoff_interval <= 0)
return 0; return 0;
return torture_create_kthread(torture_onoff, NULL, onoff_task); return torture_create_kthread(torture_onoff, NULL, onoff_task);