Blame view

kernel/scftorture.c 16.9 KB
e9d338a0b   Paul E. McKenney   scftorture: Add s...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  // SPDX-License-Identifier: GPL-2.0+
  //
  // Torture test for smp_call_function() and friends.
  //
  // Copyright (C) Facebook, 2020.
  //
  // Author: Paul E. McKenney <paulmck@kernel.org>
  
  #define pr_fmt(fmt) fmt
  
  #include <linux/atomic.h>
  #include <linux/bitops.h>
  #include <linux/completion.h>
  #include <linux/cpu.h>
  #include <linux/delay.h>
  #include <linux/err.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/kthread.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/notifier.h>
  #include <linux/percpu.h>
  #include <linux/rcupdate.h>
  #include <linux/rcupdate_trace.h>
  #include <linux/reboot.h>
  #include <linux/sched.h>
  #include <linux/spinlock.h>
  #include <linux/smp.h>
  #include <linux/stat.h>
  #include <linux/srcu.h>
  #include <linux/slab.h>
  #include <linux/torture.h>
  #include <linux/types.h>
  
  #define SCFTORT_STRING "scftorture"
  #define SCFTORT_FLAG SCFTORT_STRING ": "
  
  #define SCFTORTOUT(s, x...) \
  	pr_alert(SCFTORT_FLAG s, ## x)
  
  #define VERBOSE_SCFTORTOUT(s, x...) \
  	do { if (verbose) pr_alert(SCFTORT_FLAG s, ## x); } while (0)
  
  #define VERBOSE_SCFTORTOUT_ERRSTRING(s, x...) \
  	do { if (verbose) pr_alert(SCFTORT_FLAG "!!! " s, ## x); } while (0)
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Paul E. McKenney <paulmck@kernel.org>");
  
  // Wait until there are multiple CPUs before starting test.
  torture_param(int, holdoff, IS_BUILTIN(CONFIG_SCF_TORTURE_TEST) ? 10 : 0,
  	      "Holdoff time before test start (s)");
  torture_param(int, longwait, 0, "Include ridiculously long waits? (seconds)");
  torture_param(int, nthreads, -1, "# threads, defaults to -1 for all CPUs.");
  torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
  torture_param(int, onoff_interval, 0, "Time between CPU hotplugs (s), 0=disable");
  torture_param(int, shutdown_secs, 0, "Shutdown time (ms), <= zero to disable.");
  torture_param(int, stat_interval, 60, "Number of seconds between stats printk()s.");
  torture_param(int, stutter_cpus, 5, "Number of jiffies to change CPUs under test, 0=disable");
  torture_param(bool, use_cpus_read_lock, 0, "Use cpus_read_lock() to exclude CPU hotplug.");
  torture_param(int, verbose, 0, "Enable verbose debugging printk()s");
  torture_param(int, weight_single, -1, "Testing weight for single-CPU no-wait operations.");
  torture_param(int, weight_single_wait, -1, "Testing weight for single-CPU operations.");
5022b8ac6   Paul E. McKenney   scftorture: Imple...
67
68
  torture_param(int, weight_many, -1, "Testing weight for multi-CPU no-wait operations.");
  torture_param(int, weight_many_wait, -1, "Testing weight for multi-CPU operations.");
e9d338a0b   Paul E. McKenney   scftorture: Add s...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  torture_param(int, weight_all, -1, "Testing weight for all-CPU no-wait operations.");
  torture_param(int, weight_all_wait, -1, "Testing weight for all-CPU operations.");
  
  char *torture_type = "";
  
  #ifdef MODULE
  # define SCFTORT_SHUTDOWN 0
  #else
  # define SCFTORT_SHUTDOWN 1
  #endif
  
  torture_param(bool, shutdown, SCFTORT_SHUTDOWN, "Shutdown at end of torture test.");
  
  struct scf_statistics {
  	struct task_struct *task;
  	int cpu;
  	long long n_single;
5022b8ac6   Paul E. McKenney   scftorture: Imple...
86
  	long long n_single_ofl;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
87
  	long long n_single_wait;
5022b8ac6   Paul E. McKenney   scftorture: Imple...
88
89
90
  	long long n_single_wait_ofl;
  	long long n_many;
  	long long n_many_wait;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
91
92
93
94
95
96
97
  	long long n_all;
  	long long n_all_wait;
  };
  
  static struct scf_statistics *scf_stats_p;
  static struct task_struct *scf_torture_stats_task;
  static DEFINE_PER_CPU(long long, scf_invoked_count);
5022b8ac6   Paul E. McKenney   scftorture: Imple...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  // Data for random primitive selection
  #define SCF_PRIM_SINGLE		0
  #define SCF_PRIM_MANY		1
  #define SCF_PRIM_ALL		2
  #define SCF_NPRIMS		(2 * 3) // Need wait and no-wait versions of each.
  
  static char *scf_prim_name[] = {
  	"smp_call_function_single",
  	"smp_call_function_many",
  	"smp_call_function",
  };
  
  struct scf_selector {
  	unsigned long scfs_weight;
  	int scfs_prim;
  	bool scfs_wait;
  };
  static struct scf_selector scf_sel_array[SCF_NPRIMS];
  static int scf_sel_array_len;
  static unsigned long scf_sel_totweight;
b93e21a51   Paul E. McKenney   scftorture: Add s...
118
119
120
121
122
123
124
  // Communicate between caller and handler.
  struct scf_check {
  	bool scfc_in;
  	bool scfc_out;
  	int scfc_cpu; // -1 for not _single().
  	bool scfc_wait;
  };
e9d338a0b   Paul E. McKenney   scftorture: Add s...
125
126
127
  // Use to wait for all threads to start.
  static atomic_t n_started;
  static atomic_t n_errs;
b93e21a51   Paul E. McKenney   scftorture: Add s...
128
129
130
  static atomic_t n_mb_in_errs;
  static atomic_t n_mb_out_errs;
  static atomic_t n_alloc_errs;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
131
  static bool scfdone;
dbf83b655   Paul E. McKenney   scftorture: Flag ...
132
  static char *bangstr = "";
e9d338a0b   Paul E. McKenney   scftorture: Add s...
133

9a52a5746   Wei Yongjun   scftorture: Make ...
134
  static DEFINE_TORTURE_RANDOM_PERCPU(scf_torture_rand);
e9d338a0b   Paul E. McKenney   scftorture: Add s...
135
136
137
138
139
  
  // Print torture statistics.  Caller must ensure serialization.
  static void scf_torture_stats_print(void)
  {
  	int cpu;
dba3142b3   Paul E. McKenney   scftorture: Summa...
140
  	int i;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
141
142
  	long long invoked_count = 0;
  	bool isdone = READ_ONCE(scfdone);
dba3142b3   Paul E. McKenney   scftorture: Summa...
143
  	struct scf_statistics scfs = {};
e9d338a0b   Paul E. McKenney   scftorture: Add s...
144
145
146
  
  	for_each_possible_cpu(cpu)
  		invoked_count += data_race(per_cpu(scf_invoked_count, cpu));
dba3142b3   Paul E. McKenney   scftorture: Summa...
147
148
149
150
151
152
153
154
155
156
  	for (i = 0; i < nthreads; i++) {
  		scfs.n_single += scf_stats_p[i].n_single;
  		scfs.n_single_ofl += scf_stats_p[i].n_single_ofl;
  		scfs.n_single_wait += scf_stats_p[i].n_single_wait;
  		scfs.n_single_wait_ofl += scf_stats_p[i].n_single_wait_ofl;
  		scfs.n_many += scf_stats_p[i].n_many;
  		scfs.n_many_wait += scf_stats_p[i].n_many_wait;
  		scfs.n_all += scf_stats_p[i].n_all;
  		scfs.n_all_wait += scf_stats_p[i].n_all_wait;
  	}
dbf83b655   Paul E. McKenney   scftorture: Flag ...
157
158
159
160
161
  	if (atomic_read(&n_errs) || atomic_read(&n_mb_in_errs) ||
  	    atomic_read(&n_mb_out_errs) || atomic_read(&n_alloc_errs))
  		bangstr = "!!! ";
  	pr_alert("%s %sscf_invoked_count %s: %lld single: %lld/%lld single_ofl: %lld/%lld many: %lld/%lld all: %lld/%lld ",
  		 SCFTORT_FLAG, bangstr, isdone ? "VER" : "ver", invoked_count,
dba3142b3   Paul E. McKenney   scftorture: Summa...
162
163
  		 scfs.n_single, scfs.n_single_wait, scfs.n_single_ofl, scfs.n_single_wait_ofl,
  		 scfs.n_many, scfs.n_many_wait, scfs.n_all, scfs.n_all_wait);
e9d338a0b   Paul E. McKenney   scftorture: Add s...
164
  	torture_onoff_stats();
dbf83b655   Paul E. McKenney   scftorture: Flag ...
165
166
167
168
  	pr_cont("ste: %d stnmie: %d stnmoe: %d staf: %d
  ", atomic_read(&n_errs),
  		atomic_read(&n_mb_in_errs), atomic_read(&n_mb_out_errs),
  		atomic_read(&n_alloc_errs));
e9d338a0b   Paul E. McKenney   scftorture: Add s...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  }
  
  // Periodically prints torture statistics, if periodic statistics printing
  // was specified via the stat_interval module parameter.
  static int
  scf_torture_stats(void *arg)
  {
  	VERBOSE_TOROUT_STRING("scf_torture_stats task started");
  	do {
  		schedule_timeout_interruptible(stat_interval * HZ);
  		scf_torture_stats_print();
  		torture_shutdown_absorb("scf_torture_stats");
  	} while (!torture_must_stop());
  	torture_kthread_stopping("scf_torture_stats");
  	return 0;
  }
5022b8ac6   Paul E. McKenney   scftorture: Imple...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  // Add a primitive to the scf_sel_array[].
  static void scf_sel_add(unsigned long weight, int prim, bool wait)
  {
  	struct scf_selector *scfsp = &scf_sel_array[scf_sel_array_len];
  
  	// If no weight, if array would overflow, if computing three-place
  	// percentages would overflow, or if the scf_prim_name[] array would
  	// overflow, don't bother.  In the last three two cases, complain.
  	if (!weight ||
  	    WARN_ON_ONCE(scf_sel_array_len >= ARRAY_SIZE(scf_sel_array)) ||
  	    WARN_ON_ONCE(0 - 100000 * weight <= 100000 * scf_sel_totweight) ||
  	    WARN_ON_ONCE(prim >= ARRAY_SIZE(scf_prim_name)))
  		return;
  	scf_sel_totweight += weight;
  	scfsp->scfs_weight = scf_sel_totweight;
  	scfsp->scfs_prim = prim;
  	scfsp->scfs_wait = wait;
  	scf_sel_array_len++;
  }
  
  // Dump out weighting percentages for scf_prim_name[] array.
  static void scf_sel_dump(void)
  {
  	int i;
  	unsigned long oldw = 0;
  	struct scf_selector *scfsp;
  	unsigned long w;
  
  	for (i = 0; i < scf_sel_array_len; i++) {
  		scfsp = &scf_sel_array[i];
  		w = (scfsp->scfs_weight - oldw) * 100000 / scf_sel_totweight;
  		pr_info("%s: %3lu.%03lu %s(%s)
  ", __func__, w / 1000, w % 1000,
  			scf_prim_name[scfsp->scfs_prim],
  			scfsp->scfs_wait ? "wait" : "nowait");
  		oldw = scfsp->scfs_weight;
  	}
  }
  
  // Randomly pick a primitive and wait/nowait, based on weightings.
  static struct scf_selector *scf_sel_rand(struct torture_random_state *trsp)
  {
  	int i;
  	unsigned long w = torture_random(trsp) % (scf_sel_totweight + 1);
  
  	for (i = 0; i < scf_sel_array_len; i++)
  		if (scf_sel_array[i].scfs_weight >= w)
  			return &scf_sel_array[i];
  	WARN_ON_ONCE(1);
  	return &scf_sel_array[0];
  }
e9d338a0b   Paul E. McKenney   scftorture: Add s...
236
237
238
  // Update statistics and occasionally burn up mass quantities of CPU time,
  // if told to do so via scftorture.longwait.  Otherwise, occasionally burn
  // a little bit.
b93e21a51   Paul E. McKenney   scftorture: Add s...
239
  static void scf_handler(void *scfc_in)
e9d338a0b   Paul E. McKenney   scftorture: Add s...
240
241
242
243
  {
  	int i;
  	int j;
  	unsigned long r = torture_random(this_cpu_ptr(&scf_torture_rand));
b93e21a51   Paul E. McKenney   scftorture: Add s...
244
  	struct scf_check *scfcp = scfc_in;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
245

980205ee8   Paul E. McKenney   scftorture: Add s...
246
247
248
249
250
  	if (likely(scfcp)) {
  		WRITE_ONCE(scfcp->scfc_out, false); // For multiple receivers.
  		if (WARN_ON_ONCE(unlikely(!READ_ONCE(scfcp->scfc_in))))
  			atomic_inc(&n_mb_in_errs);
  	}
e9d338a0b   Paul E. McKenney   scftorture: Add s...
251
252
253
254
  	this_cpu_inc(scf_invoked_count);
  	if (longwait <= 0) {
  		if (!(r & 0xffc0))
  			udelay(r & 0x3f);
b93e21a51   Paul E. McKenney   scftorture: Add s...
255
  		goto out;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
256
257
  	}
  	if (r & 0xfff)
b93e21a51   Paul E. McKenney   scftorture: Add s...
258
  		goto out;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
259
260
261
  	r = (r >> 12);
  	if (longwait <= 0) {
  		udelay((r & 0xff) + 1);
b93e21a51   Paul E. McKenney   scftorture: Add s...
262
  		goto out;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
263
264
265
266
267
268
269
270
  	}
  	r = r % longwait + 1;
  	for (i = 0; i < r; i++) {
  		for (j = 0; j < 1000; j++) {
  			udelay(1000);
  			cpu_relax();
  		}
  	}
b93e21a51   Paul E. McKenney   scftorture: Add s...
271
272
273
274
275
276
277
  out:
  	if (unlikely(!scfcp))
  		return;
  	if (scfcp->scfc_wait)
  		WRITE_ONCE(scfcp->scfc_out, true);
  	else
  		kfree(scfcp);
e9d338a0b   Paul E. McKenney   scftorture: Add s...
278
  }
5022b8ac6   Paul E. McKenney   scftorture: Imple...
279
  // As above, but check for correct CPU.
b93e21a51   Paul E. McKenney   scftorture: Add s...
280
  static void scf_handler_1(void *scfc_in)
5022b8ac6   Paul E. McKenney   scftorture: Imple...
281
  {
b93e21a51   Paul E. McKenney   scftorture: Add s...
282
283
284
285
  	struct scf_check *scfcp = scfc_in;
  
  	if (likely(scfcp) && WARN_ONCE(smp_processor_id() != scfcp->scfc_cpu, "%s: Wanted CPU %d got CPU %d
  ", __func__, scfcp->scfc_cpu, smp_processor_id())) {
5022b8ac6   Paul E. McKenney   scftorture: Imple...
286
  		atomic_inc(&n_errs);
b93e21a51   Paul E. McKenney   scftorture: Add s...
287
288
  	}
  	scf_handler(scfcp);
5022b8ac6   Paul E. McKenney   scftorture: Imple...
289
  }
e9d338a0b   Paul E. McKenney   scftorture: Add s...
290
  // Randomly do an smp_call_function*() invocation.
5022b8ac6   Paul E. McKenney   scftorture: Imple...
291
  static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_random_state *trsp)
e9d338a0b   Paul E. McKenney   scftorture: Add s...
292
  {
5022b8ac6   Paul E. McKenney   scftorture: Imple...
293
  	uintptr_t cpu;
676e54696   Paul E. McKenney   scftorture: Conso...
294
  	int ret = 0;
b93e21a51   Paul E. McKenney   scftorture: Add s...
295
  	struct scf_check *scfcp = NULL;
5022b8ac6   Paul E. McKenney   scftorture: Imple...
296
  	struct scf_selector *scfsp = scf_sel_rand(trsp);
e9d338a0b   Paul E. McKenney   scftorture: Add s...
297
298
299
300
  	if (use_cpus_read_lock)
  		cpus_read_lock();
  	else
  		preempt_disable();
34e8c4837   Paul E. McKenney   scftorture: Add s...
301
  	if (scfsp->scfs_prim == SCF_PRIM_SINGLE || scfsp->scfs_wait) {
b93e21a51   Paul E. McKenney   scftorture: Add s...
302
  		scfcp = kmalloc(sizeof(*scfcp), GFP_ATOMIC);
4df55bddc   Paul E. McKenney   scftorture: Conso...
303
  		if (WARN_ON_ONCE(!scfcp)) {
b93e21a51   Paul E. McKenney   scftorture: Add s...
304
  			atomic_inc(&n_alloc_errs);
4df55bddc   Paul E. McKenney   scftorture: Conso...
305
306
307
308
309
  		} else {
  			scfcp->scfc_cpu = -1;
  			scfcp->scfc_wait = scfsp->scfs_wait;
  			scfcp->scfc_out = false;
  		}
34e8c4837   Paul E. McKenney   scftorture: Add s...
310
311
312
  	}
  	switch (scfsp->scfs_prim) {
  	case SCF_PRIM_SINGLE:
5022b8ac6   Paul E. McKenney   scftorture: Imple...
313
314
315
316
317
  		cpu = torture_random(trsp) % nr_cpu_ids;
  		if (scfsp->scfs_wait)
  			scfp->n_single_wait++;
  		else
  			scfp->n_single++;
b93e21a51   Paul E. McKenney   scftorture: Add s...
318
319
  		if (scfcp) {
  			scfcp->scfc_cpu = cpu;
ee7035d29   Paul E. McKenney   scftorture: Preve...
320
  			barrier(); // Prevent race-reduction compiler optimizations.
b93e21a51   Paul E. McKenney   scftorture: Add s...
321
322
323
  			scfcp->scfc_in = true;
  		}
  		ret = smp_call_function_single(cpu, scf_handler_1, (void *)scfcp, scfsp->scfs_wait);
5022b8ac6   Paul E. McKenney   scftorture: Imple...
324
325
326
327
328
  		if (ret) {
  			if (scfsp->scfs_wait)
  				scfp->n_single_wait_ofl++;
  			else
  				scfp->n_single_ofl++;
b93e21a51   Paul E. McKenney   scftorture: Add s...
329
  			kfree(scfcp);
676e54696   Paul E. McKenney   scftorture: Conso...
330
  			scfcp = NULL;
5022b8ac6   Paul E. McKenney   scftorture: Imple...
331
332
333
334
335
336
337
  		}
  		break;
  	case SCF_PRIM_MANY:
  		if (scfsp->scfs_wait)
  			scfp->n_many_wait++;
  		else
  			scfp->n_many++;
ee7035d29   Paul E. McKenney   scftorture: Preve...
338
339
  		if (scfcp) {
  			barrier(); // Prevent race-reduction compiler optimizations.
980205ee8   Paul E. McKenney   scftorture: Add s...
340
  			scfcp->scfc_in = true;
ee7035d29   Paul E. McKenney   scftorture: Preve...
341
  		}
980205ee8   Paul E. McKenney   scftorture: Add s...
342
  		smp_call_function_many(cpu_online_mask, scf_handler, scfcp, scfsp->scfs_wait);
5022b8ac6   Paul E. McKenney   scftorture: Imple...
343
344
345
346
347
348
  		break;
  	case SCF_PRIM_ALL:
  		if (scfsp->scfs_wait)
  			scfp->n_all_wait++;
  		else
  			scfp->n_all++;
ee7035d29   Paul E. McKenney   scftorture: Preve...
349
350
  		if (scfcp) {
  			barrier(); // Prevent race-reduction compiler optimizations.
34e8c4837   Paul E. McKenney   scftorture: Add s...
351
  			scfcp->scfc_in = true;
ee7035d29   Paul E. McKenney   scftorture: Preve...
352
  		}
34e8c4837   Paul E. McKenney   scftorture: Add s...
353
  		smp_call_function(scf_handler, scfcp, scfsp->scfs_wait);
5022b8ac6   Paul E. McKenney   scftorture: Imple...
354
  		break;
de77d4da5   Paul E. McKenney   scftorture: Check...
355
356
357
358
  	default:
  		WARN_ON_ONCE(1);
  		if (scfcp)
  			scfcp->scfc_out = true;
5022b8ac6   Paul E. McKenney   scftorture: Imple...
359
  	}
676e54696   Paul E. McKenney   scftorture: Conso...
360
  	if (scfcp && scfsp->scfs_wait) {
9e66bf03f   Paul E. McKenney   scftorture: Adapt...
361
362
  		if (WARN_ON_ONCE((num_online_cpus() > 1 || scfsp->scfs_prim == SCF_PRIM_SINGLE) &&
  				 !scfcp->scfc_out))
676e54696   Paul E. McKenney   scftorture: Conso...
363
364
365
  			atomic_inc(&n_mb_out_errs); // Leak rather than trash!
  		else
  			kfree(scfcp);
ee7035d29   Paul E. McKenney   scftorture: Preve...
366
  		barrier(); // Prevent race-reduction compiler optimizations.
676e54696   Paul E. McKenney   scftorture: Conso...
367
  	}
e9d338a0b   Paul E. McKenney   scftorture: Add s...
368
369
370
371
372
373
374
375
376
377
378
379
  	if (use_cpus_read_lock)
  		cpus_read_unlock();
  	else
  		preempt_enable();
  	if (!(torture_random(trsp) & 0xfff))
  		schedule_timeout_uninterruptible(1);
  }
  
  // SCF test kthread.  Repeatedly does calls to members of the
  // smp_call_function() family of functions.
  static int scftorture_invoker(void *arg)
  {
a7c072ef2   Paul E. McKenney   scftorture: Block...
380
  	int cpu;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
381
382
  	DEFINE_TORTURE_RANDOM(rand);
  	struct scf_statistics *scfp = (struct scf_statistics *)arg;
a7c072ef2   Paul E. McKenney   scftorture: Block...
383
  	bool was_offline = false;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
384
385
  
  	VERBOSE_SCFTORTOUT("scftorture_invoker %d: task started", scfp->cpu);
a7c072ef2   Paul E. McKenney   scftorture: Block...
386
387
  	cpu = scfp->cpu % nr_cpu_ids;
  	set_cpus_allowed_ptr(current, cpumask_of(cpu));
e9d338a0b   Paul E. McKenney   scftorture: Add s...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  	set_user_nice(current, MAX_NICE);
  	if (holdoff)
  		schedule_timeout_interruptible(holdoff * HZ);
  
  	VERBOSE_SCFTORTOUT("scftorture_invoker %d: Waiting for all SCF torturers from cpu %d", scfp->cpu, smp_processor_id());
  
  	// Make sure that the CPU is affinitized appropriately during testing.
  	WARN_ON_ONCE(smp_processor_id() != scfp->cpu);
  
  	if (!atomic_dec_return(&n_started))
  		while (atomic_read_acquire(&n_started)) {
  			if (torture_must_stop()) {
  				VERBOSE_SCFTORTOUT("scftorture_invoker %d ended before starting", scfp->cpu);
  				goto end;
  			}
  			schedule_timeout_uninterruptible(1);
  		}
  
  	VERBOSE_SCFTORTOUT("scftorture_invoker %d started", scfp->cpu);
  
  	do {
  		scftorture_invoke_one(scfp, &rand);
a7c072ef2   Paul E. McKenney   scftorture: Block...
410
411
412
413
414
415
416
417
  		while (cpu_is_offline(cpu) && !torture_must_stop()) {
  			schedule_timeout_interruptible(HZ / 5);
  			was_offline = true;
  		}
  		if (was_offline) {
  			set_cpus_allowed_ptr(current, cpumask_of(cpu));
  			was_offline = false;
  		}
65bd77f55   Paul E. McKenney   scftorture: Add c...
418
  		cond_resched();
e9d338a0b   Paul E. McKenney   scftorture: Add s...
419
420
421
422
423
424
425
426
427
428
429
430
  	} while (!torture_must_stop());
  
  	VERBOSE_SCFTORTOUT("scftorture_invoker %d ended", scfp->cpu);
  end:
  	torture_kthread_stopping("scftorture_invoker");
  	return 0;
  }
  
  static void
  scftorture_print_module_parms(const char *tag)
  {
  	pr_alert(SCFTORT_FLAG
5022b8ac6   Paul E. McKenney   scftorture: Imple...
431
432
433
  		 "--- %s:  verbose=%d holdoff=%d longwait=%d nthreads=%d onoff_holdoff=%d onoff_interval=%d shutdown_secs=%d stat_interval=%d stutter_cpus=%d use_cpus_read_lock=%d, weight_single=%d, weight_single_wait=%d, weight_many=%d, weight_many_wait=%d, weight_all=%d, weight_all_wait=%d
  ", tag,
  		 verbose, holdoff, longwait, nthreads, onoff_holdoff, onoff_interval, shutdown, stat_interval, stutter_cpus, use_cpus_read_lock, weight_single, weight_single_wait, weight_many, weight_many_wait, weight_all, weight_all_wait);
e9d338a0b   Paul E. McKenney   scftorture: Add s...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  }
  
  static void scf_cleanup_handler(void *unused)
  {
  }
  
  static void scf_torture_cleanup(void)
  {
  	int i;
  
  	if (torture_cleanup_begin())
  		return;
  
  	WRITE_ONCE(scfdone, true);
  	if (nthreads)
  		for (i = 0; i < nthreads; i++)
  			torture_stop_kthread("scftorture_invoker", scf_stats_p[i].task);
  	else
  		goto end;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
453
454
455
  	smp_call_function(scf_cleanup_handler, NULL, 0);
  	torture_stop_kthread(scf_torture_stats, scf_torture_stats_task);
  	scf_torture_stats_print();  // -After- the stats thread is stopped!
dba3142b3   Paul E. McKenney   scftorture: Summa...
456
457
  	kfree(scf_stats_p);  // -After- the last stats print has completed!
  	scf_stats_p = NULL;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
458

dbf83b655   Paul E. McKenney   scftorture: Flag ...
459
  	if (atomic_read(&n_errs) || atomic_read(&n_mb_in_errs) || atomic_read(&n_mb_out_errs))
e9d338a0b   Paul E. McKenney   scftorture: Add s...
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  		scftorture_print_module_parms("End of test: FAILURE");
  	else if (torture_onoff_failures())
  		scftorture_print_module_parms("End of test: LOCK_HOTPLUG");
  	else
  		scftorture_print_module_parms("End of test: SUCCESS");
  
  end:
  	torture_cleanup_end();
  }
  
  static int __init scf_torture_init(void)
  {
  	long i;
  	int firsterr = 0;
5022b8ac6   Paul E. McKenney   scftorture: Imple...
474
475
476
477
478
479
  	unsigned long weight_single1 = weight_single;
  	unsigned long weight_single_wait1 = weight_single_wait;
  	unsigned long weight_many1 = weight_many;
  	unsigned long weight_many_wait1 = weight_many_wait;
  	unsigned long weight_all1 = weight_all;
  	unsigned long weight_all_wait1 = weight_all_wait;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
480
481
482
483
484
485
486
  
  	if (!torture_init_begin(SCFTORT_STRING, verbose))
  		return -EBUSY;
  
  	scftorture_print_module_parms("Start of test");
  
  	if (weight_single == -1 && weight_single_wait == -1 &&
5022b8ac6   Paul E. McKenney   scftorture: Imple...
487
  	    weight_many == -1 && weight_many_wait == -1 &&
e9d338a0b   Paul E. McKenney   scftorture: Add s...
488
  	    weight_all == -1 && weight_all_wait == -1) {
5022b8ac6   Paul E. McKenney   scftorture: Imple...
489
490
491
492
493
494
  		weight_single1 = 2 * nr_cpu_ids;
  		weight_single_wait1 = 2 * nr_cpu_ids;
  		weight_many1 = 2;
  		weight_many_wait1 = 2;
  		weight_all1 = 1;
  		weight_all_wait1 = 1;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
495
496
  	} else {
  		if (weight_single == -1)
5022b8ac6   Paul E. McKenney   scftorture: Imple...
497
  			weight_single1 = 0;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
498
  		if (weight_single_wait == -1)
5022b8ac6   Paul E. McKenney   scftorture: Imple...
499
500
501
502
503
  			weight_single_wait1 = 0;
  		if (weight_many == -1)
  			weight_many1 = 0;
  		if (weight_many_wait == -1)
  			weight_many_wait1 = 0;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
504
  		if (weight_all == -1)
5022b8ac6   Paul E. McKenney   scftorture: Imple...
505
  			weight_all1 = 0;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
506
  		if (weight_all_wait == -1)
5022b8ac6   Paul E. McKenney   scftorture: Imple...
507
  			weight_all_wait1 = 0;
e9d338a0b   Paul E. McKenney   scftorture: Add s...
508
  	}
5022b8ac6   Paul E. McKenney   scftorture: Imple...
509
510
511
512
  	if (weight_single1 == 0 && weight_single_wait1 == 0 &&
  	    weight_many1 == 0 && weight_many_wait1 == 0 &&
  	    weight_all1 == 0 && weight_all_wait1 == 0) {
  		VERBOSE_SCFTORTOUT_ERRSTRING("all zero weights makes no sense");
e9d338a0b   Paul E. McKenney   scftorture: Add s...
513
514
515
  		firsterr = -EINVAL;
  		goto unwind;
  	}
5022b8ac6   Paul E. McKenney   scftorture: Imple...
516
517
518
519
520
521
522
  	scf_sel_add(weight_single1, SCF_PRIM_SINGLE, false);
  	scf_sel_add(weight_single_wait1, SCF_PRIM_SINGLE, true);
  	scf_sel_add(weight_many1, SCF_PRIM_MANY, false);
  	scf_sel_add(weight_many_wait1, SCF_PRIM_MANY, true);
  	scf_sel_add(weight_all1, SCF_PRIM_ALL, false);
  	scf_sel_add(weight_all_wait1, SCF_PRIM_ALL, true);
  	scf_sel_dump();
e9d338a0b   Paul E. McKenney   scftorture: Add s...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  
  	if (onoff_interval > 0) {
  		firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval, NULL);
  		if (firsterr)
  			goto unwind;
  	}
  	if (shutdown_secs > 0) {
  		firsterr = torture_shutdown_init(shutdown_secs, scf_torture_cleanup);
  		if (firsterr)
  			goto unwind;
  	}
  
  	// Worker tasks invoking smp_call_function().
  	if (nthreads < 0)
  		nthreads = num_online_cpus();
  	scf_stats_p = kcalloc(nthreads, sizeof(scf_stats_p[0]), GFP_KERNEL);
  	if (!scf_stats_p) {
  		VERBOSE_SCFTORTOUT_ERRSTRING("out of memory");
  		firsterr = -ENOMEM;
  		goto unwind;
  	}
  
  	VERBOSE_SCFTORTOUT("Starting %d smp_call_function() threads
  ", nthreads);
  
  	atomic_set(&n_started, nthreads);
  	for (i = 0; i < nthreads; i++) {
  		scf_stats_p[i].cpu = i;
  		firsterr = torture_create_kthread(scftorture_invoker, (void *)&scf_stats_p[i],
  						  scf_stats_p[i].task);
  		if (firsterr)
  			goto unwind;
  	}
  	if (stat_interval > 0) {
  		firsterr = torture_create_kthread(scf_torture_stats, NULL, scf_torture_stats_task);
  		if (firsterr)
  			goto unwind;
  	}
  
  	torture_init_end();
  	return 0;
  
  unwind:
  	torture_init_end();
  	scf_torture_cleanup();
  	return firsterr;
  }
  
  module_init(scf_torture_init);
  module_exit(scf_torture_cleanup);