Blame view

kernel/rcutorture.c 33.8 KB
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1
  /*
29766f1eb   Paul E. McKenney   [PATCH] rcutortur...
2
   * Read-Copy Update module-based torture test facility
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   *
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
18
   * Copyright (C) IBM Corporation, 2005, 2006
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
19
20
   *
   * Authors: Paul E. McKenney <paulmck@us.ibm.com>
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
21
   *          Josh Triplett <josh@freedesktop.org>
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
   *
   * See also:  Documentation/RCU/torture.txt
   */
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kthread.h>
  #include <linux/err.h>
  #include <linux/spinlock.h>
  #include <linux/smp.h>
  #include <linux/rcupdate.h>
  #include <linux/interrupt.h>
  #include <linux/sched.h>
  #include <asm/atomic.h>
  #include <linux/bitops.h>
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
38
39
40
41
  #include <linux/completion.h>
  #include <linux/moduleparam.h>
  #include <linux/percpu.h>
  #include <linux/notifier.h>
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
42
  #include <linux/reboot.h>
831441862   Rafael J. Wysocki   Freezer: make ker...
43
  #include <linux/freezer.h>
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
44
  #include <linux/cpu.h>
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
45
  #include <linux/delay.h>
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
46
  #include <linux/stat.h>
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
47
  #include <linux/srcu.h>
1aeb272cf   Robert P. J. Day   kernel: explicitl...
48
  #include <linux/slab.h>
f07767fd0   Harvey Harrison   byteorder: remove...
49
  #include <asm/byteorder.h>
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
50
51
  
  MODULE_LICENSE("GPL");
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
52
53
  MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
                "Josh Triplett <josh@freedesktop.org>");
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
54

4802211cf   Josh Triplett   rcutorture: Fix i...
55
  static int nreaders = -1;	/* # reader threads, defaults to 2*ncpus */
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
56
  static int nfakewriters = 4;	/* # fake writer threads */
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
57
  static int stat_interval;	/* Interval between stats, in seconds. */
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
58
  				/*  Defaults to "only at end of test". */
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
59
60
  static int verbose;		/* Print more debug info. */
  static int test_no_idle_hz;	/* Test RCU's support for tickless idle CPUs. */
d120f65f3   Paul E. McKenney   rcu: make rcutort...
61
62
  static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
  static int stutter = 5;		/* Start/stop testing interval (in sec) */
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
63
  static int irqreader = 1;	/* RCU readers from irq (timers). */
20d2e4283   Josh Triplett   [PATCH] rcu: add ...
64
  static char *torture_type = "rcu"; /* What RCU implementation to torture. */
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
65

d6ad67112   Josh Triplett   [PATCH] Publish r...
66
  module_param(nreaders, int, 0444);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
67
  MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
d6ad67112   Josh Triplett   [PATCH] Publish r...
68
  module_param(nfakewriters, int, 0444);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
69
  MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
d6ad67112   Josh Triplett   [PATCH] Publish r...
70
  module_param(stat_interval, int, 0444);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
71
  MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
d6ad67112   Josh Triplett   [PATCH] Publish r...
72
  module_param(verbose, bool, 0444);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
73
  MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
d6ad67112   Josh Triplett   [PATCH] Publish r...
74
  module_param(test_no_idle_hz, bool, 0444);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
75
  MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
d6ad67112   Josh Triplett   [PATCH] Publish r...
76
  module_param(shuffle_interval, int, 0444);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
77
  MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
d120f65f3   Paul E. McKenney   rcu: make rcutort...
78
79
  module_param(stutter, int, 0444);
  MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
80
81
  module_param(irqreader, int, 0444);
  MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
d6ad67112   Josh Triplett   [PATCH] Publish r...
82
  module_param(torture_type, charp, 0444);
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
83
  MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
84
85
  
  #define TORTURE_FLAG "-torture:"
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
86
  #define PRINTK_STRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
87
88
  	do { printk(KERN_ALERT "%s" TORTURE_FLAG s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
89
  #define VERBOSE_PRINTK_STRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
90
91
  	do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
92
  #define VERBOSE_PRINTK_ERRSTRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
93
94
  	do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
95
96
97
98
99
  
  static char printk_buf[4096];
  
  static int nrealreaders;
  static struct task_struct *writer_task;
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
100
  static struct task_struct **fakewriter_tasks;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
101
102
  static struct task_struct **reader_tasks;
  static struct task_struct *stats_task;
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
103
  static struct task_struct *shuffler_task;
d120f65f3   Paul E. McKenney   rcu: make rcutort...
104
  static struct task_struct *stutter_task;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
105
106
107
108
109
110
111
  
  #define RCU_TORTURE_PIPE_LEN 10
  
  struct rcu_torture {
  	struct rcu_head rtort_rcu;
  	int rtort_pipe_count;
  	struct list_head rtort_free;
996417d2c   Paul E. McKenney   [PATCH] add succe...
112
  	int rtort_mbtest;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
113
  };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
114
115
116
117
118
119
120
121
122
123
  static LIST_HEAD(rcu_torture_freelist);
  static struct rcu_torture *rcu_torture_current = NULL;
  static long rcu_torture_current_version = 0;
  static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
  static DEFINE_SPINLOCK(rcu_torture_lock);
  static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) =
  	{ 0 };
  static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) =
  	{ 0 };
  static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
124
125
126
127
128
  static atomic_t n_rcu_torture_alloc;
  static atomic_t n_rcu_torture_alloc_fail;
  static atomic_t n_rcu_torture_free;
  static atomic_t n_rcu_torture_mberror;
  static atomic_t n_rcu_torture_error;
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
129
  static long n_rcu_torture_timers = 0;
e30337365   Josh Triplett   [PATCH] rcu: refa...
130
  static struct list_head rcu_torture_removed;
73d0a4b10   Rusty Russell   cpumask: convert ...
131
  static cpumask_var_t shuffle_tmp_mask;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
132

d120f65f3   Paul E. McKenney   rcu: make rcutort...
133
  static int stutter_pause_test = 0;
31a72bce0   Paul E. McKenney   rcu: make rcutort...
134
135
136
137
138
139
  #if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE)
  #define RCUTORTURE_RUNNABLE_INIT 1
  #else
  #define RCUTORTURE_RUNNABLE_INIT 0
  #endif
  int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
