Blame view

kernel/rcutorture.c 38.5 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>
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
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
  MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
53
  	      "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). */
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
64
65
66
  static int fqs_duration = 0;	/* Duration of bursts (us), 0 to disable. */
  static int fqs_holdoff = 0;	/* Hold time within burst (us). */
  static int fqs_stutter = 3;	/* Wait time between bursts (s). */
20d2e4283   Josh Triplett   [PATCH] rcu: add ...
67
  static char *torture_type = "rcu"; /* What RCU implementation to torture. */
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
68

d6ad67112   Josh Triplett   [PATCH] Publish r...
69
  module_param(nreaders, int, 0444);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
70
  MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
d6ad67112   Josh Triplett   [PATCH] Publish r...
71
  module_param(nfakewriters, int, 0444);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
72
  MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
d6ad67112   Josh Triplett   [PATCH] Publish r...
73
  module_param(stat_interval, int, 0444);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
74
  MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
d6ad67112   Josh Triplett   [PATCH] Publish r...
75
  module_param(verbose, bool, 0444);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
76
  MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
d6ad67112   Josh Triplett   [PATCH] Publish r...
77
  module_param(test_no_idle_hz, bool, 0444);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
78
  MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
d6ad67112   Josh Triplett   [PATCH] Publish r...
79
  module_param(shuffle_interval, int, 0444);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
80
  MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
d120f65f3   Paul E. McKenney   rcu: make rcutort...
81
82
  module_param(stutter, int, 0444);
  MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
83
84
  module_param(irqreader, int, 0444);
  MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
85
86
87
88
89
90
  module_param(fqs_duration, int, 0444);
  MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us)");
  module_param(fqs_holdoff, int, 0444);
  MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
  module_param(fqs_stutter, int, 0444);
  MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
d6ad67112   Josh Triplett   [PATCH] Publish r...
91
  module_param(torture_type, charp, 0444);
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
92
  MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
93
94
  
  #define TORTURE_FLAG "-torture:"
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
95
  #define PRINTK_STRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
