Blame view

kernel/rcutorture.c 52 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
   *
   * 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>
60063497a   Arun Sharma   atomic: use <linu...
36
  #include <linux/atomic.h>
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
37
  #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). */
d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
64
65
  static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
  static int fqs_holdoff;		/* Hold time within burst (us). */
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
66
  static int fqs_stutter = 3;	/* Wait time between bursts (s). */
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
67
  static int onoff_interval;	/* Wait time between CPU hotplugs, 0=disable. */
d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
68
  static int shutdown_secs;	/* Shutdown time (s).  <=0 for no shutdown. */
8e8be45e8   Paul E. McKenney   rcu: add priority...
69
70
71
  static int test_boost = 1;	/* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */
  static int test_boost_interval = 7; /* Interval between boost tests, seconds. */
  static int test_boost_duration = 4; /* Duration of each boost test, seconds. */
20d2e4283   Josh Triplett   [PATCH] rcu: add ...
72
  static char *torture_type = "rcu"; /* What RCU implementation to torture. */
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
73

d6ad67112   Josh Triplett   [PATCH] Publish r...
74
  module_param(nreaders, int, 0444);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
75
  MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
d6ad67112   Josh Triplett   [PATCH] Publish r...
76
  module_param(nfakewriters, int, 0444);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
77
  MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
3721bc1d3   Paul E. McKenney   rcu: Allow rcutor...
78
  module_param(stat_interval, int, 0644);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
79
  MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
d6ad67112   Josh Triplett   [PATCH] Publish r...
80
  module_param(verbose, bool, 0444);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
81
  MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
d6ad67112   Josh Triplett   [PATCH] Publish r...
82
  module_param(test_no_idle_hz, bool, 0444);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
83
  MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
d6ad67112   Josh Triplett   [PATCH] Publish r...
84
  module_param(shuffle_interval, int, 0444);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
85
  MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
d120f65f3   Paul E. McKenney   rcu: make rcutort...
86
87
  module_param(stutter, int, 0444);
  MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
88
89
  module_param(irqreader, int, 0444);
  MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
90
91
92
93
94
95
  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)");
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
96
97
  module_param(onoff_interval, int, 0444);
  MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
98
99
  module_param(shutdown_secs, int, 0444);
  MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable.");
8e8be45e8   Paul E. McKenney   rcu: add priority...
100
101
102
103
104
105
  module_param(test_boost, int, 0444);
  MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
  module_param(test_boost_interval, int, 0444);
  MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
  module_param(test_boost_duration, int, 0444);
  MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds.");
d6ad67112   Josh Triplett   [PATCH] Publish r...
106
  module_param(torture_type, charp, 0444);
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
107
  MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
108
109
  
  #define TORTURE_FLAG "-torture:"
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
110
  #define PRINTK_STRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