140
141
142
143
144
145
146
147
  /* Mediate rmmod and system shutdown.  Concurrent rmmod & shutdown illegal! */
  
  #define FULLSTOP_DONTSTOP 0	/* Normal operation. */
  #define FULLSTOP_SHUTDOWN 1	/* System shutdown with rcutorture running. */
  #define FULLSTOP_RMMOD    2	/* Normal rmmod of rcutorture. */
  static int fullstop = FULLSTOP_RMMOD;
  DEFINE_MUTEX(fullstop_mutex);	/* Protect fullstop transitions and spawning */
  				/*  of kthreads. */
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
148
149
  
  /*
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
150
   * Detect and respond to a system shutdown.
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
151
152
153
154
155
   */
  static int
  rcutorture_shutdown_notify(struct notifier_block *unused1,
  			   unsigned long unused2, void *unused3)
  {
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
156
  	mutex_lock(&fullstop_mutex);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
157
  	if (fullstop == FULLSTOP_DONTSTOP)
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
158
  		fullstop = FULLSTOP_SHUTDOWN;
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
159
160
161
162
  	else
  		printk(KERN_WARNING /* but going down anyway, so... */
  		       "Concurrent 'rmmod rcutorture' and shutdown illegal!
  ");
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
163
  	mutex_unlock(&fullstop_mutex);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
164
165
  	return NOTIFY_DONE;
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
166
  /*
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
   * Absorb kthreads into a kernel function that won't return, so that
   * they won't ever access module text or data again.
   */
  static void rcutorture_shutdown_absorb(char *title)
  {
  	if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
  		printk(KERN_NOTICE
  		       "rcutorture thread %s parking due to system shutdown
  ",
  		       title);
  		schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT);
  	}
  }
  
  /*
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
182
183
   * Allocate an element from the rcu_tortures pool.
   */
97a41e261   Adrian Bunk   [PATCH] kernel/: ...
184
  static struct rcu_torture *
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
185
186
187
  rcu_torture_alloc(void)
  {
  	struct list_head *p;
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
188
  	spin_lock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
189
190
  	if (list_empty(&rcu_torture_freelist)) {
  		atomic_inc(&n_rcu_torture_alloc_fail);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
191
  		spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
192
193
194
195
196
  		return NULL;
  	}
  	atomic_inc(&n_rcu_torture_alloc);
  	p = rcu_torture_freelist.next;
  	list_del_init(p);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
197
  	spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
198
199
200
201
202
203
204
205
206
207
  	return container_of(p, struct rcu_torture, rtort_free);
  }
  
  /*
   * Free an element to the rcu_tortures pool.
   */
  static void
  rcu_torture_free(struct rcu_torture *p)
  {
  	atomic_inc(&n_rcu_torture_free);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
208
  	spin_lock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
209
  	list_add_tail(&p->rtort_free, &rcu_torture_freelist);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
210
  	spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
211
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
212
213
  struct rcu_random_state {
  	unsigned long rrs_state;
75cfef32f   Josh Triplett   [PATCH] rcu: Fix ...
214
  	long rrs_count;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
215
216
217
218
219
220
221
222
223
224
  };
  
  #define RCU_RANDOM_MULT 39916801  /* prime */
  #define RCU_RANDOM_ADD	479001701 /* prime */
  #define RCU_RANDOM_REFRESH 10000
  
  #define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 }
  
  /*
   * Crude but fast random-number generator.  Uses a linear congruential
c17ac8550   Paul E. McKenney   Make rcutorture R...
225
   * generator, with occasional help from cpu_clock().
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
226
   */
75cfef32f   Josh Triplett   [PATCH] rcu: Fix ...
227
  static unsigned long
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
228
229
  rcu_random(struct rcu_random_state *rrsp)
  {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
230
  	if (--rrsp->rrs_count < 0) {
c17ac8550   Paul E. McKenney   Make rcutorture R...
231
232
  		rrsp->rrs_state +=
  			(unsigned long)cpu_clock(raw_smp_processor_id());
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
233
234
235
236
237
  		rrsp->rrs_count = RCU_RANDOM_REFRESH;
  	}
  	rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
  	return swahw32(rrsp->rrs_state);
  }
d120f65f3   Paul E. McKenney   rcu: make rcutort...
238
  static void
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
239
  rcu_stutter_wait(char *title)
d120f65f3   Paul E. McKenney   rcu: make rcutort...
240
  {
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
241
  	while (stutter_pause_test || !rcutorture_runnable) {
e3d7be270   Paul E. McKenney   rcu, rcutorture: ...
242
243
244
  		if (rcutorture_runnable)
  			schedule_timeout_interruptible(1);
  		else
3ccf79f45   Paul E. McKenney   rcu: make quiesce...
245
  			schedule_timeout_interruptible(round_jiffies_relative(HZ));
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
246
  		rcutorture_shutdown_absorb(title);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
247
  	}
d120f65f3   Paul E. McKenney   rcu: make rcutort...
248
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
249
  /*
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
250
251
252
253
254
255
256
   * Operations vector for selecting different types of tests.
   */
  
  struct rcu_torture_ops {
  	void (*init)(void);
  	void (*cleanup)(void);
  	int (*readlock)(void);
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
257
  	void (*readdelay)(struct rcu_random_state *rrsp);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
258
259
260
  	void (*readunlock)(int idx);
  	int (*completed)(void);
  	void (*deferredfree)(struct rcu_torture *p);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
261
  	void (*sync)(void);
2326974df   Paul E. McKenney   rcu: add call_rcu...
262
  	void (*cb_barrier)(void);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
263
  	int (*stats)(char *page);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
264
  	int irqcapable;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
265
266
267
268
269
270
271
  	char *name;
  };
  static struct rcu_torture_ops *cur_ops = NULL;
  
  /*
   * Definitions for rcu torture testing.
   */
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
272
  static int rcu_torture_read_lock(void) __acquires(RCU)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
273
274
275
276
  {
  	rcu_read_lock();
  	return 0;
  }
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
277
278
279
280
281
282
283
284
285
286
287
  static void rcu_read_delay(struct rcu_random_state *rrsp)
  {
  	long delay;
  	const long longdelay = 200;
  
  	/* We want there to be long-running readers, but not all the time. */
  
  	delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay);
  	if (!delay)
  		udelay(longdelay);
  }
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
288
  static void rcu_torture_read_unlock(int idx) __releases(RCU)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  {
  	rcu_read_unlock();
  }
  
  static int rcu_torture_completed(void)
  {
  	return rcu_batches_completed();
  }
  
  static void
  rcu_torture_cb(struct rcu_head *p)
  {
  	int i;
  	struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
303
  	if (fullstop != FULLSTOP_DONTSTOP) {
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
  		/* Test is ending, just drop callbacks on the floor. */
  		/* The next initialization will pick up the pieces. */
  		return;
  	}
  	i = rp->rtort_pipe_count;
  	if (i > RCU_TORTURE_PIPE_LEN)
  		i = RCU_TORTURE_PIPE_LEN;
  	atomic_inc(&rcu_torture_wcount[i]);
  	if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
  		rp->rtort_mbtest = 0;
  		rcu_torture_free(rp);
  	} else
  		cur_ops->deferredfree(rp);
  }
  
  static void rcu_torture_deferred_free(struct rcu_torture *p)
  {
  	call_rcu(&p->rtort_rcu, rcu_torture_cb);
  }
  
  static struct rcu_torture_ops rcu_ops = {
  	.init = NULL,
  	.cleanup = NULL,
  	.readlock = rcu_torture_read_lock,
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
328
  	.readdelay = rcu_read_delay,
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
329
330
331
  	.readunlock = rcu_torture_read_unlock,
  	.completed = rcu_torture_completed,
  	.deferredfree = rcu_torture_deferred_free,
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
332
  	.sync = synchronize_rcu,
2326974df   Paul E. McKenney   rcu: add call_rcu...
333
  	.cb_barrier = rcu_barrier,
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
334
  	.stats = NULL,
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
335
  	.irqcapable = 1,
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
336
337
  	.name = "rcu"
  };