96
97
  	do { printk(KERN_ALERT "%s" TORTURE_FLAG s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
98
  #define VERBOSE_PRINTK_STRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
99
100
  	do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
101
  #define VERBOSE_PRINTK_ERRSTRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
102
103
  	do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
104
105
106
107
108
  
  static char printk_buf[4096];
  
  static int nrealreaders;
  static struct task_struct *writer_task;
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
109
  static struct task_struct **fakewriter_tasks;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
110
111
  static struct task_struct **reader_tasks;
  static struct task_struct *stats_task;
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
112
  static struct task_struct *shuffler_task;
d120f65f3   Paul E. McKenney   rcu: make rcutort...
113
  static struct task_struct *stutter_task;
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
114
  static struct task_struct *fqs_task;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
115
116
117
118
119
120
121
  
  #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...
122
  	int rtort_mbtest;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
123
  };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
124
  static LIST_HEAD(rcu_torture_freelist);
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
125
126
  static struct rcu_torture *rcu_torture_current;
  static long rcu_torture_current_version;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
127
128
129
130
131
132
133
  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...
134
135
136
137
138
  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;
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
139
  static long n_rcu_torture_timers;
e30337365   Josh Triplett   [PATCH] rcu: refa...
140
  static struct list_head rcu_torture_removed;
73d0a4b10   Rusty Russell   cpumask: convert ...
141
  static cpumask_var_t shuffle_tmp_mask;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
142

a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
143
  static int stutter_pause_test;
d120f65f3   Paul E. McKenney   rcu: make rcutort...
144

31a72bce0   Paul E. McKenney   rcu: make rcutort...
145
146
147
148
149
150
  #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...
151
152
153
154
155
156
157
158
  /* 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...
159
160
  
  /*
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
161
   * Detect and respond to a system shutdown.
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
162
163
164
165
166
   */
  static int
  rcutorture_shutdown_notify(struct notifier_block *unused1,
  			   unsigned long unused2, void *unused3)
  {
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
167
  	mutex_lock(&fullstop_mutex);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
168
  	if (fullstop == FULLSTOP_DONTSTOP)
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
169
  		fullstop = FULLSTOP_SHUTDOWN;
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
170
171
172
173
  	else
  		printk(KERN_WARNING /* but going down anyway, so... */
  		       "Concurrent 'rmmod rcutorture' and shutdown illegal!
  ");
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
174
  	mutex_unlock(&fullstop_mutex);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
175
176
  	return NOTIFY_DONE;
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
177
  /*
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
   * 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...
193
194
   * Allocate an element from the rcu_tortures pool.
   */
97a41e261   Adrian Bunk   [PATCH] kernel/: ...
195
  static struct rcu_torture *
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
196
197
198
  rcu_torture_alloc(void)
  {
  	struct list_head *p;
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
199
  	spin_lock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
200
201
  	if (list_empty(&rcu_torture_freelist)) {
  		atomic_inc(&n_rcu_torture_alloc_fail);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
202
  		spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
203
204
205
206
207
  		return NULL;
  	}
  	atomic_inc(&n_rcu_torture_alloc);
  	p = rcu_torture_freelist.next;
  	list_del_init(p);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
208
  	spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
209
210
211
212
213
214
215
216
217
218
  	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...
219
  	spin_lock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
220
  	list_add_tail(&p->rtort_free, &rcu_torture_freelist);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
221
  	spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
222
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
223
224
  struct rcu_random_state {
  	unsigned long rrs_state;
75cfef32f   Josh Triplett   [PATCH] rcu: Fix ...
225
  	long rrs_count;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
226
227
228
229
230
231
232
233
234
235
  };
  
  #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...
236
   * generator, with occasional help from cpu_clock().
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
237
   */
75cfef32f   Josh Triplett   [PATCH] rcu: Fix ...
238
  static unsigned long
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
239
240
  rcu_random(struct rcu_random_state *rrsp)
  {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
241
  	if (--rrsp->rrs_count < 0) {
c676329ab   Peter Zijlstra   sched_clock: Add ...
242
  		rrsp->rrs_state += (unsigned long)local_clock();
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
243
244
245
246
247
  		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...
248
  static void
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
249
  rcu_stutter_wait(char *title)
d120f65f3   Paul E. McKenney   rcu: make rcutort...
250
  {
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
251
  	while (stutter_pause_test || !rcutorture_runnable) {
e3d7be270   Paul E. McKenney   rcu, rcutorture: ...
252
253
254
  		if (rcutorture_runnable)
  			schedule_timeout_interruptible(1);
  		else
3ccf79f45   Paul E. McKenney   rcu: make quiesce...
255
  			schedule_timeout_interruptible(round_jiffies_relative(HZ));
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
256
  		rcutorture_shutdown_absorb(title);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
257
  	}
d120f65f3   Paul E. McKenney   rcu: make rcutort...
258
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
259
  /*
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
260
261
262
263
264
265
266
   * Operations vector for selecting different types of tests.
   */
  
  struct rcu_torture_ops {
  	void (*init)(void);
  	void (*cleanup)(void);
  	int (*readlock)(void);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
267
  	void (*read_delay)(struct rcu_random_state *rrsp);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
268
269
  	void (*readunlock)(int idx);
  	int (*completed)(void);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
270
  	void (*deferred_free)(struct rcu_torture *p);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
271
  	void (*sync)(void);
2326974df   Paul E. McKenney   rcu: add call_rcu...
272
  	void (*cb_barrier)(void);
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
273
  	void (*fqs)(void);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
274
  	int (*stats)(char *page);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
275
  	int irq_capable;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
276
277
  	char *name;
  };
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
278
279
  
  static struct rcu_torture_ops *cur_ops;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
280
281
282
283
  
  /*
   * Definitions for rcu torture testing.
   */
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
284
  static int rcu_torture_read_lock(void) __acquires(RCU)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
285
286
287
288
  {
  	rcu_read_lock();
  	return 0;
  }
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
289
290
  static void rcu_read_delay(struct rcu_random_state *rrsp)
  {
b8d57a76d   Josh Triplett   rcutorture: Occas...
291
292
  	const unsigned long shortdelay_us = 200;
  	const unsigned long longdelay_ms = 50;
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
293

b8d57a76d   Josh Triplett   rcutorture: Occas...
294
295
296
  	/* We want a short delay sometimes to make a reader delay the grace
  	 * period, and we want a long delay occasionally to trigger
  	 * force_quiescent_state. */
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
297

b8d57a76d   Josh Triplett   rcutorture: Occas...
298
299
300
301
  	if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
  		mdelay(longdelay_ms);
  	if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
  		udelay(shortdelay_us);
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
302
  }
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
303
  static void rcu_torture_read_unlock(int idx) __releases(RCU)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  {
  	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...
318
  	if (fullstop != FULLSTOP_DONTSTOP) {
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
319
320
321
322
323
324
325
326
327
328
329
330
  		/* 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
0acc512cb   Paul E. McKenney   rcu: Add synchron...
331
  		cur_ops->deferred_free(rp);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
332
  }
d9a3da069   Paul E. McKenney   rcu: Add expedite...
333
334
335
336
  static int rcu_no_completed(void)
  {
  	return 0;
  }
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
337
338
339
340
341
342
  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 = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
343
344
345
346
347
348
349
350
351
  	.init		= NULL,
  	.cleanup	= NULL,
  	.readlock	= rcu_torture_read_lock,
  	.read_delay	= rcu_read_delay,
  	.readunlock	= rcu_torture_read_unlock,
  	.completed	= rcu_torture_completed,
  	.deferred_free	= rcu_torture_deferred_free,
  	.sync		= synchronize_rcu,
  	.cb_barrier	= rcu_barrier,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
352
  	.fqs		= rcu_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
353
  	.stats		= NULL,
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
354
355
  	.irq_capable	= 1,
  	.name		= "rcu"
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
356
  };
e30337365   Josh Triplett   [PATCH] rcu: refa...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
  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 ...
382
  static struct rcu_torture_ops rcu_sync_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
383
384
385
386
387
388
389
390
391
  	.init		= rcu_sync_torture_init,
  	.cleanup	= NULL,
  	.readlock	= rcu_torture_read_lock,
  	.read_delay	= rcu_read_delay,
  	.readunlock	= rcu_torture_read_unlock,
  	.completed	= rcu_torture_completed,
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= synchronize_rcu,
  	.cb_barrier	= NULL,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
392
  	.fqs		= rcu_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
393
394
395
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "rcu_sync"
20d2e4283   Josh Triplett   [PATCH] rcu: add ...
396
  };
d9a3da069   Paul E. McKenney   rcu: Add expedite...
397
398
399
400
401
402
403
404
405
406
  static struct rcu_torture_ops rcu_expedited_ops = {
  	.init		= rcu_sync_torture_init,
  	.cleanup	= NULL,
  	.readlock	= rcu_torture_read_lock,
  	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock	= rcu_torture_read_unlock,
  	.completed	= rcu_no_completed,
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= synchronize_rcu_expedited,
  	.cb_barrier	= NULL,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
407
  	.fqs		= rcu_force_quiescent_state,
d9a3da069   Paul E. McKenney   rcu: Add expedite...
408
409
410
411
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "rcu_expedited"
  };
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
412
413
414
  /*
   * Definitions for rcu_bh torture testing.
   */
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
415
  static int rcu_bh_torture_read_lock(void) __acquires(RCU_BH)
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
416
417
418
419
  {
  	rcu_read_lock_bh();
  	return 0;
  }
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
420
  static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH)
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
421
422
423
424
425
426
427
428
429
430
431
432
433
  {
  	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 ...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
  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;
72d5a9f7a   Paul E. McKenney   rcu: remove all r...
450
  	init_rcu_head_on_stack(&rcu.head);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
451
452
453
  	init_completion(&rcu.completion);
  	call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
  	wait_for_completion(&rcu.completion);
72d5a9f7a   Paul E. McKenney   rcu: remove all r...
454
  	destroy_rcu_head_on_stack(&rcu.head);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
455
  }
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
456
  static struct rcu_torture_ops rcu_bh_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
457
458
459
460
461
462
463
464
465
  	.init		= NULL,
  	.cleanup	= NULL,
  	.readlock	= rcu_bh_torture_read_lock,
  	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock	= rcu_bh_torture_read_unlock,
  	.completed	= rcu_bh_torture_completed,
  	.deferred_free	= rcu_bh_torture_deferred_free,
  	.sync		= rcu_bh_torture_synchronize,
  	.cb_barrier	= rcu_barrier_bh,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
466
  	.fqs		= rcu_bh_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
467
468
469
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "rcu_bh"
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
470
  };
11a147013   Josh Triplett   [PATCH] rcu: add ...
471
  static struct rcu_torture_ops rcu_bh_sync_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
472
473
474
475
476
477
478
479
480
  	.init		= rcu_sync_torture_init,
  	.cleanup	= NULL,
  	.readlock	= rcu_bh_torture_read_lock,
  	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock	= rcu_bh_torture_read_unlock,
  	.completed	= rcu_bh_torture_completed,
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= rcu_bh_torture_synchronize,
  	.cb_barrier	= NULL,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
481
  	.fqs		= rcu_bh_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
482
483
484
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "rcu_bh_sync"
11a147013   Josh Triplett   [PATCH] rcu: add ...
485
  };
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
486
487
488
489
490
  /*
   * Definitions for srcu torture testing.
   */
  
  static struct srcu_struct srcu_ctl;
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
491
492
493
494
  
  static void srcu_torture_init(void)
  {
  	init_srcu_struct(&srcu_ctl);
e30337365   Josh Triplett   [PATCH] rcu: refa...
495
  	rcu_sync_torture_init();
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
496
497
498
499
500
501
502
  }
  
  static void srcu_torture_cleanup(void)
  {
  	synchronize_srcu(&srcu_ctl);
  	cleanup_srcu_struct(&srcu_ctl);
  }
012d3ca8d   Josh Triplett   [PATCH] Add Spars...
503
  static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  {
  	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...
520
  static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl)
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
521
522
523
524
525
526
527
528
  {
  	srcu_read_unlock(&srcu_ctl, idx);
  }
  
  static int srcu_torture_completed(void)
  {
  	return srcu_batches_completed(&srcu_ctl);
  }
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
529
530
531
532
  static void srcu_torture_synchronize(void)
  {
  	synchronize_srcu(&srcu_ctl);
  }
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  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 = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
552
553
554
555
556
557
558
559
560
561
562
  	.init		= srcu_torture_init,
  	.cleanup	= srcu_torture_cleanup,
  	.readlock	= srcu_torture_read_lock,
  	.read_delay	= srcu_read_delay,
  	.readunlock	= srcu_torture_read_unlock,
  	.completed	= srcu_torture_completed,
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= srcu_torture_synchronize,
  	.cb_barrier	= NULL,
  	.stats		= srcu_torture_stats,
  	.name		= "srcu"
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
563
  };
804bb8370   Paul E. McKenney   rcu: Add synchron...
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  static void srcu_torture_synchronize_expedited(void)
  {
  	synchronize_srcu_expedited(&srcu_ctl);
  }
  
  static struct rcu_torture_ops srcu_expedited_ops = {
  	.init		= srcu_torture_init,
  	.cleanup	= srcu_torture_cleanup,
  	.readlock	= srcu_torture_read_lock,
  	.read_delay	= srcu_read_delay,
  	.readunlock	= srcu_torture_read_unlock,
  	.completed	= srcu_torture_completed,
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= srcu_torture_synchronize_expedited,
  	.cb_barrier	= NULL,
  	.stats		= srcu_torture_stats,
  	.name		= "srcu_expedited"
  };
4b6c2cca6   Josh Triplett   [PATCH] rcu: add ...
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  /*
   * 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();
  }
2326974df   Paul E. McKenney   rcu: add call_rcu...
596
597
598
599
  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 ...
600
601
602
603
604
605
  static void sched_torture_synchronize(void)
  {
  	synchronize_sched();
  }
  
  static struct rcu_torture_ops sched_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
606
607
608
609
610
  	.init		= rcu_sync_torture_init,
  	.cleanup	= NULL,
  	.readlock	= sched_torture_read_lock,
  	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock	= sched_torture_read_unlock,
d9a3da069   Paul E. McKenney   rcu: Add expedite...
611
  	.completed	= rcu_no_completed,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
612
613
614
  	.deferred_free	= rcu_sched_torture_deferred_free,
  	.sync		= sched_torture_synchronize,
  	.cb_barrier	= rcu_barrier_sched,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
615
  	.fqs		= rcu_sched_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
616
617
618
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "sched"
4b6c2cca6   Josh Triplett   [PATCH] rcu: add ...
619
  };
804bb8370   Paul E. McKenney   rcu: Add synchron...
620
  static struct rcu_torture_ops sched_sync_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
621
622
623
624
625
  	.init		= rcu_sync_torture_init,
  	.cleanup	= NULL,
  	.readlock	= sched_torture_read_lock,
  	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock	= sched_torture_read_unlock,
d9a3da069   Paul E. McKenney   rcu: Add expedite...
626
  	.completed	= rcu_no_completed,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
627
628
629
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= sched_torture_synchronize,
  	.cb_barrier	= NULL,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
630
  	.fqs		= rcu_sched_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
631
632
633
  	.stats		= NULL,
  	.name		= "sched_sync"
  };
0acc512cb   Paul E. McKenney   rcu: Add synchron...
634
635
636
637
638
639
  static struct rcu_torture_ops sched_expedited_ops = {
  	.init		= rcu_sync_torture_init,
  	.cleanup	= NULL,
  	.readlock	= sched_torture_read_lock,
  	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
  	.readunlock	= sched_torture_read_unlock,
d9a3da069   Paul E. McKenney   rcu: Add expedite...
640
  	.completed	= rcu_no_completed,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
641
642
643
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= synchronize_sched_expedited,
  	.cb_barrier	= NULL,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
644
  	.fqs		= rcu_sched_force_quiescent_state,
969c79215   Tejun Heo   sched: replace mi...
645
  	.stats		= NULL,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
646
647
  	.irq_capable	= 1,
  	.name		= "sched_expedited"
2326974df   Paul E. McKenney   rcu: add call_rcu...
648
  };
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
649
  /*
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
650
651
652
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
   * RCU torture force-quiescent-state kthread.  Repeatedly induces
   * bursts of calls to force_quiescent_state(), increasing the probability
   * of occurrence of some important types of race conditions.
   */
  static int
  rcu_torture_fqs(void *arg)
  {
  	unsigned long fqs_resume_time;
  	int fqs_burst_remaining;
  
  	VERBOSE_PRINTK_STRING("rcu_torture_fqs task started");
  	do {
  		fqs_resume_time = jiffies + fqs_stutter * HZ;
  		while (jiffies - fqs_resume_time > LONG_MAX) {
  			schedule_timeout_interruptible(1);
  		}
  		fqs_burst_remaining = fqs_duration;
  		while (fqs_burst_remaining > 0) {
  			cur_ops->fqs();
  			udelay(fqs_holdoff);
  			fqs_burst_remaining -= fqs_holdoff;
  		}
  		rcu_stutter_wait("rcu_torture_fqs");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
  	VERBOSE_PRINTK_STRING("rcu_torture_fqs task stopping");
  	rcutorture_shutdown_absorb("rcu_torture_fqs");
  	while (!kthread_should_stop())
  		schedule_timeout_uninterruptible(1);
  	return 0;
  }
  
  /*
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
682
683
684
685
686
687
688
689
690
691
692
693
694
695
   * 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...
696
  	set_user_nice(current, 19);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
697
698
  	do {
  		schedule_timeout_uninterruptible(1);
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
699
700
  		rp = rcu_torture_alloc();
  		if (rp == NULL)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
701
702
703
704
  			continue;
  		rp->rtort_pipe_count = 0;
  		udelay(rcu_random(&rand) & 0x3ff);
  		old_rp = rcu_torture_current;
996417d2c   Paul E. McKenney   [PATCH] add succe...
705
  		rp->rtort_mbtest = 1;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
706
  		rcu_assign_pointer(rcu_torture_current, rp);
9b2619aff   Paul E. McKenney   rcu: Clean up cod...
707
  		smp_wmb(); /* Mods to old_rp must follow rcu_assign_pointer() */
c8e5b1631   Josh Triplett   rcutorture: style...
708
  		if (old_rp) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
709
710
711
712
713
  			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++;
0acc512cb   Paul E. McKenney   rcu: Add synchron...
714
  			cur_ops->deferred_free(old_rp);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
715
716
  		}
  		rcu_torture_current_version++;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
717
  		oldbatch = cur_ops->completed();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
718
719
  		rcu_stutter_wait("rcu_torture_writer");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
720
  	VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
721
722
  	rcutorture_shutdown_absorb("rcu_torture_writer");
  	while (!kthread_should_stop())
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
723
724
725
726
727
  		schedule_timeout_uninterruptible(1);
  	return 0;
  }
  
  /*
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
   * 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...
743
744
  		rcu_stutter_wait("rcu_torture_fakewriter");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
745
746
  
  	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
747
748
  	rcutorture_shutdown_absorb("rcu_torture_fakewriter");
  	while (!kthread_should_stop())
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
749
750
751
752
753
  		schedule_timeout_uninterruptible(1);
  	return 0;
  }
  
  /*
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
   * 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();
632ee2001   Paul E. McKenney   rcu: Introduce lo...
770
771
772
773
774
  	p = rcu_dereference_check(rcu_torture_current,
  				  rcu_read_lock_held() ||
  				  rcu_read_lock_bh_held() ||
  				  rcu_read_lock_sched_held() ||
  				  srcu_read_lock_held(&srcu_ctl));
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
775
776
777
778
779
780
781
782
  	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);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
783
  	cur_ops->read_delay(&rand);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
784
785
786
787
788
789
790
791
  	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;
  	}
dd17c8f72   Rusty Russell   percpu: remove pe...
792
  	__this_cpu_inc(rcu_torture_count[pipe_count]);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
793
794
795
796
797
  	completed = cur_ops->completed() - completed;
  	if (completed > RCU_TORTURE_PIPE_LEN) {
  		/* Should not happen, but... */
  		completed = RCU_TORTURE_PIPE_LEN;
  	}
dd17c8f72   Rusty Russell   percpu: remove pe...
798
  	__this_cpu_inc(rcu_torture_batch[completed]);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
799
800
801
802
803
  	preempt_enable();
  	cur_ops->readunlock(idx);
  }
  
  /*
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
804
805
806
807
808
809
810
811
812
   * 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...
813
  	int idx;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
814
815
816
  	DEFINE_RCU_RANDOM(rand);
  	struct rcu_torture *p;
  	int pipe_count;
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
817
  	struct timer_list t;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
818
819
  
  	VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
dbdf65b1b   Ingo Molnar   [PATCH] rcutortur...
820
  	set_user_nice(current, 19);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
821
  	if (irqreader && cur_ops->irq_capable)
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
822
  		setup_timer_on_stack(&t, rcu_torture_timer, 0);
dbdf65b1b   Ingo Molnar   [PATCH] rcutortur...
823

a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
824
  	do {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
825
  		if (irqreader && cur_ops->irq_capable) {
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
826
  			if (!timer_pending(&t))
6155fec92   Paul E. McKenney   rcu: Fix rcutortu...
827
  				mod_timer(&t, jiffies + 1);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
828
  		}
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
829
830
  		idx = cur_ops->readlock();
  		completed = cur_ops->completed();
632ee2001   Paul E. McKenney   rcu: Introduce lo...
831
832
833
834
835
  		p = rcu_dereference_check(rcu_torture_current,
  					  rcu_read_lock_held() ||
  					  rcu_read_lock_bh_held() ||
  					  rcu_read_lock_sched_held() ||
  					  srcu_read_lock_held(&srcu_ctl));
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
836
837
  		if (p == NULL) {
  			/* Wait for rcu_torture_writer to get underway */
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
838
  			cur_ops->readunlock(idx);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
839
840
841
  			schedule_timeout_interruptible(HZ);
  			continue;
  		}
996417d2c   Paul E. McKenney   [PATCH] add succe...
842
843
  		if (p->rtort_mbtest == 0)
  			atomic_inc(&n_rcu_torture_mberror);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
844
  		cur_ops->read_delay(&rand);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
845
846
847
848
849
850
  		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;
  		}