111
112
  	do { printk(KERN_ALERT "%s" TORTURE_FLAG s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
113
  #define VERBOSE_PRINTK_STRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
114
115
  	do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
116
  #define VERBOSE_PRINTK_ERRSTRING(s) \
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
117
118
  	do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "
  ", torture_type); } while (0)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
119
120
121
122
123
  
  static char printk_buf[4096];
  
  static int nrealreaders;
  static struct task_struct *writer_task;
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
124
  static struct task_struct **fakewriter_tasks;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
125
126
  static struct task_struct **reader_tasks;
  static struct task_struct *stats_task;
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
127
  static struct task_struct *shuffler_task;
d120f65f3   Paul E. McKenney   rcu: make rcutort...
128
  static struct task_struct *stutter_task;
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
129
  static struct task_struct *fqs_task;
8e8be45e8   Paul E. McKenney   rcu: add priority...
130
  static struct task_struct *boost_tasks[NR_CPUS];
d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
131
  static struct task_struct *shutdown_task;
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
132
133
134
  #ifdef CONFIG_HOTPLUG_CPU
  static struct task_struct *onoff_task;
  #endif /* #ifdef CONFIG_HOTPLUG_CPU */
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
135
136
137
138
139
140
141
  
  #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...
142
  	int rtort_mbtest;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
143
  };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
144
  static LIST_HEAD(rcu_torture_freelist);
0ddea0ead   Paul E. McKenney   rcu: fix sparse e...
145
  static struct rcu_torture __rcu *rcu_torture_current;
4a2986568   Paul E. McKenney   rcu: make rcutort...
146
  static unsigned long rcu_torture_current_version;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
147
148
149
150
151
152
153
  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...
154
155
156
157
158
  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;
8e8be45e8   Paul E. McKenney   rcu: add priority...
159
160
  static long n_rcu_torture_boost_ktrerror;
  static long n_rcu_torture_boost_rterror;
8e8be45e8   Paul E. McKenney   rcu: add priority...
161
162
  static long n_rcu_torture_boost_failure;
  static long n_rcu_torture_boosts;
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
163
  static long n_rcu_torture_timers;
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
164
165
166
167
  static long n_offline_attempts;
  static long n_offline_successes;
  static long n_online_attempts;
  static long n_online_successes;
e30337365   Josh Triplett   [PATCH] rcu: refa...
168
  static struct list_head rcu_torture_removed;
73d0a4b10   Rusty Russell   cpumask: convert ...
169
  static cpumask_var_t shuffle_tmp_mask;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
170

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

31a72bce0   Paul E. McKenney   rcu: make rcutort...
173
174
175
176
177
178
  #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;
bb3bf7052   Paul E. McKenney   rcu: Control rcut...
179
180
  module_param(rcutorture_runnable, int, 0444);
  MODULE_PARM_DESC(rcutorture_runnable, "Start rcutorture at boot");
31a72bce0   Paul E. McKenney   rcu: make rcutort...
181

3acf4a9a3   Paul E. McKenney   rcu: avoid hammer...
182
  #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU)
8e8be45e8   Paul E. McKenney   rcu: add priority...
183
  #define rcu_can_boost() 1
3acf4a9a3   Paul E. McKenney   rcu: avoid hammer...
184
  #else /* #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
8e8be45e8   Paul E. McKenney   rcu: add priority...
185
  #define rcu_can_boost() 0
3acf4a9a3   Paul E. McKenney   rcu: avoid hammer...
186
  #endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
8e8be45e8   Paul E. McKenney   rcu: add priority...
187

d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
188
  static unsigned long shutdown_time;	/* jiffies to system shutdown. */
8e8be45e8   Paul E. McKenney   rcu: add priority...
189
190
191
  static unsigned long boost_starttime;	/* jiffies of next boost test start. */
  DEFINE_MUTEX(boost_mutex);		/* protect setting boost_starttime */
  					/*  and boost task create/destroy. */
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
192
193
194
195
196
197
  /* 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;
0ddea0ead   Paul E. McKenney   rcu: fix sparse e...
198
199
200
201
  /*
   * Protect fullstop transitions and spawning of kthreads.
   */
  static DEFINE_MUTEX(fullstop_mutex);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
202

d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
203
204
  /* Forward reference. */
  static void rcu_torture_cleanup(void);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
205
  /*
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
206
   * Detect and respond to a system shutdown.
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
207
208
209
210
211
   */
  static int
  rcutorture_shutdown_notify(struct notifier_block *unused1,
  			   unsigned long unused2, void *unused3)
  {
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
212
  	mutex_lock(&fullstop_mutex);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
213
  	if (fullstop == FULLSTOP_DONTSTOP)
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
214
  		fullstop = FULLSTOP_SHUTDOWN;
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
215
216
217
218
  	else
  		printk(KERN_WARNING /* but going down anyway, so... */
  		       "Concurrent 'rmmod rcutorture' and shutdown illegal!
  ");
c59ab97e9   Paul E. McKenney   rcu: fix rcutortu...
219
  	mutex_unlock(&fullstop_mutex);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
220
221
  	return NOTIFY_DONE;
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
222
  /*
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
   * 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...
238
239
   * Allocate an element from the rcu_tortures pool.
   */
97a41e261   Adrian Bunk   [PATCH] kernel/: ...
240
  static struct rcu_torture *
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
241
242
243
  rcu_torture_alloc(void)
  {
  	struct list_head *p;
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
244
  	spin_lock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
245
246
  	if (list_empty(&rcu_torture_freelist)) {
  		atomic_inc(&n_rcu_torture_alloc_fail);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
247
  		spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
248
249
250
251
252
  		return NULL;
  	}
  	atomic_inc(&n_rcu_torture_alloc);
  	p = rcu_torture_freelist.next;
  	list_del_init(p);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
253
  	spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
254
255
256
257
258
259
260
261
262
263
  	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...
264
  	spin_lock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
265
  	list_add_tail(&p->rtort_free, &rcu_torture_freelist);
adac16652   Ingo Molnar   [PATCH] rcu_tortu...
266
  	spin_unlock_bh(&rcu_torture_lock);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
267
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
268
269
  struct rcu_random_state {
  	unsigned long rrs_state;
75cfef32f   Josh Triplett   [PATCH] rcu: Fix ...
270
  	long rrs_count;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
271
272
273
274
275
276
277
278
279
280
  };
  
  #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...
281
   * generator, with occasional help from cpu_clock().
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
282
   */
75cfef32f   Josh Triplett   [PATCH] rcu: Fix ...
283
  static unsigned long
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
284
285
  rcu_random(struct rcu_random_state *rrsp)
  {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
286
  	if (--rrsp->rrs_count < 0) {
c676329ab   Peter Zijlstra   sched_clock: Add ...
287
  		rrsp->rrs_state += (unsigned long)local_clock();
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
288
289
290
291
292
  		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...
293
  static void
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
294
  rcu_stutter_wait(char *title)
d120f65f3   Paul E. McKenney   rcu: make rcutort...
295
  {
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
296
  	while (stutter_pause_test || !rcutorture_runnable) {
e3d7be270   Paul E. McKenney   rcu, rcutorture: ...
297
298
299
  		if (rcutorture_runnable)
  			schedule_timeout_interruptible(1);
  		else
3ccf79f45   Paul E. McKenney   rcu: make quiesce...
300
  			schedule_timeout_interruptible(round_jiffies_relative(HZ));
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
301
  		rcutorture_shutdown_absorb(title);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
302
  	}
d120f65f3   Paul E. McKenney   rcu: make rcutort...
303
  }
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
304
  /*
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
305
306
307
308
309
310
311
   * 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...
312
  	void (*read_delay)(struct rcu_random_state *rrsp);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
313
314
  	void (*readunlock)(int idx);
  	int (*completed)(void);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
315
  	void (*deferred_free)(struct rcu_torture *p);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
316
  	void (*sync)(void);
2326974df   Paul E. McKenney   rcu: add call_rcu...
317
  	void (*cb_barrier)(void);
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
318
  	void (*fqs)(void);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
319
  	int (*stats)(char *page);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
320
  	int irq_capable;
8e8be45e8   Paul E. McKenney   rcu: add priority...
321
  	int can_boost;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
322
323
  	char *name;
  };
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
324
325
  
  static struct rcu_torture_ops *cur_ops;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
326
327
328
329
  
  /*
   * Definitions for rcu torture testing.
   */
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
330
  static int rcu_torture_read_lock(void) __acquires(RCU)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
331
332
333
334
  {
  	rcu_read_lock();
  	return 0;
  }
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
335
336
  static void rcu_read_delay(struct rcu_random_state *rrsp)
  {
b8d57a76d   Josh Triplett   rcutorture: Occas...
337
338
  	const unsigned long shortdelay_us = 200;
  	const unsigned long longdelay_ms = 50;
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
339

b8d57a76d   Josh Triplett   rcutorture: Occas...
340
341
342
  	/* 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...
343

b8d57a76d   Josh Triplett   rcutorture: Occas...
344
345
346
347
  	if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
  		mdelay(longdelay_ms);
  	if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
  		udelay(shortdelay_us);
e546f485e   Lai Jiangshan   rcutorture: add r...
348
349
350
351
  #ifdef CONFIG_PREEMPT
  	if (!preempt_count() && !(rcu_random(rrsp) % (nrealreaders * 20000)))
  		preempt_schedule();  /* No QS if preempt_disable() in effect */
  #endif
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
352
  }
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
353
  static void rcu_torture_read_unlock(int idx) __releases(RCU)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
  {
  	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...
368
  	if (fullstop != FULLSTOP_DONTSTOP) {
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
369
370
371
372
373
374
375
376
377
378
379
380
  		/* 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...
381
  		cur_ops->deferred_free(rp);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
382
  }
d9a3da069   Paul E. McKenney   rcu: Add expedite...
383
384
385
386
  static int rcu_no_completed(void)
  {
  	return 0;
  }
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
387
388
389
390
391
392
  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...
393
394
395
396
397
398
399
400
401
  	.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...
402
  	.fqs		= rcu_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
403
  	.stats		= NULL,
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
404
  	.irq_capable	= 1,
8e8be45e8   Paul E. McKenney   rcu: add priority...
405
  	.can_boost	= rcu_can_boost(),
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
406
  	.name		= "rcu"
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
407
  };
e30337365   Josh Triplett   [PATCH] rcu: refa...
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  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 ...
433
  static struct rcu_torture_ops rcu_sync_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
434
435
436
437
438
439
440
441
442
  	.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...
443
  	.fqs		= rcu_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
444
445
  	.stats		= NULL,
  	.irq_capable	= 1,
8e8be45e8   Paul E. McKenney   rcu: add priority...
446
  	.can_boost	= rcu_can_boost(),
0acc512cb   Paul E. McKenney   rcu: Add synchron...
447
  	.name		= "rcu_sync"
20d2e4283   Josh Triplett   [PATCH] rcu: add ...
448
  };
d9a3da069   Paul E. McKenney   rcu: Add expedite...
449
450
451
452
453
454
455
456
457
458
  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...
459
  	.fqs		= rcu_force_quiescent_state,
d9a3da069   Paul E. McKenney   rcu: Add expedite...
460
461
  	.stats		= NULL,
  	.irq_capable	= 1,
8e8be45e8   Paul E. McKenney   rcu: add priority...
462
  	.can_boost	= rcu_can_boost(),
d9a3da069   Paul E. McKenney   rcu: Add expedite...
463
464
  	.name		= "rcu_expedited"
  };
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
465
466
467
  /*
   * Definitions for rcu_bh torture testing.
   */
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
468
  static int rcu_bh_torture_read_lock(void) __acquires(RCU_BH)
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
469
470
471
472
  {
  	rcu_read_lock_bh();
  	return 0;
  }
a49a4af75   Josh Triplett   [PATCH] rcu: add ...
473
  static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH)
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
  {
  	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);
  }
  
  static struct rcu_torture_ops rcu_bh_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
489
490
491
492
493
494
495
  	.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,
bdf2a4364   Paul E. McKenney   rcu: Catch rcutor...
496
  	.sync		= synchronize_rcu_bh,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
497
  	.cb_barrier	= rcu_barrier_bh,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
498
  	.fqs		= rcu_bh_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
499
500
501
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "rcu_bh"
c32e06605   Paul E. McKenney   [PATCH] rcutortur...
502
  };
11a147013   Josh Triplett   [PATCH] rcu: add ...
503
  static struct rcu_torture_ops rcu_bh_sync_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
504
505
506
507
508
509
510
  	.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,
bdf2a4364   Paul E. McKenney   rcu: Catch rcutor...
511
  	.sync		= synchronize_rcu_bh,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
512
  	.cb_barrier	= NULL,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
513
  	.fqs		= rcu_bh_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
514
515
516
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "rcu_bh_sync"
11a147013   Josh Triplett   [PATCH] rcu: add ...
517
  };
bdf2a4364   Paul E. McKenney   rcu: Catch rcutor...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  static struct rcu_torture_ops rcu_bh_expedited_ops = {
  	.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		= synchronize_rcu_bh_expedited,
  	.cb_barrier	= NULL,
  	.fqs		= rcu_bh_force_quiescent_state,
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "rcu_bh_expedited"
  };
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
533
534
535
536
537
  /*
   * Definitions for srcu torture testing.
   */
  
  static struct srcu_struct srcu_ctl;
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
538
539
540
541
  
  static void srcu_torture_init(void)
  {
  	init_srcu_struct(&srcu_ctl);
e30337365   Josh Triplett   [PATCH] rcu: refa...
542
  	rcu_sync_torture_init();
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
543
544
545
546
547
548
549
  }
  
  static void srcu_torture_cleanup(void)
  {
  	synchronize_srcu(&srcu_ctl);
  	cleanup_srcu_struct(&srcu_ctl);
  }
012d3ca8d   Josh Triplett   [PATCH] Add Spars...
550
  static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  {
  	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);
e546f485e   Lai Jiangshan   rcutorture: add r...
566
567
  	else
  		rcu_read_delay(rrsp);
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
568
  }
012d3ca8d   Josh Triplett   [PATCH] Add Spars...
569
  static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl)
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
570
571
572
573
574
575
576
577
  {
  	srcu_read_unlock(&srcu_ctl, idx);
  }
  
  static int srcu_torture_completed(void)
  {
  	return srcu_batches_completed(&srcu_ctl);
  }
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
578
579
580
581
  static void srcu_torture_synchronize(void)
  {
  	synchronize_srcu(&srcu_ctl);
  }
b2896d2e7   Paul E. McKenney   [PATCH] srcu-3: a...
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
  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...
601
602
603
604
605
606
607
608
609
610
611
  	.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...
612
  };
101db7b41   Paul E. McKenney   rcu: Add rcutortu...
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
  static int srcu_torture_read_lock_raw(void) __acquires(&srcu_ctl)
  {
  	return srcu_read_lock_raw(&srcu_ctl);
  }
  
  static void srcu_torture_read_unlock_raw(int idx) __releases(&srcu_ctl)
  {
  	srcu_read_unlock_raw(&srcu_ctl, idx);
  }
  
  static struct rcu_torture_ops srcu_raw_ops = {
  	.init		= srcu_torture_init,
  	.cleanup	= srcu_torture_cleanup,
  	.readlock	= srcu_torture_read_lock_raw,
  	.read_delay	= srcu_read_delay,
  	.readunlock	= srcu_torture_read_unlock_raw,
  	.completed	= srcu_torture_completed,
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= srcu_torture_synchronize,
  	.cb_barrier	= NULL,
  	.stats		= srcu_torture_stats,
  	.name		= "srcu_raw"
  };
804bb8370   Paul E. McKenney   rcu: Add synchron...
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
  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 ...
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  /*
   * 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...
668
669
670
671
  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 ...
672
  static struct rcu_torture_ops sched_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
673
674
675
676
677
  	.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...
678
  	.completed	= rcu_no_completed,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
679
  	.deferred_free	= rcu_sched_torture_deferred_free,
bdf2a4364   Paul E. McKenney   rcu: Catch rcutor...
680
  	.sync		= synchronize_sched,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
681
  	.cb_barrier	= rcu_barrier_sched,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
682
  	.fqs		= rcu_sched_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
683
684
685
  	.stats		= NULL,
  	.irq_capable	= 1,
  	.name		= "sched"
4b6c2cca6   Josh Triplett   [PATCH] rcu: add ...
686
  };
804bb8370   Paul E. McKenney   rcu: Add synchron...
687
  static struct rcu_torture_ops sched_sync_ops = {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
688
689
690
691
692
  	.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...
693
  	.completed	= rcu_no_completed,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
694
  	.deferred_free	= rcu_sync_torture_deferred_free,
bdf2a4364   Paul E. McKenney   rcu: Catch rcutor...
695
  	.sync		= synchronize_sched,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
696
  	.cb_barrier	= NULL,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
697
  	.fqs		= rcu_sched_force_quiescent_state,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
698
699
700
  	.stats		= NULL,
  	.name		= "sched_sync"
  };
0acc512cb   Paul E. McKenney   rcu: Add synchron...
701
702
703
704
705
706
  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...
707
  	.completed	= rcu_no_completed,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
708
709
710
  	.deferred_free	= rcu_sync_torture_deferred_free,
  	.sync		= synchronize_sched_expedited,
  	.cb_barrier	= NULL,
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
711
  	.fqs		= rcu_sched_force_quiescent_state,
969c79215   Tejun Heo   sched: replace mi...
712
  	.stats		= NULL,
0acc512cb   Paul E. McKenney   rcu: Add synchron...
713
714
  	.irq_capable	= 1,
  	.name		= "sched_expedited"
2326974df   Paul E. McKenney   rcu: add call_rcu...
715
  };
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
716
  /*
8e8be45e8   Paul E. McKenney   rcu: add priority...
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
   * RCU torture priority-boost testing.  Runs one real-time thread per
   * CPU for moderate bursts, repeatedly registering RCU callbacks and
   * spinning waiting for them to be invoked.  If a given callback takes
   * too long to be invoked, we assume that priority inversion has occurred.
   */
  
  struct rcu_boost_inflight {
  	struct rcu_head rcu;
  	int inflight;
  };
  
  static void rcu_torture_boost_cb(struct rcu_head *head)
  {
  	struct rcu_boost_inflight *rbip =
  		container_of(head, struct rcu_boost_inflight, rcu);
  
  	smp_mb(); /* Ensure RCU-core accesses precede clearing ->inflight */
  	rbip->inflight = 0;
  }
  
  static int rcu_torture_boost(void *arg)
  {
  	unsigned long call_rcu_time;
  	unsigned long endtime;
  	unsigned long oldstarttime;
  	struct rcu_boost_inflight rbi = { .inflight = 0 };
  	struct sched_param sp;
  
  	VERBOSE_PRINTK_STRING("rcu_torture_boost started");
  
  	/* Set real-time priority. */
  	sp.sched_priority = 1;
  	if (sched_setscheduler(current, SCHED_FIFO, &sp) < 0) {
  		VERBOSE_PRINTK_STRING("rcu_torture_boost RT prio failed!");
  		n_rcu_torture_boost_rterror++;
  	}
561190e3b   Paul E. McKenney   rcu: mark rcutort...
753
  	init_rcu_head_on_stack(&rbi.rcu);
8e8be45e8   Paul E. McKenney   rcu: add priority...
754
755
756
757
  	/* Each pass through the following loop does one boost-test cycle. */
  	do {
  		/* Wait for the next test interval. */
  		oldstarttime = boost_starttime;
93898fb1a   Paul E. McKenney   rcu: Make rcu_tor...
758
  		while (ULONG_CMP_LT(jiffies, oldstarttime)) {
8e8be45e8   Paul E. McKenney   rcu: add priority...
759
760
761
762
763
764
765
766
767
768
  			schedule_timeout_uninterruptible(1);
  			rcu_stutter_wait("rcu_torture_boost");
  			if (kthread_should_stop() ||
  			    fullstop != FULLSTOP_DONTSTOP)
  				goto checkwait;
  		}
  
  		/* Do one boost-test interval. */
  		endtime = oldstarttime + test_boost_duration * HZ;
  		call_rcu_time = jiffies;
93898fb1a   Paul E. McKenney   rcu: Make rcu_tor...
769
  		while (ULONG_CMP_LT(jiffies, endtime)) {
8e8be45e8   Paul E. McKenney   rcu: add priority...
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
  			/* If we don't have a callback in flight, post one. */
  			if (!rbi.inflight) {
  				smp_mb(); /* RCU core before ->inflight = 1. */
  				rbi.inflight = 1;
  				call_rcu(&rbi.rcu, rcu_torture_boost_cb);
  				if (jiffies - call_rcu_time >
  					 test_boost_duration * HZ - HZ / 2) {
  					VERBOSE_PRINTK_STRING("rcu_torture_boost boosting failed");
  					n_rcu_torture_boost_failure++;
  				}
  				call_rcu_time = jiffies;
  			}
  			cond_resched();
  			rcu_stutter_wait("rcu_torture_boost");
  			if (kthread_should_stop() ||
  			    fullstop != FULLSTOP_DONTSTOP)
  				goto checkwait;
  		}
  
  		/*
  		 * Set the start time of the next test interval.
  		 * Yes, this is vulnerable to long delays, but such
  		 * delays simply cause a false negative for the next
  		 * interval.  Besides, we are running at RT priority,
  		 * so delays should be relatively rare.
  		 */
ab8f11e5f   Paul E. McKenney   rcu: Make rcu_tor...
796
797
  		while (oldstarttime == boost_starttime &&
  		       !kthread_should_stop()) {
8e8be45e8   Paul E. McKenney   rcu: add priority...
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
  			if (mutex_trylock(&boost_mutex)) {
  				boost_starttime = jiffies +
  						  test_boost_interval * HZ;
  				n_rcu_torture_boosts++;
  				mutex_unlock(&boost_mutex);
  				break;
  			}
  			schedule_timeout_uninterruptible(1);
  		}
  
  		/* Go do the stutter. */
  checkwait:	rcu_stutter_wait("rcu_torture_boost");
  	} while (!kthread_should_stop() && fullstop  == FULLSTOP_DONTSTOP);
  
  	/* Clean up and exit. */
  	VERBOSE_PRINTK_STRING("rcu_torture_boost task stopping");
  	rcutorture_shutdown_absorb("rcu_torture_boost");
  	while (!kthread_should_stop() || rbi.inflight)
  		schedule_timeout_uninterruptible(1);
  	smp_mb(); /* order accesses to ->inflight before stack-frame death. */
9d68197c0   Paul E. McKenney   rcu: Don't destro...
818
  	destroy_rcu_head_on_stack(&rbi.rcu);
8e8be45e8   Paul E. McKenney   rcu: add priority...
819
820
821
822
  	return 0;
  }
  
  /*
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
823
824
825
826
827
828
829
830
831
832
833
834
835
   * 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;
93898fb1a   Paul E. McKenney   rcu: Make rcu_tor...
836
837
  		while (ULONG_CMP_LT(jiffies, fqs_resume_time) &&
  		       !kthread_should_stop()) {
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
838
839
840
  			schedule_timeout_interruptible(1);
  		}
  		fqs_burst_remaining = fqs_duration;
93898fb1a   Paul E. McKenney   rcu: Make rcu_tor...
841
842
  		while (fqs_burst_remaining > 0 &&
  		       !kthread_should_stop()) {
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  			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...
857
858
859
860
861
862
863
864
865
866
867
868
869
870
   * 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...
871
  	set_user_nice(current, 19);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
872
873
  	do {
  		schedule_timeout_uninterruptible(1);
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
874
875
  		rp = rcu_torture_alloc();
  		if (rp == NULL)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
876
877
878
  			continue;
  		rp->rtort_pipe_count = 0;
  		udelay(rcu_random(&rand) & 0x3ff);
0ddea0ead   Paul E. McKenney   rcu: fix sparse e...
879
880
  		old_rp = rcu_dereference_check(rcu_torture_current,
  					       current == writer_task);
996417d2c   Paul E. McKenney   [PATCH] add succe...
881
  		rp->rtort_mbtest = 1;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
882
  		rcu_assign_pointer(rcu_torture_current, rp);
9b2619aff   Paul E. McKenney   rcu: Clean up cod...
883
  		smp_wmb(); /* Mods to old_rp must follow rcu_assign_pointer() */
c8e5b1631   Josh Triplett   rcutorture: style...
884
  		if (old_rp) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
885
886
887
888
889
  			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...
890
  			cur_ops->deferred_free(old_rp);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
891
  		}