e30337365   Josh Triplett   [PATCH] rcu: refa...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
  {
  	int i;
  	struct rcu_torture *rp;
  	struct rcu_torture *rp1;
  
  	cur_ops->sync();
  	list_add(&p->rtort_free, &rcu_torture_removed);
  	list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
  		i = rp->rtort_pipe_count;
  		if (i > RCU_TORTURE_PIPE_LEN)
  			i = RCU_TORTURE_PIPE_LEN;
  		atomic_inc(&rcu_torture_wcount[i]);
  		if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
  			rp->rtort_mbtest = 0;
  			list_del(&rp->rtort_free);
  			rcu_torture_free(rp);
  		}
  	}
  }
  
  static void rcu_sync_torture_init(void)
  {
  	INIT_LIST_HEAD(&rcu_torture_removed);
  }
20d2e4283   Josh Triplett   [PATCH] rcu: add ...
363
364
365
366
367
368
369
370
371
  static struct rcu_torture_ops rcu_sync_ops = {
  	.init = rcu_sync_torture_init,
  	.cleanup = NULL,
  	.readlock = rcu_torture_read_lock,
  	.readdelay = rcu_read_delay,
  	.readunlock = rcu_torture_read_unlock,
  	.completed = rcu_torture_completed,
  	.deferredfree = rcu_sync_torture_deferred_free,
  	.sync = synchronize_rcu,
2326974df   Paul E. McKenney   rcu: add call_rcu...
372
  	.cb_barrier = NULL,
20d2e4283   Josh Triplett   [PATCH] rcu: add ...
373
  	.stats = NULL,
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
374
  	.irqcapable = 1,
20d2e4283   Josh Triplett   [PATCH] rcu: add ...
375
376
  	.name = "rcu_sync"
  };
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
377
378
379
  /*
   * Definitions for rcu_bh torture testing.
   */
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
380
  static int rcu_bh_torture_read_lock(void) __acquires(RCU_BH)
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
381
382
383
384
  {
  	rcu_read_lock_bh();
  	return 0;
  }
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
385
  static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH)
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
386
387
388
389
390
391
392
393
394
395
396
397
398
  {
  	rcu_read_unlock_bh();
  }
  
  static int rcu_bh_torture_completed(void)
  {
  	return rcu_batches_completed_bh();
  }
  
  static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
  {
  	call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
  }
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  struct rcu_bh_torture_synchronize {
  	struct rcu_head head;
  	struct completion completion;
  };
  
  static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head)
  {
  	struct rcu_bh_torture_synchronize *rcu;
  
  	rcu = container_of(head, struct rcu_bh_torture_synchronize, head);
  	complete(&rcu->completion);
  }
  
  static void rcu_bh_torture_synchronize(void)
  {
  	struct rcu_bh_torture_synchronize rcu;
  
  	init_completion(&rcu.completion);
  	call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
  	wait_for_completion(&rcu.completion);
  }
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
420
421
422
423
  static struct rcu_torture_ops rcu_bh_ops = {
  	.init = NULL,
  	.cleanup = NULL,
  	.readlock = rcu_bh_torture_read_lock,
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
424
  	.readdelay = rcu_read_delay,  /* just reuse rcu's version. */
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
425
426
427
  	.readunlock = rcu_bh_torture_read_unlock,
  	.completed = rcu_bh_torture_completed,
  	.deferredfree = rcu_bh_torture_deferred_free,
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
428
  	.sync = rcu_bh_torture_synchronize,
2326974df   Paul E. McKenney   rcu: add call_rcu...
429
  	.cb_barrier = rcu_barrier_bh,
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
430
  	.stats = NULL,
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
431
  	.irqcapable = 1,
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
432
433
  	.name = "rcu_bh"
  };
11a147013   Josh Triplett   [PATCH] rcu: add ...
434
435
436
437
438
439
440
441
442
  static struct rcu_torture_ops rcu_bh_sync_ops = {
  	.init = rcu_sync_torture_init,
  	.cleanup = NULL,
  	.readlock = rcu_bh_torture_read_lock,
  	.readdelay = rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock = rcu_bh_torture_read_unlock,
  	.completed = rcu_bh_torture_completed,
  	.deferredfree = rcu_sync_torture_deferred_free,
  	.sync = rcu_bh_torture_synchronize,
2326974df   Paul E. McKenney   rcu: add call_rcu...
443
  	.cb_barrier = NULL,
11a147013   Josh Triplett   [PATCH] rcu: add ...
444
  	.stats = NULL,
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
445
  	.irqcapable = 1,
11a147013   Josh Triplett   [PATCH] rcu: add ...
446
447
  	.name = "rcu_bh_sync"
  };
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
448
449
450
451
452
  /*
   * Definitions for srcu torture testing.
   */
  
  static struct srcu_struct srcu_ctl;
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
453
454
455
456
  
  static void srcu_torture_init(void)
  {
  	init_srcu_struct(&srcu_ctl);
e30337365   Josh Triplett   [PATCH] rcu: refa...
457
  	rcu_sync_torture_init();
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
458
459
460
461
462
463
464
  }
  
  static void srcu_torture_cleanup(void)
  {
  	synchronize_srcu(&srcu_ctl);
  	cleanup_srcu_struct(&srcu_ctl);
  }
