hc
2023-12-11 1f93a7dfd1f8d5ff7a5c53246c7534fe2332d6f4
kernel/kernel/torture.c
....@@ -1,23 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * Common functions for in-kernel torture tests.
34 *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License as published by
6
- * the Free Software Foundation; either version 2 of the License, or
7
- * (at your option) any later version.
8
- *
9
- * This program is distributed in the hope that it will be useful,
10
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- * GNU General Public License for more details.
13
- *
14
- * You should have received a copy of the GNU General Public License
15
- * along with this program; if not, you can access it online at
16
- * http://www.gnu.org/licenses/gpl-2.0.html.
17
- *
185 * Copyright (C) IBM Corporation, 2014
196 *
20
- * Author: Paul E. McKenney <paulmck@us.ibm.com>
7
+ * Author: Paul E. McKenney <paulmck@linux.ibm.com>
218 * Based on kernel/rcu/torture.c.
229 */
2310
....@@ -53,7 +40,13 @@
5340 #include "rcu/rcu.h"
5441
5542 MODULE_LICENSE("GPL");
56
-MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
43
+MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");
44
+
45
+static bool disable_onoff_at_boot;
46
+module_param(disable_onoff_at_boot, bool, 0444);
47
+
48
+static bool ftrace_dump_at_shutdown;
49
+module_param(ftrace_dump_at_shutdown, bool, 0444);
5750
5851 static char *torture_type;
5952 static int verbose;
....@@ -75,6 +68,7 @@
7568 static struct task_struct *onoff_task;
7669 static long onoff_holdoff;
7770 static long onoff_interval;
71
+static torture_ofl_func *onoff_f;
7872 static long n_offline_attempts;
7973 static long n_offline_successes;
8074 static unsigned long sum_offline;
....@@ -96,10 +90,13 @@
9690 {
9791 unsigned long delta;
9892 int ret;
93
+ char *s;
9994 unsigned long starttime;
10095
10196 if (!cpu_online(cpu) || !cpu_is_hotpluggable(cpu))
10297 return false;
98
+ if (num_online_cpus() <= 1)
99
+ return false; /* Can't offline the last CPU. */
103100
104101 if (verbose > 1)
105102 pr_alert("%s" TORTURE_FLAG
....@@ -107,17 +104,25 @@
107104 torture_type, cpu);
108105 starttime = jiffies;
109106 (*n_offl_attempts)++;
110
- ret = cpu_down(cpu);
107
+ ret = remove_cpu(cpu);
111108 if (ret) {
109
+ s = "";
110
+ if (!rcu_inkernel_boot_has_ended() && ret == -EBUSY) {
111
+ // PCI probe frequently disables hotplug during boot.
112
+ (*n_offl_attempts)--;
113
+ s = " (-EBUSY forgiven during boot)";
114
+ }
112115 if (verbose)
113116 pr_alert("%s" TORTURE_FLAG
114
- "torture_onoff task: offline %d failed: errno %d\n",
115
- torture_type, cpu, ret);
117
+ "torture_onoff task: offline %d failed%s: errno %d\n",
118
+ torture_type, cpu, s, ret);
116119 } else {
117120 if (verbose > 1)
118121 pr_alert("%s" TORTURE_FLAG
119122 "torture_onoff task: offlined %d\n",
120123 torture_type, cpu);
124
+ if (onoff_f)
125
+ onoff_f();
121126 (*n_offl_successes)++;
122127 delta = jiffies - starttime;
123128 *sum_offl += delta;
....@@ -145,6 +150,7 @@
145150 {
146151 unsigned long delta;
147152 int ret;
153
+ char *s;
148154 unsigned long starttime;
149155
150156 if (cpu_online(cpu) || !cpu_is_hotpluggable(cpu))
....@@ -156,12 +162,18 @@
156162 torture_type, cpu);
157163 starttime = jiffies;
158164 (*n_onl_attempts)++;
159
- ret = cpu_up(cpu);
165
+ ret = add_cpu(cpu);
160166 if (ret) {
167
+ s = "";
168
+ if (!rcu_inkernel_boot_has_ended() && ret == -EBUSY) {
169
+ // PCI probe frequently disables hotplug during boot.
170
+ (*n_onl_attempts)--;
171
+ s = " (-EBUSY forgiven during boot)";
172
+ }
161173 if (verbose)
162174 pr_alert("%s" TORTURE_FLAG
163
- "torture_onoff task: online %d failed: errno %d\n",
164
- torture_type, cpu, ret);
175
+ "torture_onoff task: online %d failed%s: errno %d\n",
176
+ torture_type, cpu, s, ret);
165177 } else {
166178 if (verbose > 1)
167179 pr_alert("%s" TORTURE_FLAG
....@@ -194,11 +206,24 @@
194206 int cpu;
195207 int maxcpu = -1;
196208 DEFINE_TORTURE_RANDOM(rand);
209
+ int ret;
197210
198211 VERBOSE_TOROUT_STRING("torture_onoff task started");
199212 for_each_online_cpu(cpu)
200213 maxcpu = cpu;
201214 WARN_ON(maxcpu < 0);
215
+ if (!IS_MODULE(CONFIG_TORTURE_TEST)) {
216
+ for_each_possible_cpu(cpu) {
217
+ if (cpu_online(cpu))
218
+ continue;
219
+ ret = add_cpu(cpu);
220
+ if (ret && verbose) {
221
+ pr_alert("%s" TORTURE_FLAG
222
+ "%s: Initial online %d: errno %d\n",
223
+ __func__, torture_type, cpu, ret);
224
+ }
225
+ }
226
+ }
202227
203228 if (maxcpu == 0) {
204229 VERBOSE_TOROUT_STRING("Only one CPU, so CPU-hotplug testing is disabled");
....@@ -211,6 +236,10 @@
211236 VERBOSE_TOROUT_STRING("torture_onoff end holdoff");
212237 }
213238 while (!torture_must_stop()) {
239
+ if (disable_onoff_at_boot && !rcu_inkernel_boot_has_ended()) {
240
+ schedule_timeout_interruptible(HZ / 10);
241
+ continue;
242
+ }
214243 cpu = (torture_random(&rand) >> 4) % (maxcpu + 1);
215244 if (!torture_offline(cpu,
216245 &n_offline_attempts, &n_offline_successes,
....@@ -231,18 +260,18 @@
231260 /*
232261 * Initiate online-offline handling.
233262 */
234
-int torture_onoff_init(long ooholdoff, long oointerval)
263
+int torture_onoff_init(long ooholdoff, long oointerval, torture_ofl_func *f)
235264 {
236
- int ret = 0;
237
-
238265 #ifdef CONFIG_HOTPLUG_CPU
239266 onoff_holdoff = ooholdoff;
240267 onoff_interval = oointerval;
268
+ onoff_f = f;
241269 if (onoff_interval <= 0)
242270 return 0;
243
- ret = torture_create_kthread(torture_onoff, NULL, onoff_task);
244
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
245
- return ret;
271
+ return torture_create_kthread(torture_onoff, NULL, onoff_task);
272
+#else /* #ifdef CONFIG_HOTPLUG_CPU */
273
+ return 0;
274
+#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
246275 }
247276 EXPORT_SYMBOL_GPL(torture_onoff_init);
248277
....@@ -259,7 +288,6 @@
259288 onoff_task = NULL;
260289 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
261290 }
262
-EXPORT_SYMBOL_GPL(torture_onoff_cleanup);
263291
264292 /*
265293 * Print online/offline testing statistics.
....@@ -445,7 +473,6 @@
445473 }
446474 shuffler_task = NULL;
447475 }
448
-EXPORT_SYMBOL_GPL(torture_shuffle_cleanup);
449476
450477 /*
451478 * Variables for auto-shutdown. This allows "lights out" torture runs
....@@ -503,7 +530,8 @@
503530 torture_shutdown_hook();
504531 else
505532 VERBOSE_TOROUT_STRING("No torture_shutdown_hook(), skipping.");
506
- rcu_ftrace_dump(DUMP_ALL);
533
+ if (ftrace_dump_at_shutdown)
534
+ rcu_ftrace_dump(DUMP_ALL);
507535 kernel_power_off(); /* Shut down the system. */
508536 return 0;
509537 }
....@@ -513,15 +541,13 @@
513541 */
514542 int torture_shutdown_init(int ssecs, void (*cleanup)(void))
515543 {
516
- int ret = 0;
517
-
518544 torture_shutdown_hook = cleanup;
519545 if (ssecs > 0) {
520546 shutdown_time = ktime_add(ktime_get(), ktime_set(ssecs, 0));
521
- ret = torture_create_kthread(torture_shutdown, NULL,
547
+ return torture_create_kthread(torture_shutdown, NULL,
522548 shutdown_task);
523549 }
524
- return ret;
550
+ return 0;
525551 }
526552 EXPORT_SYMBOL_GPL(torture_shutdown_init);
527553
....@@ -568,18 +594,21 @@
568594 static struct task_struct *stutter_task;
569595 static int stutter_pause_test;
570596 static int stutter;
597
+static int stutter_gap;
571598
572599 /*
573600 * Block until the stutter interval ends. This must be called periodically
574601 * by all running kthreads that need to be subject to stuttering.
575602 */
576
-void stutter_wait(const char *title)
603
+bool stutter_wait(const char *title)
577604 {
578605 int spt;
606
+ bool ret = false;
579607
580608 cond_resched_tasks_rcu_qs();
581609 spt = READ_ONCE(stutter_pause_test);
582610 for (; spt; spt = READ_ONCE(stutter_pause_test)) {
611
+ ret = true;
583612 if (spt == 1) {
584613 schedule_timeout_interruptible(1);
585614 } else if (spt == 2) {
....@@ -590,6 +619,7 @@
590619 }
591620 torture_shutdown_absorb(title);
592621 }
622
+ return ret;
593623 }
594624 EXPORT_SYMBOL_GPL(stutter_wait);
595625
....@@ -599,17 +629,24 @@
599629 */
600630 static int torture_stutter(void *arg)
601631 {
632
+ int wtime;
633
+
602634 VERBOSE_TOROUT_STRING("torture_stutter task started");
603635 do {
604636 if (!torture_must_stop() && stutter > 1) {
605
- WRITE_ONCE(stutter_pause_test, 1);
606
- schedule_timeout_interruptible(stutter - 1);
637
+ wtime = stutter;
638
+ if (stutter > HZ + 1) {
639
+ WRITE_ONCE(stutter_pause_test, 1);
640
+ wtime = stutter - HZ - 1;
641
+ schedule_timeout_interruptible(wtime);
642
+ wtime = HZ + 1;
643
+ }
607644 WRITE_ONCE(stutter_pause_test, 2);
608
- schedule_timeout_interruptible(1);
645
+ schedule_timeout_interruptible(wtime);
609646 }
610647 WRITE_ONCE(stutter_pause_test, 0);
611648 if (!torture_must_stop())
612
- schedule_timeout_interruptible(stutter);
649
+ schedule_timeout_interruptible(stutter_gap);
613650 torture_shutdown_absorb("torture_stutter");
614651 } while (!torture_must_stop());
615652 torture_kthread_stopping("torture_stutter");
....@@ -619,13 +656,11 @@
619656 /*
620657 * Initialize and kick off the torture_stutter kthread.
621658 */
622
-int torture_stutter_init(int s)
659
+int torture_stutter_init(const int s, const int sgap)
623660 {
624
- int ret;
625
-
626661 stutter = s;
627
- ret = torture_create_kthread(torture_stutter, NULL, stutter_task);
628
- return ret;
662
+ stutter_gap = sgap;
663
+ return torture_create_kthread(torture_stutter, NULL, stutter_task);
629664 }
630665 EXPORT_SYMBOL_GPL(torture_stutter_init);
631666