4a2986568   Paul E. McKenney   rcu: make rcutort...
892
  		rcutorture_record_progress(++rcu_torture_current_version);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
893
  		oldbatch = cur_ops->completed();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
894
895
  		rcu_stutter_wait("rcu_torture_writer");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
896
  	VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
897
898
  	rcutorture_shutdown_absorb("rcu_torture_writer");
  	while (!kthread_should_stop())
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
899
900
901
902
903
  		schedule_timeout_uninterruptible(1);
  	return 0;
  }
  
  /*
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
   * 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...
919
920
  		rcu_stutter_wait("rcu_torture_fakewriter");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
921
922
  
  	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
923
924
  	rcutorture_shutdown_absorb("rcu_torture_fakewriter");
  	while (!kthread_should_stop())
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
925
926
927
  		schedule_timeout_uninterruptible(1);
  	return 0;
  }
91afaf300   Paul E. McKenney   rcu: Add failure ...
928
929
930
931
932
933
934
935
936
937
938
  void rcutorture_trace_dump(void)
  {
  	static atomic_t beenhere = ATOMIC_INIT(0);
  
  	if (atomic_read(&beenhere))
  		return;
  	if (atomic_xchg(&beenhere, 1) != 0)
  		return;
  	do_trace_rcu_torture_read(cur_ops->name, (struct rcu_head *)~0UL);
  	ftrace_dump(DUMP_ALL);
  }
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
939
  /*
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
   * 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...
956
  	p = rcu_dereference_check(rcu_torture_current,
632ee2001   Paul E. McKenney   rcu: Introduce lo...
957
958
959
  				  rcu_read_lock_bh_held() ||
  				  rcu_read_lock_sched_held() ||
  				  srcu_read_lock_held(&srcu_ctl));
91afaf300   Paul E. McKenney   rcu: Add failure ...
960
  	do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
961
962
963
964
965
966
967
968
  	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...
969
  	cur_ops->read_delay(&rand);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
970
971
972
973
974
975
976
977
  	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;
  	}
91afaf300   Paul E. McKenney   rcu: Add failure ...
978
979
  	if (pipe_count > 1)
  		rcutorture_trace_dump();
dd17c8f72   Rusty Russell   percpu: remove pe...
980
  	__this_cpu_inc(rcu_torture_count[pipe_count]);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
981
982
983
984
985
  	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...
986
  	__this_cpu_inc(rcu_torture_batch[completed]);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
987
988
989
990
991
  	preempt_enable();
  	cur_ops->readunlock(idx);
  }
  
  /*
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
992
993
994
995
996
997
998
999
1000
   * 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...
1001
  	int idx;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1002
1003
1004
  	DEFINE_RCU_RANDOM(rand);
  	struct rcu_torture *p;
  	int pipe_count;
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
1005
  	struct timer_list t;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1006
1007
  
  	VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
dbdf65b1b   Ingo Molnar   [PATCH] rcutortur...
1008
  	set_user_nice(current, 19);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
1009
  	if (irqreader && cur_ops->irq_capable)
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
1010
  		setup_timer_on_stack(&t, rcu_torture_timer, 0);
dbdf65b1b   Ingo Molnar   [PATCH] rcutortur...
1011

a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1012
  	do {
0acc512cb   Paul E. McKenney   rcu: Add synchron...
1013
  		if (irqreader && cur_ops->irq_capable) {
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
1014
  			if (!timer_pending(&t))
6155fec92   Paul E. McKenney   rcu: Fix rcutortu...
1015
  				mod_timer(&t, jiffies + 1);
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
1016
  		}
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1017
1018
  		idx = cur_ops->readlock();
  		completed = cur_ops->completed();
632ee2001   Paul E. McKenney   rcu: Introduce lo...
1019
  		p = rcu_dereference_check(rcu_torture_current,
632ee2001   Paul E. McKenney   rcu: Introduce lo...
1020
1021
1022
  					  rcu_read_lock_bh_held() ||
  					  rcu_read_lock_sched_held() ||
  					  srcu_read_lock_held(&srcu_ctl));
91afaf300   Paul E. McKenney   rcu: Add failure ...
1023
  		do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1024
1025
  		if (p == NULL) {
  			/* Wait for rcu_torture_writer to get underway */
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1026
  			cur_ops->readunlock(idx);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1027