012d3ca8d   Josh Triplett   [PATCH] Add Spars...
465
  static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  {
  	return srcu_read_lock(&srcu_ctl);
  }
  
  static void srcu_read_delay(struct rcu_random_state *rrsp)
  {
  	long delay;
  	const long uspertick = 1000000 / HZ;
  	const long longdelay = 10;
  
  	/* We want there to be long-running readers, but not all the time. */
  
  	delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
  	if (!delay)
  		schedule_timeout_interruptible(longdelay);
  }
012d3ca8d   Josh Triplett   [PATCH] Add Spars...
482
  static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl)
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
483
484
485
486
487
488
489
490
  {
  	srcu_read_unlock(&srcu_ctl, idx);
  }
  
  static int srcu_torture_completed(void)
  {
  	return srcu_batches_completed(&srcu_ctl);
  }
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
491
492
493
494
  static void srcu_torture_synchronize(void)
  {
  	synchronize_srcu(&srcu_ctl);
  }
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  static int srcu_torture_stats(char *page)
  {
  	int cnt = 0;
  	int cpu;
  	int idx = srcu_ctl.completed & 0x1;
  
  	cnt += sprintf(&page[cnt], "%s%s per-CPU(idx=%d):",
  		       torture_type, TORTURE_FLAG, idx);
  	for_each_possible_cpu(cpu) {
  		cnt += sprintf(&page[cnt], " %d(%d,%d)", cpu,
  			       per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx],
  			       per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]);
  	}
  	cnt += sprintf(&page[cnt], "
  ");
  	return cnt;
  }
  
  static struct rcu_torture_ops srcu_ops = {
  	.init = srcu_torture_init,
  	.cleanup = srcu_torture_cleanup,
  	.readlock = srcu_torture_read_lock,
  	.readdelay = srcu_read_delay,
  	.readunlock = srcu_torture_read_unlock,
  	.completed = srcu_torture_completed,
e30337365   Josh Triplett   [PATCH] rcu: refa...
520
  	.deferredfree = rcu_sync_torture_deferred_free,
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
521
  	.sync = srcu_torture_synchronize,
2326974df   Paul E. McKenney   rcu: add call_rcu...
522
  	.cb_barrier = NULL,
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
523
524
525
  	.stats = srcu_torture_stats,
  	.name = "srcu"
  };
4b6c2cca6   Josh Triplett   [PATCH] rcu: add ...
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  /*
   * Definitions for sched torture testing.
   */
  
  static int sched_torture_read_lock(void)
  {
  	preempt_disable();
  	return 0;
  }
  
  static void sched_torture_read_unlock(int idx)
  {
  	preempt_enable();
  }
  
  static int sched_torture_completed(void)
  {
  	return 0;
  }
2326974df   Paul E. McKenney   rcu: add call_rcu...
545
546
547
548
  static void rcu_sched_torture_deferred_free(struct rcu_torture *p)
  {
  	call_rcu_sched(&p->rtort_rcu, rcu_torture_cb);
  }
4b6c2cca6   Josh Triplett   [PATCH] rcu: add ...
549
550
551
552
553
554
555
556
557
558
559
560
  static void sched_torture_synchronize(void)
  {
  	synchronize_sched();
  }
  
  static struct rcu_torture_ops sched_ops = {
  	.init = rcu_sync_torture_init,
  	.cleanup = NULL,
  	.readlock = sched_torture_read_lock,
  	.readdelay = rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock = sched_torture_read_unlock,
  	.completed = sched_torture_completed,
2326974df   Paul E. McKenney   rcu: add call_rcu...
561
  	.deferredfree = rcu_sched_torture_deferred_free,
4b6c2cca6   Josh Triplett   [PATCH] rcu: add ...
562
  	.sync = sched_torture_synchronize,
2326974df   Paul E. McKenney   rcu: add call_rcu...
563
  	.cb_barrier = rcu_barrier_sched,
4b6c2cca6   Josh Triplett   [PATCH] rcu: add ...
564
  	.stats = NULL,
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
565
  	.irqcapable = 1,
4b6c2cca6   Josh Triplett   [PATCH] rcu: add ...
566
567
  	.name = "sched"
  };