dd17c8f72   Rusty Russell   percpu: remove pe...
851
  		__this_cpu_inc(rcu_torture_count[pipe_count]);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
852
  		completed = cur_ops->completed() - completed;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
853
854
855
856
  		if (completed > RCU_TORTURE_PIPE_LEN) {
  			/* Should not happen, but... */
  			completed = RCU_TORTURE_PIPE_LEN;
  		}
dd17c8f72   Rusty Russell   percpu: remove pe...
857
  		__this_cpu_inc(rcu_torture_batch[completed]);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
858
  		preempt_enable();
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
859
  		cur_ops->readunlock(idx);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
860
  		schedule();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
861
862
  		rcu_stutter_wait("rcu_torture_reader");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
863
  	VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
864
  	rcutorture_shutdown_absorb("rcu_torture_reader");
0acc512cb   Paul E. McKenney   rcu: Add synchron...
865
  	if (irqreader && cur_ops->irq_capable)
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
866
  		del_timer_sync(&t);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
867
  	while (!kthread_should_stop())
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
  		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_...
883
  	for_each_possible_cpu(cpu) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
884
885
886
887
888
889
890
891
892
  		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...
893
  	cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
894
  	cnt += sprintf(&page[cnt],
996417d2c   Paul E. McKenney   [PATCH] add succe...
895
  		       "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
896
  		       "rtmbe: %d nt: %ld",
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
897
898
899
900
901
  		       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...
902
  		       atomic_read(&n_rcu_torture_free),
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
903
904
  		       atomic_read(&n_rcu_torture_mberror),
  		       n_rcu_torture_timers);