1028
1029
  			schedule_timeout_interruptible(HZ);
  			continue;
  		}
996417d2c   Paul E. McKenney   [PATCH] add succe...
1030
1031
  		if (p->rtort_mbtest == 0)
  			atomic_inc(&n_rcu_torture_mberror);
0acc512cb   Paul E. McKenney   rcu: Add synchron...
1032
  		cur_ops->read_delay(&rand);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1033
1034
1035
1036
1037
1038
  		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;
  		}
91afaf300   Paul E. McKenney   rcu: Add failure ...
1039
1040
  		if (pipe_count > 1)
  			rcutorture_trace_dump();
dd17c8f72   Rusty Russell   percpu: remove pe...
1041
  		__this_cpu_inc(rcu_torture_count[pipe_count]);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1042
  		completed = cur_ops->completed() - completed;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1043
1044
1045
1046
  		if (completed > RCU_TORTURE_PIPE_LEN) {
  			/* Should not happen, but... */
  			completed = RCU_TORTURE_PIPE_LEN;
  		}
dd17c8f72   Rusty Russell   percpu: remove pe...
1047
  		__this_cpu_inc(rcu_torture_batch[completed]);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1048
  		preempt_enable();
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1049
  		cur_ops->readunlock(idx);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1050
  		schedule();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1051