2326974df   Paul E. McKenney   rcu: add call_rcu...
568
569
570
571
572
573
574
575
576
577
578
579
580
  static struct rcu_torture_ops sched_ops_sync = {
  	.init = rcu_sync_torture_init,
  	.cleanup = NULL,
  	.readlock = sched_torture_read_lock,
  	.readdelay = rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock = sched_torture_read_unlock,
  	.completed = sched_torture_completed,
  	.deferredfree = rcu_sync_torture_deferred_free,
  	.sync = sched_torture_synchronize,
  	.cb_barrier = NULL,
  	.stats = NULL,
  	.name = "sched_sync"
  };
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
581
  /*
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
582
583
584
585
586
587
588
589
590
591
592
593
594
595
   * RCU torture writer kthread.  Repeatedly substitutes a new structure
   * for that pointed to by rcu_torture_current, freeing the old structure
   * after a series of grace periods (the "pipeline").
   */
  static int
  rcu_torture_writer(void *arg)
  {
  	int i;
  	long oldbatch = rcu_batches_completed();
  	struct rcu_torture *rp;
  	struct rcu_torture *old_rp;
  	static DEFINE_RCU_RANDOM(rand);
  
  	VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
dbdf65b1b   Ingo Molnar   [PATCH] rcutortur...
596
  	set_user_nice(current, 19);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
597
598
  	do {
  		schedule_timeout_uninterruptible(1);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
599
600
601
602
603
  		if ((rp = rcu_torture_alloc()) == NULL)
  			continue;
  		rp->rtort_pipe_count = 0;
  		udelay(rcu_random(&rand) & 0x3ff);
  		old_rp = rcu_torture_current;
996417d2c   Paul E. McKenney   [PATCH] add succe...
604
  		rp->rtort_mbtest = 1;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
605
606
  		rcu_assign_pointer(rcu_torture_current, rp);
  		smp_wmb();
c8e5b1631   Josh Triplett   rcutorture: style...
607
  		if (old_rp) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
608
609
610
611
612
  			i = old_rp->rtort_pipe_count;
  			if (i > RCU_TORTURE_PIPE_LEN)
  				i = RCU_TORTURE_PIPE_LEN;
  			atomic_inc(&rcu_torture_wcount[i]);
  			old_rp->rtort_pipe_count++;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
613
  			cur_ops->deferredfree(old_rp);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
614
615
  		}
  		rcu_torture_current_version++;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
616
  		oldbatch = cur_ops->completed();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
617
618
  		rcu_stutter_wait("rcu_torture_writer");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
619
  	VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
620
621
  	rcutorture_shutdown_absorb("rcu_torture_writer");
  	while (!kthread_should_stop())
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
622
623
624
625
626
  		schedule_timeout_uninterruptible(1);
  	return 0;
  }
  
  /*
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
   * RCU torture fake writer kthread.  Repeatedly calls sync, with a random
   * delay between calls.
   */
  static int
  rcu_torture_fakewriter(void *arg)
  {
  	DEFINE_RCU_RANDOM(rand);
  
  	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
  	set_user_nice(current, 19);
  
  	do {
  		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
  		udelay(rcu_random(&rand) & 0x3ff);
  		cur_ops->sync();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
642
643
  		rcu_stutter_wait("rcu_torture_fakewriter");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
644
645
  
  	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
646
647
  	rcutorture_shutdown_absorb("rcu_torture_fakewriter");
  	while (!kthread_should_stop())
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
648
649
650
651
652
  		schedule_timeout_uninterruptible(1);
  	return 0;
  }
  
  /*
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
   * RCU torture reader from timer handler.  Dereferences rcu_torture_current,
   * incrementing the corresponding element of the pipeline array.  The
   * counter in the element should never be greater than 1, otherwise, the
   * RCU implementation is broken.
   */
  static void rcu_torture_timer(unsigned long unused)
  {
  	int idx;
  	int completed;
  	static DEFINE_RCU_RANDOM(rand);
  	static DEFINE_SPINLOCK(rand_lock);
  	struct rcu_torture *p;
  	int pipe_count;
  
  	idx = cur_ops->readlock();
  	completed = cur_ops->completed();
  	p = rcu_dereference(rcu_torture_current);
  	if (p == NULL) {
  		/* Leave because rcu_torture_writer is not yet underway */
  		cur_ops->readunlock(idx);
  		return;
  	}
  	if (p->rtort_mbtest == 0)
  		atomic_inc(&n_rcu_torture_mberror);
  	spin_lock(&rand_lock);
  	cur_ops->readdelay(&rand);
  	n_rcu_torture_timers++;
  	spin_unlock(&rand_lock);
  	preempt_disable();
  	pipe_count = p->rtort_pipe_count;
  	if (pipe_count > RCU_TORTURE_PIPE_LEN) {
  		/* Should not happen, but... */
  		pipe_count = RCU_TORTURE_PIPE_LEN;
  	}
  	++__get_cpu_var(rcu_torture_count)[pipe_count];
  	completed = cur_ops->completed() - completed;
  	if (completed > RCU_TORTURE_PIPE_LEN) {
  		/* Should not happen, but... */
  		completed = RCU_TORTURE_PIPE_LEN;
  	}
  	++__get_cpu_var(rcu_torture_batch)[completed];
  	preempt_enable();
  	cur_ops->readunlock(idx);
  }
  
  /*
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
699
700
701
702
703
704
705
706
707
   * RCU torture reader kthread.  Repeatedly dereferences rcu_torture_current,
   * incrementing the corresponding element of the pipeline array.  The
   * counter in the element should never be greater than 1, otherwise, the
   * RCU implementation is broken.
   */
  static int
  rcu_torture_reader(void *arg)
  {
  	int completed;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
708
  	int idx;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
709
710
711
  	DEFINE_RCU_RANDOM(rand);
  	struct rcu_torture *p;
  	int pipe_count;
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
712
  	struct timer_list t;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
713
714
  
  	VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
dbdf65b1b   Ingo Molnar   [PATCH] rcutortur...
715
  	set_user_nice(current, 19);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
716
717
  	if (irqreader && cur_ops->irqcapable)
  		setup_timer_on_stack(&t, rcu_torture_timer, 0);
dbdf65b1b   Ingo Molnar   [PATCH] rcutortur...
718

a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
719
  	do {
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
720
721
722
723
  		if (irqreader && cur_ops->irqcapable) {
  			if (!timer_pending(&t))
  				mod_timer(&t, 1);
  		}
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
724
725
  		idx = cur_ops->readlock();
  		completed = cur_ops->completed();
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
726
727
728
  		p = rcu_dereference(rcu_torture_current);
  		if (p == NULL) {
  			/* Wait for rcu_torture_writer to get underway */
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
729
  			cur_ops->readunlock(idx);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
730
731
732
  			schedule_timeout_interruptible(HZ);
  			continue;
  		}
996417d2c   Paul E. McKenney   [PATCH] add succe...
733
734
  		if (p->rtort_mbtest == 0)
  			atomic_inc(&n_rcu_torture_mberror);
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
735
  		cur_ops->readdelay(&rand);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
736
737
738
739
740
741
742
  		preempt_disable();
  		pipe_count = p->rtort_pipe_count;
  		if (pipe_count > RCU_TORTURE_PIPE_LEN) {
  			/* Should not happen, but... */
  			pipe_count = RCU_TORTURE_PIPE_LEN;
  		}
  		++__get_cpu_var(rcu_torture_count)[pipe_count];
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
743
  		completed = cur_ops->completed() - completed;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
744
745
746
747
748
749
  		if (completed > RCU_TORTURE_PIPE_LEN) {
  			/* Should not happen, but... */
  			completed = RCU_TORTURE_PIPE_LEN;
  		}
  		++__get_cpu_var(rcu_torture_batch)[completed];
  		preempt_enable();
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
750
  		cur_ops->readunlock(idx);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
751
  		schedule();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
752
753
  		rcu_stutter_wait("rcu_torture_reader");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
754
  	VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
755
  	rcutorture_shutdown_absorb("rcu_torture_reader");
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
756
757
  	if (irqreader && cur_ops->irqcapable)
  		del_timer_sync(&t);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
758
  	while (!kthread_should_stop())
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
  		schedule_timeout_uninterruptible(1);
  	return 0;
  }
  
  /*
   * Create an RCU-torture statistics message in the specified buffer.
   */
  static int
  rcu_torture_printk(char *page)
  {
  	int cnt = 0;
  	int cpu;
  	int i;
  	long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
  	long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
0a9450227   KAMEZAWA Hiroyuki   [PATCH] for_each_...
774
  	for_each_possible_cpu(cpu) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
775
776
777
778
779
780
781
782
783
  		for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
  			pipesummary[i] += per_cpu(rcu_torture_count, cpu)[i];
  			batchsummary[i] += per_cpu(rcu_torture_batch, cpu)[i];
  		}
  	}
  	for (i = RCU_TORTURE_PIPE_LEN - 1; i >= 0; i--) {
  		if (pipesummary[i] != 0)
  			break;
  	}
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
784
  	cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
785
  	cnt += sprintf(&page[cnt],
996417d2c   Paul E. McKenney   [PATCH] add succe...
786
  		       "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
787
  		       "rtmbe: %d nt: %ld",
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
788
789
790
791
792
  		       rcu_torture_current,
  		       rcu_torture_current_version,
  		       list_empty(&rcu_torture_freelist),
  		       atomic_read(&n_rcu_torture_alloc),
  		       atomic_read(&n_rcu_torture_alloc_fail),
996417d2c   Paul E. McKenney   [PATCH] add succe...
793
  		       atomic_read(&n_rcu_torture_free),
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
794
795
  		       atomic_read(&n_rcu_torture_mberror),
  		       n_rcu_torture_timers);
996417d2c   Paul E. McKenney   [PATCH] add succe...
796
797
  	if (atomic_read(&n_rcu_torture_mberror) != 0)
  		cnt += sprintf(&page[cnt], " !!!");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
798
799
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
996417d2c   Paul E. McKenney   [PATCH] add succe...
800
  	if (i > 1) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
801
  		cnt += sprintf(&page[cnt], "!!! ");
996417d2c   Paul E. McKenney   [PATCH] add succe...
802
  		atomic_inc(&n_rcu_torture_error);
5af970a48   Ingo Molnar   rcutorture: WARN_...
803
  		WARN_ON_ONCE(1);
996417d2c   Paul E. McKenney   [PATCH] add succe...
804
  	}
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
805
806
807
  	cnt += sprintf(&page[cnt], "Reader Pipe: ");
  	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
  		cnt += sprintf(&page[cnt], " %ld", pipesummary[i]);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