996417d2c   Paul E. McKenney   [PATCH] add succe...
905
906
  	if (atomic_read(&n_rcu_torture_mberror) != 0)
  		cnt += sprintf(&page[cnt], " !!!");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
907
908
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
996417d2c   Paul E. McKenney   [PATCH] add succe...
909
  	if (i > 1) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
910
  		cnt += sprintf(&page[cnt], "!!! ");
996417d2c   Paul E. McKenney   [PATCH] add succe...
911
  		atomic_inc(&n_rcu_torture_error);
5af970a48   Ingo Molnar   rcutorture: WARN_...
912
  		WARN_ON_ONCE(1);
996417d2c   Paul E. McKenney   [PATCH] add succe...
913
  	}
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
914
915
916
  	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...
917
918
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
919
  	cnt += sprintf(&page[cnt], "Reader Batch: ");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
920
  	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
921
  		cnt += sprintf(&page[cnt], " %ld", batchsummary[i]);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
922
923
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
924
925
926
927
928
929
930
  	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...
931
  	if (cur_ops->stats)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
932
  		cnt += cur_ops->stats(&page[cnt]);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  	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...
967
968
  		rcutorture_shutdown_absorb("rcu_torture_stats");
  	} while (!kthread_should_stop());
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
969
970
971
  	VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
  	return 0;
  }
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
972
973
974
975
976
  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...