1052
  		rcu_stutter_wait("rcu_torture_reader");
  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1053
  	VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1054
  	rcutorture_shutdown_absorb("rcu_torture_reader");
0acc512cb   Paul E. McKenney   rcu: Add synchron...
1055
  	if (irqreader && cur_ops->irq_capable)
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
1056
  		del_timer_sync(&t);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1057
  	while (!kthread_should_stop())
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
  		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_...
1073
  	for_each_possible_cpu(cpu) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1074
1075
1076
1077
1078
1079
1080
1081
1082
  		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...
1083
  	cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1084
  	cnt += sprintf(&page[cnt],
4a2986568   Paul E. McKenney   rcu: make rcutort...
1085
  		       "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d "
67b98dba4   Paul E. McKenney   rcu: eliminate un...
1086
  		       "rtmbe: %d rtbke: %ld rtbre: %ld "
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1087
1088
  		       "rtbf: %ld rtb: %ld nt: %ld "
  		       "onoff: %ld/%ld:%ld/%ld",
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1089
1090
1091
1092
1093
  		       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...
1094
  		       atomic_read(&n_rcu_torture_free),
0729fbf3b   Paul E. McKenney   rcu: make rcutort...
1095
  		       atomic_read(&n_rcu_torture_mberror),
8e8be45e8   Paul E. McKenney   rcu: add priority...
1096
1097
  		       n_rcu_torture_boost_ktrerror,
  		       n_rcu_torture_boost_rterror,
8e8be45e8   Paul E. McKenney   rcu: add priority...
1098
1099
  		       n_rcu_torture_boost_failure,
  		       n_rcu_torture_boosts,
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1100
1101
1102
1103
1104
  		       n_rcu_torture_timers,
  		       n_online_successes,
  		       n_online_attempts,
  		       n_offline_successes,
  		       n_offline_attempts);
8e8be45e8   Paul E. McKenney   rcu: add priority...
1105
1106
1107
  	if (atomic_read(&n_rcu_torture_mberror) != 0 ||
  	    n_rcu_torture_boost_ktrerror != 0 ||
  	    n_rcu_torture_boost_rterror != 0 ||
8e8be45e8   Paul E. McKenney   rcu: add priority...
1108
  	    n_rcu_torture_boost_failure != 0)
996417d2c   Paul E. McKenney   [PATCH] add succe...
1109
  		cnt += sprintf(&page[cnt], " !!!");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1110
1111
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
996417d2c   Paul E. McKenney   [PATCH] add succe...
1112
  	if (i > 1) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1113
  		cnt += sprintf(&page[cnt], "!!! ");
996417d2c   Paul E. McKenney   [PATCH] add succe...
1114
  		atomic_inc(&n_rcu_torture_error);
5af970a48   Ingo Molnar   rcutorture: WARN_...
1115
  		WARN_ON_ONCE(1);
996417d2c   Paul E. McKenney   [PATCH] add succe...
1116
  	}
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1117
1118
1119
  	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...
1120
1121
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1122
  	cnt += sprintf(&page[cnt], "Reader Batch: ");
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1123
  	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1124
  		cnt += sprintf(&page[cnt], " %ld", batchsummary[i]);
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1125
1126
  	cnt += sprintf(&page[cnt], "
  %s%s ", torture_type, TORTURE_FLAG);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1127
1128
1129
1130
1131
1132
1133
  	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...
1134
  	if (cur_ops->stats)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1135
  		cnt += cur_ops->stats(&page[cnt]);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  	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...
1170
1171
  		rcutorture_shutdown_absorb("rcu_torture_stats");
  	} while (!kthread_should_stop());
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1172
1173
1174
  	VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
  	return 0;
  }
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1175
1176
1177
1178
1179
  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...