808
809
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
810
  	cnt += sprintf(&page[cnt], "Reader Batch: ");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
811
  	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
812
  		cnt += sprintf(&page[cnt], " %ld", batchsummary[i]);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
813
814
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
815
816
817
818
819
820
821
  	cnt += sprintf(&page[cnt], "Free-Block Circulation: ");
  	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
  		cnt += sprintf(&page[cnt], " %d",
  			       atomic_read(&rcu_torture_wcount[i]));
  	}
  	cnt += sprintf(&page[cnt], "
  ");
c8e5b1631   Josh Triplett   rcutorture: style...
822
  	if (cur_ops->stats)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
823
  		cnt += cur_ops->stats(&page[cnt]);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
  	return cnt;
  }
  
  /*
   * Print torture statistics.  Caller must ensure that there is only
   * one call to this function at a given time!!!  This is normally
   * accomplished by relying on the module system to only have one copy
   * of the module loaded, and then by giving the rcu_torture_stats
   * kthread full control (or the init/cleanup functions when rcu_torture_stats
   * thread is not running).
   */
  static void
  rcu_torture_stats_print(void)
  {
  	int cnt;
  
  	cnt = rcu_torture_printk(printk_buf);
  	printk(KERN_ALERT "%s", printk_buf);
  }
  
  /*
   * Periodically prints torture statistics, if periodic statistics printing
   * was specified via the stat_interval module parameter.
   *
   * No need to worry about fullstop here, since this one doesn't reference
   * volatile state or register callbacks.
   */
  static int
  rcu_torture_stats(void *arg)
  {
  	VERBOSE_PRINTK_STRING("rcu_torture_stats task started");
  	do {
  		schedule_timeout_interruptible(stat_interval * HZ);
  		rcu_torture_stats_print();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
858
859
  		rcutorture_shutdown_absorb("rcu_torture_stats");
  	} while (!kthread_should_stop());
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
860
861
862
  	VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
  	return 0;
  }
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
863
864
865
866
867
  static int rcu_idle_cpu;	/* Force all torture tasks off this CPU */
  
  /* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
   * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
   */
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
868
  static void rcu_torture_shuffle_tasks(void)
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
869
  {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
870
  	int i;
73d0a4b10   Rusty Russell   cpumask: convert ...
871
  	cpumask_setall(shuffle_tmp_mask);
86ef5c9a8   Gautham R Shenoy   cpu-hotplug: repl...
872
  	get_online_cpus();
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
873
874
  
  	/* No point in shuffling if there is only one online CPU (ex: UP) */
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
875
876
877
878
  	if (num_online_cpus() == 1) {
  		put_online_cpus();
  		return;
  	}
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
879
880
  
  	if (rcu_idle_cpu != -1)
73d0a4b10   Rusty Russell   cpumask: convert ...
881
  		cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
882

73d0a4b10   Rusty Russell   cpumask: convert ...
883
  	set_cpus_allowed_ptr(current, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
884

c8e5b1631   Josh Triplett   rcutorture: style...
885
  	if (reader_tasks) {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
886
887
  		for (i = 0; i < nrealreaders; i++)
  			if (reader_tasks[i])
f70316dac   Mike Travis   generic: use new ...
888
  				set_cpus_allowed_ptr(reader_tasks[i],
73d0a4b10   Rusty Russell   cpumask: convert ...
889
  						     shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
890
  	}
c8e5b1631   Josh Triplett   rcutorture: style...
891
  	if (fakewriter_tasks) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
892
893
  		for (i = 0; i < nfakewriters; i++)
  			if (fakewriter_tasks[i])
f70316dac   Mike Travis   generic: use new ...
894
  				set_cpus_allowed_ptr(fakewriter_tasks[i],
73d0a4b10   Rusty Russell   cpumask: convert ...
895
  						     shuffle_tmp_mask);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
896
  	}
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
897
  	if (writer_task)
73d0a4b10   Rusty Russell   cpumask: convert ...
898
  		set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
899
900
  
  	if (stats_task)
73d0a4b10   Rusty Russell   cpumask: convert ...
901
  		set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
902
903
904
905
906
  
  	if (rcu_idle_cpu == -1)
  		rcu_idle_cpu = num_online_cpus() - 1;
  	else
  		rcu_idle_cpu--;
86ef5c9a8   Gautham R Shenoy   cpu-hotplug: repl...
907
  	put_online_cpus();
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
908
909
910
911
912
913
914
915
916
917
918
919
920
  }
  
  /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
   * system to become idle at a time and cut off its timer ticks. This is meant
   * to test the support for such tickless idle CPU in RCU.
   */
  static int
  rcu_torture_shuffle(void *arg)
  {
  	VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started");
  	do {
  		schedule_timeout_interruptible(shuffle_interval * HZ);
  		rcu_torture_shuffle_tasks();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
921
922
  		rcutorture_shutdown_absorb("rcu_torture_shuffle");
  	} while (!kthread_should_stop());
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
923
924
925
  	VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
  	return 0;
  }
d120f65f3   Paul E. McKenney   rcu: make rcutort...
926
927
928
929
930
931
932
933
934
935
  /* Cause the rcutorture test to "stutter", starting and stopping all
   * threads periodically.
   */
  static int
  rcu_torture_stutter(void *arg)
  {
  	VERBOSE_PRINTK_STRING("rcu_torture_stutter task started");
  	do {
  		schedule_timeout_interruptible(stutter * HZ);
  		stutter_pause_test = 1;
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
936
  		if (!kthread_should_stop())
d120f65f3   Paul E. McKenney   rcu: make rcutort...
937
938
  			schedule_timeout_interruptible(stutter * HZ);
  		stutter_pause_test = 0;
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
939
940
  		rcutorture_shutdown_absorb("rcu_torture_stutter");
  	} while (!kthread_should_stop());
d120f65f3   Paul E. McKenney   rcu: make rcutort...
941
942
943
  	VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
  	return 0;
  }
95c383227   Paul E. McKenney   [PATCH] rcutortur...
944
945
946
  static inline void
  rcu_torture_print_module_parms(char *tag)
  {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
947
948
  	printk(KERN_ALERT "%s" TORTURE_FLAG
  		"--- %s: nreaders=%d nfakewriters=%d "
95c383227   Paul E. McKenney   [PATCH] rcutortur...
949
  		"stat_interval=%d verbose=%d test_no_idle_hz=%d "
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
950
951
  		"shuffle_interval=%d stutter=%d irqreader=%d
  ",
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
952
  		torture_type, tag, nrealreaders, nfakewriters,
d120f65f3   Paul E. McKenney   rcu: make rcutort...
953
  		stat_interval, verbose, test_no_idle_hz, shuffle_interval,
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
954
  		stutter, irqreader);
95c383227   Paul E. McKenney   [PATCH] rcutortur...
955
  }
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
956
957
958
  static struct notifier_block rcutorture_nb = {
  	.notifier_call = rcutorture_shutdown_notify,
  };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
959
960
961
962
  static void
  rcu_torture_cleanup(void)
  {
  	int i;
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
963
  	mutex_lock(&fullstop_mutex);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
964
965
966
967
  	if (fullstop == FULLSTOP_SHUTDOWN) {
  		printk(KERN_WARNING /* but going down anyway, so... */
  		       "Concurrent 'rmmod rcutorture' and shutdown illegal!
  ");
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
968
  		mutex_unlock(&fullstop_mutex);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
969
  		schedule_timeout_uninterruptible(10);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
970
971
972
973
  		if (cur_ops->cb_barrier != NULL)
  			cur_ops->cb_barrier();
  		return;
  	}
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
974
  	fullstop = FULLSTOP_RMMOD;
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
975
976
  	mutex_unlock(&fullstop_mutex);
  	unregister_reboot_notifier(&rcutorture_nb);
d120f65f3   Paul E. McKenney   rcu: make rcutort...
977
978
979
980
981
  	if (stutter_task) {
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
  		kthread_stop(stutter_task);
  	}
  	stutter_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
982
  	if (shuffler_task) {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
983
984
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
  		kthread_stop(shuffler_task);
73d0a4b10   Rusty Russell   cpumask: convert ...
985
  		free_cpumask_var(shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
986
987
  	}
  	shuffler_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
988
  	if (writer_task) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
989
990
991
992
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
  		kthread_stop(writer_task);
  	}
  	writer_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
993
  	if (reader_tasks) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
994
  		for (i = 0; i < nrealreaders; i++) {
c8e5b1631   Josh Triplett   rcutorture: style...
995
  			if (reader_tasks[i]) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
996
997
998
999
1000
1001
1002
1003
1004
1005
  				VERBOSE_PRINTK_STRING(
  					"Stopping rcu_torture_reader task");
  				kthread_stop(reader_tasks[i]);
  			}
  			reader_tasks[i] = NULL;
  		}
  		kfree(reader_tasks);
  		reader_tasks = NULL;
  	}
  	rcu_torture_current = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
1006
  	if (fakewriter_tasks) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1007
  		for (i = 0; i < nfakewriters; i++) {
c8e5b1631   Josh Triplett   rcutorture: style...
1008
  			if (fakewriter_tasks[i]) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1009
1010
1011
1012
1013
1014
1015
1016
1017
  				VERBOSE_PRINTK_STRING(
  					"Stopping rcu_torture_fakewriter task");
  				kthread_stop(fakewriter_tasks[i]);
  			}
  			fakewriter_tasks[i] = NULL;
  		}
  		kfree(fakewriter_tasks);
  		fakewriter_tasks = NULL;
  	}