977
  static void rcu_torture_shuffle_tasks(void)
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
978
  {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
979
  	int i;
73d0a4b10   Rusty Russell   cpumask: convert ...
980
  	cpumask_setall(shuffle_tmp_mask);
86ef5c9a8   Gautham R Shenoy   cpu-hotplug: repl...
981
  	get_online_cpus();
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
982
983
  
  	/* No point in shuffling if there is only one online CPU (ex: UP) */
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
984
985
986
987
  	if (num_online_cpus() == 1) {
  		put_online_cpus();
  		return;
  	}
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
988
989
  
  	if (rcu_idle_cpu != -1)
73d0a4b10   Rusty Russell   cpumask: convert ...
990
  		cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
991

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

c8e5b1631   Josh Triplett   rcutorture: style...
994
  	if (reader_tasks) {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
995
996
  		for (i = 0; i < nrealreaders; i++)
  			if (reader_tasks[i])
f70316dac   Mike Travis   generic: use new ...
997
  				set_cpus_allowed_ptr(reader_tasks[i],
73d0a4b10   Rusty Russell   cpumask: convert ...
998
  						     shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
999
  	}
c8e5b1631   Josh Triplett   rcutorture: style...
1000
  	if (fakewriter_tasks) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1001
1002
  		for (i = 0; i < nfakewriters; i++)
  			if (fakewriter_tasks[i])
f70316dac   Mike Travis   generic: use new ...
1003
  				set_cpus_allowed_ptr(fakewriter_tasks[i],
73d0a4b10   Rusty Russell   cpumask: convert ...
1004
  						     shuffle_tmp_mask);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1005
  	}
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1006
  	if (writer_task)
73d0a4b10   Rusty Russell   cpumask: convert ...
1007
  		set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1008
1009
  
  	if (stats_task)
73d0a4b10   Rusty Russell   cpumask: convert ...
1010
  		set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1011
1012
1013
1014
1015
  
  	if (rcu_idle_cpu == -1)
  		rcu_idle_cpu = num_online_cpus() - 1;
  	else
  		rcu_idle_cpu--;
86ef5c9a8   Gautham R Shenoy   cpu-hotplug: repl...
1016
  	put_online_cpus();
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  }
  
  /* 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...
1030
1031
  		rcutorture_shutdown_absorb("rcu_torture_shuffle");
  	} while (!kthread_should_stop());
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1032
1033
1034
  	VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
  	return 0;
  }
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  /* 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...
1045
  		if (!kthread_should_stop())
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1046
1047
  			schedule_timeout_interruptible(stutter * HZ);
  		stutter_pause_test = 0;
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1048
1049
  		rcutorture_shutdown_absorb("rcu_torture_stutter");
  	} while (!kthread_should_stop());
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1050
1051
1052
  	VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
  	return 0;
  }
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1053
1054
1055
  static inline void
  rcu_torture_print_module_parms(char *tag)
  {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1056
1057
  	printk(KERN_ALERT "%s" TORTURE_FLAG
  		"--- %s: nreaders=%d nfakewriters=%d "
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1058
  		"stat_interval=%d verbose=%d test_no_idle_hz=%d "
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1059
1060
1061
  		"shuffle_interval=%d stutter=%d irqreader=%d "
  		"fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d
  ",
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1062
  		torture_type, tag, nrealreaders, nfakewriters,
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1063
  		stat_interval, verbose, test_no_idle_hz, shuffle_interval,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1064
  		stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter);
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1065
  }
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1066
1067
1068
  static struct notifier_block rcutorture_nb = {
  	.notifier_call = rcutorture_shutdown_notify,
  };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1069
1070
1071
1072
  static void
  rcu_torture_cleanup(void)
  {
  	int i;
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1073
  	mutex_lock(&fullstop_mutex);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1074
1075
1076
1077
  	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...
1078
  		mutex_unlock(&fullstop_mutex);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1079
  		schedule_timeout_uninterruptible(10);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1080
1081
1082
1083
  		if (cur_ops->cb_barrier != NULL)
  			cur_ops->cb_barrier();
  		return;
  	}
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1084
  	fullstop = FULLSTOP_RMMOD;
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1085
1086
  	mutex_unlock(&fullstop_mutex);
  	unregister_reboot_notifier(&rcutorture_nb);
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1087
1088
1089
1090
1091
  	if (stutter_task) {
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
  		kthread_stop(stutter_task);
  	}
  	stutter_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
1092
  	if (shuffler_task) {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1093
1094
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
  		kthread_stop(shuffler_task);
73d0a4b10   Rusty Russell   cpumask: convert ...
1095
  		free_cpumask_var(shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1096
1097
  	}
  	shuffler_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
1098
  	if (writer_task) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1099
1100
1101
1102
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
  		kthread_stop(writer_task);
  	}
  	writer_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
1103
  	if (reader_tasks) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1104
  		for (i = 0; i < nrealreaders; i++) {
c8e5b1631   Josh Triplett   rcutorture: style...
1105
  			if (reader_tasks[i]) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
  				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...
1116
  	if (fakewriter_tasks) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1117
  		for (i = 0; i < nfakewriters; i++) {
c8e5b1631   Josh Triplett   rcutorture: style...
1118
  			if (fakewriter_tasks[i]) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1119
1120
1121
1122
1123
1124
1125
1126
1127
  				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...
1128
  	if (stats_task) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1129
1130
1131
1132
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
  		kthread_stop(stats_task);
  	}
  	stats_task = NULL;
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1133
1134
1135
1136
1137
  	if (fqs_task) {
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_fqs task");
  		kthread_stop(fqs_task);
  	}
  	fqs_task = NULL;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1138
  	/* Wait for all RCU callbacks to fire.  */