1180
  static void rcu_torture_shuffle_tasks(void)
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1181
  {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1182
  	int i;
73d0a4b10   Rusty Russell   cpumask: convert ...
1183
  	cpumask_setall(shuffle_tmp_mask);
86ef5c9a8   Gautham R Shenoy   cpu-hotplug: repl...
1184
  	get_online_cpus();
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1185
1186
  
  	/* No point in shuffling if there is only one online CPU (ex: UP) */
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1187
1188
1189
1190
  	if (num_online_cpus() == 1) {
  		put_online_cpus();
  		return;
  	}
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1191
1192
  
  	if (rcu_idle_cpu != -1)
73d0a4b10   Rusty Russell   cpumask: convert ...
1193
  		cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1194

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

c8e5b1631   Josh Triplett   rcutorture: style...
1197
  	if (reader_tasks) {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1198
1199
  		for (i = 0; i < nrealreaders; i++)
  			if (reader_tasks[i])
f70316dac   Mike Travis   generic: use new ...
1200
  				set_cpus_allowed_ptr(reader_tasks[i],
73d0a4b10   Rusty Russell   cpumask: convert ...
1201
  						     shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1202
  	}
c8e5b1631   Josh Triplett   rcutorture: style...
1203
  	if (fakewriter_tasks) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1204
1205
  		for (i = 0; i < nfakewriters; i++)
  			if (fakewriter_tasks[i])
f70316dac   Mike Travis   generic: use new ...
1206
  				set_cpus_allowed_ptr(fakewriter_tasks[i],
73d0a4b10   Rusty Russell   cpumask: convert ...
1207
  						     shuffle_tmp_mask);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1208
  	}
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1209
  	if (writer_task)
73d0a4b10   Rusty Russell   cpumask: convert ...
1210
  		set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1211
1212
  
  	if (stats_task)
73d0a4b10   Rusty Russell   cpumask: convert ...
1213
  		set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1214
1215
1216
1217
1218
  
  	if (rcu_idle_cpu == -1)
  		rcu_idle_cpu = num_online_cpus() - 1;
  	else
  		rcu_idle_cpu--;
86ef5c9a8   Gautham R Shenoy   cpu-hotplug: repl...
1219
  	put_online_cpus();
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
  }
  
  /* 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...
1233
1234
  		rcutorture_shutdown_absorb("rcu_torture_shuffle");
  	} while (!kthread_should_stop());
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1235
1236
1237
  	VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
  	return 0;
  }
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
  /* 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...
1248
  		if (!kthread_should_stop())
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1249
1250
  			schedule_timeout_interruptible(stutter * HZ);
  		stutter_pause_test = 0;
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1251
1252
  		rcutorture_shutdown_absorb("rcu_torture_stutter");
  	} while (!kthread_should_stop());
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1253
1254
1255
  	VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
  	return 0;
  }
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1256
  static inline void
8e8be45e8   Paul E. McKenney   rcu: add priority...
1257
  rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, char *tag)
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1258
  {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1259
1260
  	printk(KERN_ALERT "%s" TORTURE_FLAG
  		"--- %s: nreaders=%d nfakewriters=%d "
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1261
  		"stat_interval=%d verbose=%d test_no_idle_hz=%d "
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1262
  		"shuffle_interval=%d stutter=%d irqreader=%d "
8e8be45e8   Paul E. McKenney   rcu: add priority...
1263
1264
  		"fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
  		"test_boost=%d/%d test_boost_interval=%d "
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1265
1266
1267
  		"test_boost_duration=%d shutdown_secs=%d "
  		"onoff_interval=%d
  ",
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1268
  		torture_type, tag, nrealreaders, nfakewriters,
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1269
  		stat_interval, verbose, test_no_idle_hz, shuffle_interval,
8e8be45e8   Paul E. McKenney   rcu: add priority...
1270
1271
  		stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
  		test_boost, cur_ops->can_boost,
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1272
1273
  		test_boost_interval, test_boost_duration, shutdown_secs,
  		onoff_interval);
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1274
  }
8e8be45e8   Paul E. McKenney   rcu: add priority...
1275
  static struct notifier_block rcutorture_shutdown_nb = {
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1276
1277
  	.notifier_call = rcutorture_shutdown_notify,
  };
8e8be45e8   Paul E. McKenney   rcu: add priority...
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
  static void rcutorture_booster_cleanup(int cpu)
  {
  	struct task_struct *t;
  
  	if (boost_tasks[cpu] == NULL)
  		return;
  	mutex_lock(&boost_mutex);
  	VERBOSE_PRINTK_STRING("Stopping rcu_torture_boost task");
  	t = boost_tasks[cpu];
  	boost_tasks[cpu] = NULL;
  	mutex_unlock(&boost_mutex);
  
  	/* This must be outside of the mutex, otherwise deadlock! */
  	kthread_stop(t);
  }
  
  static int rcutorture_booster_init(int cpu)
  {
  	int retval;
  
  	if (boost_tasks[cpu] != NULL)
  		return 0;  /* Already created, nothing more to do. */
  
  	/* Don't allow time recalculation while creating a new task. */
  	mutex_lock(&boost_mutex);
  	VERBOSE_PRINTK_STRING("Creating rcu_torture_boost task");
1f2880948   Eric Dumazet   rcu: Use kthread_...
1304
1305
1306
  	boost_tasks[cpu] = kthread_create_on_node(rcu_torture_boost, NULL,
  						  cpu_to_node(cpu),
  						  "rcu_torture_boost");
8e8be45e8   Paul E. McKenney   rcu: add priority...
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
  	if (IS_ERR(boost_tasks[cpu])) {
  		retval = PTR_ERR(boost_tasks[cpu]);
  		VERBOSE_PRINTK_STRING("rcu_torture_boost task create failed");
  		n_rcu_torture_boost_ktrerror++;
  		boost_tasks[cpu] = NULL;
  		mutex_unlock(&boost_mutex);
  		return retval;
  	}
  	kthread_bind(boost_tasks[cpu], cpu);
  	wake_up_process(boost_tasks[cpu]);
  	mutex_unlock(&boost_mutex);
  	return 0;
  }
