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:
parent
0d8a9ea976
commit
3a6cb58f15
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user