2326974df   Paul E. McKenney   rcu: add call_rcu...
1139
1140
1141
  
  	if (cur_ops->cb_barrier != NULL)
  		cur_ops->cb_barrier();
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1142

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

c8e5b1631   Josh Triplett   rcutorture: style...
1145
  	if (cur_ops->cleanup)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1146
  		cur_ops->cleanup();
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1147
1148
1149
1150
  	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...
1151
  }
6f8bc500a   Josh Triplett   rcutorture: Mark ...
1152
  static int __init
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1153
1154
1155
1156
1157
  rcu_torture_init(void)
  {
  	int i;
  	int cpu;
  	int firsterr = 0;
ade5fb818   Josh Triplett   rcutorture: Remov...
1158
  	static struct rcu_torture_ops *torture_ops[] =
d9a3da069   Paul E. McKenney   rcu: Add expedite...
1159
1160
  		{ &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
  		  &rcu_bh_ops, &rcu_bh_sync_ops,
804bb8370   Paul E. McKenney   rcu: Add synchron...
1161
1162
  		  &srcu_ops, &srcu_expedited_ops,
  		  &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1163

343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1164
  	mutex_lock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1165
  	/* Process args and tell the world that the torturer is on the job. */
ade5fb818   Josh Triplett   rcutorture: Remov...
1166
  	for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1167
  		cur_ops = torture_ops[i];
ade5fb818   Josh Triplett   rcutorture: Remov...
1168
  		if (strcmp(torture_type, cur_ops->name) == 0)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1169
  			break;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1170
  	}
ade5fb818   Josh Triplett   rcutorture: Remov...
1171
  	if (i == ARRAY_SIZE(torture_ops)) {
cf886c44e   Paul E. McKenney   rcu: Improve rcut...
1172
1173
  		printk(KERN_ALERT "rcu-torture: invalid torture type: \"%s\"
  ",
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1174
  		       torture_type);
cf886c44e   Paul E. McKenney   rcu: Improve rcut...
1175
1176
1177
1178
1179
  		printk(KERN_ALERT "rcu-torture types:");
  		for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
  			printk(KERN_ALERT " %s", torture_ops[i]->name);
  		printk(KERN_ALERT "
  ");
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1180
  		mutex_unlock(&fullstop_mutex);
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
1181
  		return -EINVAL;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1182
  	}
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1183
1184
1185
1186
1187
1188
  	if (cur_ops->fqs == NULL && fqs_duration != 0) {
  		printk(KERN_ALERT "rcu-torture: ->fqs NULL and non-zero "
  				  "fqs_duration, fqs disabled.
  ");
  		fqs_duration = 0;
  	}
c8e5b1631   Josh Triplett   rcutorture: style...
1189
  	if (cur_ops->init)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1190
  		cur_ops->init(); /* no "goto unwind" prior to this point!!! */
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1191
1192
1193
1194
  	if (nreaders >= 0)
  		nrealreaders = nreaders;
  	else
  		nrealreaders = 2 * num_online_cpus();
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1195
  	rcu_torture_print_module_parms("Start of test");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1196
  	fullstop = FULLSTOP_DONTSTOP;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1197
1198
1199
1200
  
  	/* Set up the freelist. */
  
  	INIT_LIST_HEAD(&rcu_torture_freelist);
788e770eb   Ahmed S. Darwish   rcutorture: Use A...
1201
  	for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) {
996417d2c   Paul E. McKenney   [PATCH] add succe...
1202
  		rcu_tortures[i].rtort_mbtest = 0;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
  		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...
1214
1215
  	atomic_set(&n_rcu_torture_mberror, 0);
  	atomic_set(&n_rcu_torture_error, 0);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1216
1217
  	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
  		atomic_set(&rcu_torture_wcount[i], 0);
0a9450227   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1218
  	for_each_possible_cpu(cpu) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
  		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 ...
1236
  	fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
1237
  				   GFP_KERNEL);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1238
1239
1240
1241
1242
1243
1244
1245
  	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,
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
1246
  						  "rcu_torture_fakewriter");
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1247
1248
1249
1250
1251
1252
1253
  		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...
1254
  	reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  			       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...
1283
1284
  	if (test_no_idle_hz) {
  		rcu_idle_cpu = num_online_cpus() - 1;
73d0a4b10   Rusty Russell   cpumask: convert ...
1285
1286
1287
1288
1289
1290
  
  		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...
1291
1292
1293
1294
  		/* 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 ...
1295
  			free_cpumask_var(shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1296
1297
1298
1299
1300
1301
  			firsterr = PTR_ERR(shuffler_task);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
  			shuffler_task = NULL;
  			goto unwind;
  		}
  	}
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
  	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;
  		}
  	}
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
  	if (fqs_duration < 0)
  		fqs_duration = 0;
  	if (fqs_duration) {
  		/* Create the stutter thread */
  		fqs_task = kthread_run(rcu_torture_fqs, NULL,
  				       "rcu_torture_fqs");
  		if (IS_ERR(fqs_task)) {
  			firsterr = PTR_ERR(fqs_task);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create fqs");
  			fqs_task = NULL;
  			goto unwind;
  		}
  	}
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1328
1329
  	register_reboot_notifier(&rcutorture_nb);
  	mutex_unlock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1330
1331
1332
  	return 0;
  
  unwind:
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1333
  	mutex_unlock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1334
1335
1336
1337
1338
1339
  	rcu_torture_cleanup();
  	return firsterr;
  }
  
  module_init(rcu_torture_init);
  module_exit(rcu_torture_cleanup);