d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
  /*
   * Cause the rcutorture test to shutdown the system after the test has
   * run for the time specified by the shutdown_secs module parameter.
   */
  static int
  rcu_torture_shutdown(void *arg)
  {
  	long delta;
  	unsigned long jiffies_snap;
  
  	VERBOSE_PRINTK_STRING("rcu_torture_shutdown task started");
  	jiffies_snap = ACCESS_ONCE(jiffies);
  	while (ULONG_CMP_LT(jiffies_snap, shutdown_time) &&
  	       !kthread_should_stop()) {
  		delta = shutdown_time - jiffies_snap;
  		if (verbose)
  			printk(KERN_ALERT "%s" TORTURE_FLAG
  			       "rcu_torture_shutdown task: %lu "
  			       "jiffies remaining
  ",
  			       torture_type, delta);
  		schedule_timeout_interruptible(delta);
  		jiffies_snap = ACCESS_ONCE(jiffies);
  	}
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1344
  	if (kthread_should_stop()) {
d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
  		VERBOSE_PRINTK_STRING("rcu_torture_shutdown task stopping");
  		return 0;
  	}
  
  	/* OK, shut down the system. */
  
  	VERBOSE_PRINTK_STRING("rcu_torture_shutdown task shutting down system");
  	shutdown_task = NULL;	/* Avoid self-kill deadlock. */
  	rcu_torture_cleanup();	/* Get the success/failure message. */
  	kernel_power_off();	/* Shut down the system. */
  	return 0;
  }
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
  #ifdef CONFIG_HOTPLUG_CPU
  
  /*
   * Execute random CPU-hotplug operations at the interval specified
   * by the onoff_interval.
   */
  static int
  rcu_torture_onoff(void *arg)
  {
  	int cpu;
  	int maxcpu = -1;
  	DEFINE_RCU_RANDOM(rand);
  
  	VERBOSE_PRINTK_STRING("rcu_torture_onoff task started");
  	for_each_online_cpu(cpu)
  		maxcpu = cpu;
  	WARN_ON(maxcpu < 0);
  	while (!kthread_should_stop()) {
  		cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1);
f220242af   Paul E. McKenney   rcu: Make rcutort...
1376
  		if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
  			if (verbose)
  				printk(KERN_ALERT "%s" TORTURE_FLAG
  				       "rcu_torture_onoff task: offlining %d
  ",
  				       torture_type, cpu);
  			n_offline_attempts++;
  			if (cpu_down(cpu) == 0) {
  				if (verbose)
  					printk(KERN_ALERT "%s" TORTURE_FLAG
  					       "rcu_torture_onoff task: "
  					       "offlined %d
  ",
  					       torture_type, cpu);
  				n_offline_successes++;
  			}
f220242af   Paul E. McKenney   rcu: Make rcutort...
1392
  		} else if (cpu_is_hotpluggable(cpu)) {
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
  			if (verbose)
  				printk(KERN_ALERT "%s" TORTURE_FLAG
  				       "rcu_torture_onoff task: onlining %d
  ",
  				       torture_type, cpu);
  			n_online_attempts++;
  			if (cpu_up(cpu) == 0) {
  				if (verbose)
  					printk(KERN_ALERT "%s" TORTURE_FLAG
  					       "rcu_torture_onoff task: "
  					       "onlined %d
  ",
  					       torture_type, cpu);
  				n_online_successes++;
  			}
  		}
  		schedule_timeout_interruptible(onoff_interval * HZ);
  	}
  	VERBOSE_PRINTK_STRING("rcu_torture_onoff task stopping");
  	return 0;
  }
  
  static int
  rcu_torture_onoff_init(void)
  {
  	if (onoff_interval <= 0)
  		return 0;
  	onoff_task = kthread_run(rcu_torture_onoff, NULL, "rcu_torture_onoff");
  	if (IS_ERR(onoff_task)) {
  		onoff_task = NULL;
  		return PTR_ERR(onoff_task);
  	}
  	return 0;
  }
  
  static void rcu_torture_onoff_cleanup(void)
  {
  	if (onoff_task == NULL)
  		return;
  	VERBOSE_PRINTK_STRING("Stopping rcu_torture_onoff task");
  	kthread_stop(onoff_task);
  }
  
  #else /* #ifdef CONFIG_HOTPLUG_CPU */
  
  static void
  rcu_torture_onoff_init(void)
  {
  }
  
  static void rcu_torture_onoff_cleanup(void)
  {
  }
  
  #endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
8e8be45e8   Paul E. McKenney   rcu: add priority...
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
  static int rcutorture_cpu_notify(struct notifier_block *self,
  				 unsigned long action, void *hcpu)
  {
  	long cpu = (long)hcpu;
  
  	switch (action) {
  	case CPU_ONLINE:
  	case CPU_DOWN_FAILED:
  		(void)rcutorture_booster_init(cpu);
  		break;
  	case CPU_DOWN_PREPARE:
  		rcutorture_booster_cleanup(cpu);
  		break;
  	default:
  		break;
  	}
  	return NOTIFY_OK;
  }
  
  static struct notifier_block rcutorture_cpu_nb = {
  	.notifier_call = rcutorture_cpu_notify,
  };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1470
1471
1472
1473
  static void
  rcu_torture_cleanup(void)
  {
  	int i;
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1474
  	mutex_lock(&fullstop_mutex);
4a2986568   Paul E. McKenney   rcu: make rcutort...
1475
  	rcutorture_record_test_transition();
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1476
1477
1478
1479
  	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...
1480
  		mutex_unlock(&fullstop_mutex);
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1481
  		schedule_timeout_uninterruptible(10);
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1482
1483
1484
1485
  		if (cur_ops->cb_barrier != NULL)
  			cur_ops->cb_barrier();
  		return;
  	}
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1486
  	fullstop = FULLSTOP_RMMOD;
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1487
  	mutex_unlock(&fullstop_mutex);
8e8be45e8   Paul E. McKenney   rcu: add priority...
1488
  	unregister_reboot_notifier(&rcutorture_shutdown_nb);
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1489
1490
1491
1492
1493
  	if (stutter_task) {
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
  		kthread_stop(stutter_task);
  	}
  	stutter_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
1494
  	if (shuffler_task) {
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1495
1496
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
  		kthread_stop(shuffler_task);
73d0a4b10   Rusty Russell   cpumask: convert ...
1497
  		free_cpumask_var(shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1498
1499
  	}
  	shuffler_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
1500
  	if (writer_task) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1501
1502
1503
1504
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
  		kthread_stop(writer_task);
  	}
  	writer_task = NULL;