c8e5b1631   Josh Triplett   rcutorture: style...
1018
  	if (stats_task) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1019
1020
1021
1022
1023
1024
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
  		kthread_stop(stats_task);
  	}
  	stats_task = NULL;
  
  	/* Wait for all RCU callbacks to fire.  */
2326974df   Paul E. McKenney   rcu: add call_rcu...
1025
1026
1027
  
  	if (cur_ops->cb_barrier != NULL)
  		cur_ops->cb_barrier();
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1028

a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1029
  	rcu_torture_stats_print();  /* -After- the stats thread is stopped! */
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1030

c8e5b1631   Josh Triplett   rcutorture: style...
1031
  	if (cur_ops->cleanup)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1032
  		cur_ops->cleanup();
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1033
1034
1035
1036
  	if (atomic_read(&n_rcu_torture_error))
  		rcu_torture_print_module_parms("End of test: FAILURE");
  	else
  		rcu_torture_print_module_parms("End of test: SUCCESS");
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1037
  }
6f8bc500a   Josh Triplett   rcutorture: Mark ...
1038
  static int __init
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1039
1040
1041
1042
1043
  rcu_torture_init(void)
  {
  	int i;
  	int cpu;
  	int firsterr = 0;
ade5fb818   Josh Triplett   rcutorture: Remov...
1044
1045
  	static struct rcu_torture_ops *torture_ops[] =
  		{ &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops,
2326974df   Paul E. McKenney   rcu: add call_rcu...
1046
  		  &srcu_ops, &sched_ops, &sched_ops_sync, };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1047

343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1048
  	mutex_lock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1049
  	/* Process args and tell the world that the torturer is on the job. */
ade5fb818   Josh Triplett   rcutorture: Remov...
1050
  	for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1051
  		cur_ops = torture_ops[i];
ade5fb818   Josh Triplett   rcutorture: Remov...
1052
  		if (strcmp(torture_type, cur_ops->name) == 0)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1053
  			break;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1054
  	}
