diff options
author | Paul E. McKenney <paulmck@linux.ibm.com> | 2018-12-10 12:44:52 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.ibm.com> | 2019-01-25 18:37:10 -0500 |
commit | 3a6cb58f159e64241b2af9374acad41a70939349 (patch) | |
tree | ada940f453392a61ee945b23974647841ee65700 | |
parent | 0d8a9ea9764a0e34e17e3b80a2be3855de239d6e (diff) |
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>
-rw-r--r-- | include/linux/torture.h | 3 | ||||
-rw-r--r-- | kernel/locking/locktorture.c | 2 | ||||
-rw-r--r-- | kernel/rcu/rcutorture.c | 11 | ||||
-rw-r--r-- | kernel/torture.c | 6 |
4 files changed, 18 insertions, 4 deletions
diff --git a/include/linux/torture.h b/include/linux/torture.h index 48fad21109fc..f2d3bcbf4337 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h | |||
@@ -50,11 +50,12 @@ | |||
50 | do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0) | 50 | do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0) |
51 | 51 | ||
52 | /* Definitions for online/offline exerciser. */ | 52 | /* Definitions for online/offline exerciser. */ |
53 | typedef void torture_ofl_func(void); | ||
53 | bool torture_offline(int cpu, long *n_onl_attempts, long *n_onl_successes, | 54 | bool torture_offline(int cpu, long *n_onl_attempts, long *n_onl_successes, |
54 | unsigned long *sum_offl, int *min_onl, int *max_onl); | 55 | unsigned long *sum_offl, int *min_onl, int *max_onl); |
55 | bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes, | 56 | bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes, |
56 | unsigned long *sum_onl, int *min_onl, int *max_onl); | 57 | unsigned long *sum_onl, int *min_onl, int *max_onl); |
57 | int torture_onoff_init(long ooholdoff, long oointerval); | 58 | int torture_onoff_init(long ooholdoff, long oointerval, torture_ofl_func *f); |
58 | void torture_onoff_stats(void); | 59 | void torture_onoff_stats(void); |
59 | bool torture_onoff_failures(void); | 60 | bool torture_onoff_failures(void); |
60 | 61 | ||
diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index 7d0b0ed74404..c8b348097bb5 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c | |||
@@ -970,7 +970,7 @@ static int __init lock_torture_init(void) | |||
970 | /* Prepare torture context. */ | 970 | /* Prepare torture context. */ |
971 | if (onoff_interval > 0) { | 971 | if (onoff_interval > 0) { |
972 | firsterr = torture_onoff_init(onoff_holdoff * HZ, | 972 | firsterr = torture_onoff_init(onoff_holdoff * HZ, |
973 | onoff_interval * HZ); | 973 | onoff_interval * HZ, NULL); |
974 | if (firsterr) | 974 | if (firsterr) |
975 | goto unwind; | 975 | goto unwind; |
976 | } | 976 | } |
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 0955f3a20952..9eb9235c1ec9 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c | |||
@@ -2243,6 +2243,14 @@ static void rcu_test_debug_objects(void) | |||
2243 | #endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ | 2243 | #endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ |
2244 | } | 2244 | } |
2245 | 2245 | ||
2246 | static void rcutorture_sync(void) | ||
2247 | { | ||
2248 | static unsigned long n; | ||
2249 | |||
2250 | if (cur_ops->sync && !(++n & 0xfff)) | ||
2251 | cur_ops->sync(); | ||
2252 | } | ||
2253 | |||
2246 | static int __init | 2254 | static int __init |
2247 | rcu_torture_init(void) | 2255 | rcu_torture_init(void) |
2248 | { | 2256 | { |
@@ -2404,7 +2412,8 @@ rcu_torture_init(void) | |||
2404 | firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup); | 2412 | firsterr = torture_shutdown_init(shutdown_secs, rcu_torture_cleanup); |
2405 | if (firsterr) | 2413 | if (firsterr) |
2406 | goto unwind; | 2414 | goto unwind; |
2407 | firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval); | 2415 | firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval, |
2416 | rcutorture_sync); | ||
2408 | if (firsterr) | 2417 | if (firsterr) |
2409 | goto unwind; | 2418 | goto unwind; |
2410 | firsterr = rcu_torture_stall_init(); | 2419 | firsterr = rcu_torture_stall_init(); |
diff --git a/kernel/torture.c b/kernel/torture.c index bbf6d473e50c..a03ff722352b 100644 --- a/kernel/torture.c +++ b/kernel/torture.c | |||
@@ -75,6 +75,7 @@ static DEFINE_MUTEX(fullstop_mutex); | |||
75 | static struct task_struct *onoff_task; | 75 | static struct task_struct *onoff_task; |
76 | static long onoff_holdoff; | 76 | static long onoff_holdoff; |
77 | static long onoff_interval; | 77 | static long onoff_interval; |
78 | static torture_ofl_func *onoff_f; | ||
78 | static long n_offline_attempts; | 79 | static long n_offline_attempts; |
79 | static long n_offline_successes; | 80 | static long n_offline_successes; |
80 | static unsigned long sum_offline; | 81 | static unsigned long sum_offline; |
@@ -118,6 +119,8 @@ bool torture_offline(int cpu, long *n_offl_attempts, long *n_offl_successes, | |||
118 | pr_alert("%s" TORTURE_FLAG | 119 | pr_alert("%s" TORTURE_FLAG |
119 | "torture_onoff task: offlined %d\n", | 120 | "torture_onoff task: offlined %d\n", |
120 | torture_type, cpu); | 121 | torture_type, cpu); |
122 | if (onoff_f) | ||
123 | onoff_f(); | ||
121 | (*n_offl_successes)++; | 124 | (*n_offl_successes)++; |
122 | delta = jiffies - starttime; | 125 | delta = jiffies - starttime; |
123 | *sum_offl += delta; | 126 | *sum_offl += delta; |
@@ -243,11 +246,12 @@ stop: | |||
243 | /* | 246 | /* |
244 | * Initiate online-offline handling. | 247 | * Initiate online-offline handling. |
245 | */ | 248 | */ |
246 | int torture_onoff_init(long ooholdoff, long oointerval) | 249 | int torture_onoff_init(long ooholdoff, long oointerval, torture_ofl_func *f) |
247 | { | 250 | { |
248 | #ifdef CONFIG_HOTPLUG_CPU | 251 | #ifdef CONFIG_HOTPLUG_CPU |
249 | onoff_holdoff = ooholdoff; | 252 | onoff_holdoff = ooholdoff; |
250 | onoff_interval = oointerval; | 253 | onoff_interval = oointerval; |
254 | onoff_f = f; | ||
251 | if (onoff_interval <= 0) | 255 | if (onoff_interval <= 0) |
252 | return 0; | 256 | return 0; |
253 | return torture_create_kthread(torture_onoff, NULL, onoff_task); | 257 | return torture_create_kthread(torture_onoff, NULL, onoff_task); |