c8e5b1631   Josh Triplett   rcutorture: style...
1505
  	if (reader_tasks) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1506
  		for (i = 0; i < nrealreaders; i++) {
c8e5b1631   Josh Triplett   rcutorture: style...
1507
  			if (reader_tasks[i]) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
  				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...
1518
  	if (fakewriter_tasks) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1519
  		for (i = 0; i < nfakewriters; i++) {
c8e5b1631   Josh Triplett   rcutorture: style...
1520
  			if (fakewriter_tasks[i]) {
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1521
1522
1523
1524
1525
1526
1527
1528
1529
  				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...
1530
  	if (stats_task) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1531
1532
1533
1534
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
  		kthread_stop(stats_task);
  	}
  	stats_task = NULL;
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1535
1536
1537
1538
1539
  	if (fqs_task) {
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_fqs task");
  		kthread_stop(fqs_task);
  	}
  	fqs_task = NULL;
8e8be45e8   Paul E. McKenney   rcu: add priority...
1540
1541
1542
1543
1544
1545
  	if ((test_boost == 1 && cur_ops->can_boost) ||
  	    test_boost == 2) {
  		unregister_cpu_notifier(&rcutorture_cpu_nb);
  		for_each_possible_cpu(i)
  			rcutorture_booster_cleanup(i);
  	}
d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
1546
1547
1548
1549
  	if (shutdown_task != NULL) {
  		VERBOSE_PRINTK_STRING("Stopping rcu_torture_shutdown task");
  		kthread_stop(shutdown_task);
  	}
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1550
  	rcu_torture_onoff_cleanup();
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1551

a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1552
  	/* Wait for all RCU callbacks to fire.  */
2326974df   Paul E. McKenney   rcu: add call_rcu...
1553
1554
1555
  
  	if (cur_ops->cb_barrier != NULL)
  		cur_ops->cb_barrier();
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1556

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

c8e5b1631   Josh Triplett   rcutorture: style...
1559
  	if (cur_ops->cleanup)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1560
  		cur_ops->cleanup();
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1561
  	if (atomic_read(&n_rcu_torture_error))
8e8be45e8   Paul E. McKenney   rcu: add priority...
1562
  		rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE");
95c383227   Paul E. McKenney   [PATCH] rcutortur...
1563
  	else
8e8be45e8   Paul E. McKenney   rcu: add priority...
1564
  		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1565
  }
6f8bc500a   Josh Triplett   rcutorture: Mark ...
1566
  static int __init
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1567
1568
1569
1570
1571
  rcu_torture_init(void)
  {
  	int i;
  	int cpu;
  	int firsterr = 0;
ade5fb818   Josh Triplett   rcutorture: Remov...
1572
  	static struct rcu_torture_ops *torture_ops[] =
d9a3da069   Paul E. McKenney   rcu: Add expedite...
1573
  		{ &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
bdf2a4364   Paul E. McKenney   rcu: Catch rcutor...
1574
  		  &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops,
101db7b41   Paul E. McKenney   rcu: Add rcutortu...
1575
  		  &srcu_ops, &srcu_raw_ops, &srcu_expedited_ops,
804bb8370   Paul E. McKenney   rcu: Add synchron...
1576
  		  &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1577

343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1578
  	mutex_lock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1579
  	/* Process args and tell the world that the torturer is on the job. */
ade5fb818   Josh Triplett   rcutorture: Remov...
1580
  	for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1581
  		cur_ops = torture_ops[i];
ade5fb818   Josh Triplett   rcutorture: Remov...
1582
  		if (strcmp(torture_type, cur_ops->name) == 0)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1583
  			break;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1584
  	}
ade5fb818   Josh Triplett   rcutorture: Remov...
1585
  	if (i == ARRAY_SIZE(torture_ops)) {
cf886c44e   Paul E. McKenney   rcu: Improve rcut...
1586
1587
  		printk(KERN_ALERT "rcu-torture: invalid torture type: \"%s\"
  ",
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1588
  		       torture_type);
cf886c44e   Paul E. McKenney   rcu: Improve rcut...
1589
1590
1591
1592
1593
  		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...
1594
  		mutex_unlock(&fullstop_mutex);
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
1595
  		return -EINVAL;
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1596
  	}
bf66f18e7   Paul E. McKenney   rcu: Add force_qu...
1597
1598
1599
1600
1601
1602
  	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...
1603
  	if (cur_ops->init)
72e9bb549   Paul E. McKenney   [PATCH] rcutortur...
1604
  		cur_ops->init(); /* no "goto unwind" prior to this point!!! */
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1605
1606
1607
1608
  	if (nreaders >= 0)
  		nrealreaders = nreaders;
  	else
  		nrealreaders = 2 * num_online_cpus();
8e8be45e8   Paul E. McKenney   rcu: add priority...
1609
  	rcu_torture_print_module_parms(cur_ops, "Start of test");
c9d557c19   Paul E. McKenney   rcu: fix bug in r...
1610
  	fullstop = FULLSTOP_DONTSTOP;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1611
1612
1613
1614
  
  	/* Set up the freelist. */
  
  	INIT_LIST_HEAD(&rcu_torture_freelist);
788e770eb   Ahmed S. Darwish   rcutorture: Use A...
1615
  	for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) {
996417d2c   Paul E. McKenney   [PATCH] add succe...
1616
  		rcu_tortures[i].rtort_mbtest = 0;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
  		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...
1628
1629
  	atomic_set(&n_rcu_torture_mberror, 0);
  	atomic_set(&n_rcu_torture_error, 0);
8e8be45e8   Paul E. McKenney   rcu: add priority...
1630
1631
  	n_rcu_torture_boost_ktrerror = 0;
  	n_rcu_torture_boost_rterror = 0;
8e8be45e8   Paul E. McKenney   rcu: add priority...
1632
1633
  	n_rcu_torture_boost_failure = 0;
  	n_rcu_torture_boosts = 0;
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1634
1635
  	for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
  		atomic_set(&rcu_torture_wcount[i], 0);
0a9450227   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1636
  	for_each_possible_cpu(cpu) {
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
  		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 ...
1654
  	fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
a71fca58b   Paul E. McKenney   rcu: Fix whitespa...
1655
  				   GFP_KERNEL);
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1656
1657
1658
1659
1660
1661
1662
1663
  	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...
1664
  						  "rcu_torture_fakewriter");
b772e1dd4   Josh Triplett   [PATCH] RCU: add ...
1665
1666
1667
1668
1669
1670
1671
  		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...
1672
  	reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
  			       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...
1701
1702
  	if (test_no_idle_hz) {
  		rcu_idle_cpu = num_online_cpus() - 1;
73d0a4b10   Rusty Russell   cpumask: convert ...
1703
1704
1705
1706
1707
1708
  
  		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...
1709
1710
1711
1712
  		/* 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 ...
1713
  			free_cpumask_var(shuffle_tmp_mask);
d84f52034   Srivatsa Vaddagiri   [PATCH] Extend RC...
1714
1715
1716
1717
1718
1719
  			firsterr = PTR_ERR(shuffler_task);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
  			shuffler_task = NULL;
  			goto unwind;
  		}
  	}
d120f65f3   Paul E. McKenney   rcu: make rcutort...
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
  	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...
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
  	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;
  		}
  	}
8e8be45e8   Paul E. McKenney   rcu: add priority...
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
  	if (test_boost_interval < 1)
  		test_boost_interval = 1;
  	if (test_boost_duration < 2)
  		test_boost_duration = 2;
  	if ((test_boost == 1 && cur_ops->can_boost) ||
  	    test_boost == 2) {
  		int retval;
  
  		boost_starttime = jiffies + test_boost_interval * HZ;
  		register_cpu_notifier(&rcutorture_cpu_nb);
  		for_each_possible_cpu(i) {
  			if (cpu_is_offline(i))
  				continue;  /* Heuristic: CPU can go offline. */
  			retval = rcutorture_booster_init(i);
  			if (retval < 0) {
  				firsterr = retval;
  				goto unwind;
  			}
  		}
  	}
d5f546d83   Paul E. McKenney   rcu: Add rcutortu...
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
  	if (shutdown_secs > 0) {
  		shutdown_time = jiffies + shutdown_secs * HZ;
  		shutdown_task = kthread_run(rcu_torture_shutdown, NULL,
  					    "rcu_torture_shutdown");
  		if (IS_ERR(shutdown_task)) {
  			firsterr = PTR_ERR(shutdown_task);
  			VERBOSE_PRINTK_ERRSTRING("Failed to create shutdown");
  			shutdown_task = NULL;
  			goto unwind;
  		}
  	}
b58bdccaa   Paul E. McKenney   rcu: Add rcutortu...
1777
  	rcu_torture_onoff_init();
8e8be45e8   Paul E. McKenney   rcu: add priority...
1778
  	register_reboot_notifier(&rcutorture_shutdown_nb);
4a2986568   Paul E. McKenney   rcu: make rcutort...
1779
  	rcutorture_record_test_transition();
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1780
  	mutex_unlock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1781
1782
1783
  	return 0;
  
  unwind:
343e9099c   Paul E. McKenney   rcu: fix rcutortu...
1784
  	mutex_unlock(&fullstop_mutex);
a241ec65a   Paul E. McKenney   [PATCH] RCU tortu...
1785
1786
1787
1788
1789
1790
  	rcu_torture_cleanup();
  	return firsterr;
  }
  
  module_init(rcu_torture_init);
  module_exit(rcu_torture_cleanup);