ade5fb818   Josh Triplett   rcutorture: Remov...
1055
  	if (i == ARRAY_SIZE(torture_ops)) {
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1056
1057
1058
  		printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"
  ",
  		       torture_type);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1059
  		mutex_unlock(&fullstop_mutex);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1060
1061
  		return (-EINVAL);
  	}
c8e5b1631   Josh Triplett   rcutorture: style...
1062
  	if (cur_ops->init)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1063
  		cur_ops->init(); /* no "goto unwind" prior to this point!!! */
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1064
1065
1066
1067
  	if (nreaders >= 0)
  		nrealreaders = nreaders;
  	else
  		nrealreaders = 2 * num_online_cpus();
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1068
  	rcu_torture_print_module_parms("Start of test");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1069
  	fullstop = FULLSTOP_DONTSTOP;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1070
1071
1072
1073
  
  	/* Set up the freelist. */
  
  	INIT_LIST_HEAD(&rcu_torture_freelist);
788e770eb   Ahmed S. Darwish   rcutorture: Use A...
1074
  	for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) {
996417d2c   Paul E. McKenney   [PATCH] add succe...
1075
  		rcu_tortures[i].rtort_mbtest = 0;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
  		list_add_tail(&rcu_tortures[i].rtort_free,
  			      &rcu_torture_freelist);
  	}
  
  	/* Initialize the statistics so that each run gets its own numbers. */
  
  	rcu_torture_current = NULL;
  	rcu_torture_current_version = 0;
  	atomic_set(&n_rcu_torture_alloc, 0);
  	atomic_set(&n_rcu_torture_alloc_fail, 0);
  	atomic_set(&n_rcu_torture_free, 0);
996417d2c   Paul E. McKenney   [PATCH] add succe...
1087
1088
  	atomic_set(&n_rcu_torture_mberror, 0);
  	atomic_set(&n_rcu_torture_error, 0);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1089
1090
  	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
  		atomic_set(&rcu_torture_wcount[i], 0);
0a9450227   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1091
  	for_each_possible_cpu(cpu) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  		for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
  			per_cpu(rcu_torture_count, cpu)[i] = 0;
  			per_cpu(rcu_torture_batch, cpu)[i] = 0;
  		}
  	}
  
  	/* Start up the kthreads. */
  
  	VERBOSE_PRINTK_STRING("Creating rcu_torture_writer task");
  	writer_task = kthread_run(rcu_torture_writer, NULL,
  				  "rcu_torture_writer");
  	if (IS_ERR(writer_task)) {
  		firsterr = PTR_ERR(writer_task);
  		VERBOSE_PRINTK_ERRSTRING("Failed to create writer");
  		writer_task = NULL;
  		goto unwind;
  	}
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
  	fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
  	                           GFP_KERNEL);
  	if (fakewriter_tasks == NULL) {
  		VERBOSE_PRINTK_ERRSTRING("out of memory");
  		firsterr = -ENOMEM;
  		goto unwind;
  	}
  	for (i = 0; i < nfakewriters; i++) {
  		VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
  		fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
  		                                  "rcu_torture_fakewriter");
  		if (IS_ERR(fakewriter_tasks[i])) {
  			firsterr = PTR_ERR(fakewriter_tasks[i]);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
  			fakewriter_tasks[i] = NULL;
  			goto unwind;
  		}
  	}
2860aaba4   Josh Triplett   [PATCH] rcu: Avoi...
1127
  	reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
  			       GFP_KERNEL);
  	if (reader_tasks == NULL) {
  		VERBOSE_PRINTK_ERRSTRING("out of memory");
  		firsterr = -ENOMEM;
  		goto unwind;
  	}
  	for (i = 0; i < nrealreaders; i++) {
  		VERBOSE_PRINTK_STRING("Creating rcu_torture_reader task");
  		reader_tasks[i] = kthread_run(rcu_torture_reader, NULL,
  					      "rcu_torture_reader");
  		if (IS_ERR(reader_tasks[i])) {
  			firsterr = PTR_ERR(reader_tasks[i]);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create reader");
  			reader_tasks[i] = NULL;
  			goto unwind;
  		}
  	}
  	if (stat_interval > 0) {
  		VERBOSE_PRINTK_STRING("Creating rcu_torture_stats task");
  		stats_task = kthread_run(rcu_torture_stats, NULL,
  					"rcu_torture_stats");
  		if (IS_ERR(stats_task)) {
  			firsterr = PTR_ERR(stats_task);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create stats");
  			stats_task = NULL;
  			goto unwind;
  		}
  	}
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1156
1157
  	if (test_no_idle_hz) {
  		rcu_idle_cpu = num_online_cpus() - 1;
73d0a4b10   Rusty Russell   cpumask: convert ...
1158
1159
1160
1161
1162
1163
  
  		if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) {
  			firsterr = -ENOMEM;
  			VERBOSE_PRINTK_ERRSTRING("Failed to alloc mask");
  			goto unwind;
  		}
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1164
1165
1166
1167
  		/* Create the shuffler thread */
  		shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
  					  "rcu_torture_shuffle");
  		if (IS_ERR(shuffler_task)) {
73d0a4b10   Rusty Russell   cpumask: convert ...
1168
  			free_cpumask_var(shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1169
1170
1171
1172
1173
1174
  			firsterr = PTR_ERR(shuffler_task);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
  			shuffler_task = NULL;
  			goto unwind;
  		}
  	}
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
  	if (stutter < 0)
  		stutter = 0;
  	if (stutter) {
  		/* Create the stutter thread */
  		stutter_task = kthread_run(rcu_torture_stutter, NULL,
  					  "rcu_torture_stutter");
  		if (IS_ERR(stutter_task)) {
  			firsterr = PTR_ERR(stutter_task);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create stutter");
  			stutter_task = NULL;
  			goto unwind;
  		}
  	}
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1188
1189
  	register_reboot_notifier(&rcutorture_nb);
  	mutex_unlock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1190
1191
1192
  	return 0;
  
  unwind:
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1193
  	mutex_unlock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1194
1195
1196
1197
1198
1199
  	rcu_torture_cleanup();
  	return firsterr;
  }
  
  module_init(rcu_torture_init);
  module_exit(rcu_torture_cleanup);