Blame view

kernel/locking/locktorture.c 27.6 KB
5a4eb3cb2   Paul E. McKenney   locking/locktortu...
1
  // SPDX-License-Identifier: GPL-2.0+
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
2
3
4
  /*
   * Module-based torture test facility for locking
   *
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
5
6
   * Copyright (C) IBM Corporation, 2014
   *
5a4eb3cb2   Paul E. McKenney   locking/locktortu...
7
   * Authors: Paul E. McKenney <paulmck@linux.ibm.com>
095777c41   Davidlohr Bueso   locktorture: Supp...
8
   *          Davidlohr Bueso <dave@stgolabs.net>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
9
10
   *	Based on kernel/rcu/torture.c.
   */
605000376   Paul E. McKenney   torture: Keep old...
11
12
  
  #define pr_fmt(fmt) fmt
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
13
  #include <linux/kernel.h>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
14
15
  #include <linux/module.h>
  #include <linux/kthread.h>
095777c41   Davidlohr Bueso   locktorture: Supp...
16
  #include <linux/sched/rt.h>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
17
  #include <linux/spinlock.h>
42ddc75dd   Davidlohr Bueso   locktorture: Supp...
18
  #include <linux/mutex.h>
c98fed9fc   Davidlohr Bueso   locktorture: Clea...
19
  #include <linux/rwsem.h>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
20
21
22
  #include <linux/smp.h>
  #include <linux/interrupt.h>
  #include <linux/sched.h>
ae7e81c07   Ingo Molnar   sched/headers: Pr...
23
  #include <uapi/linux/sched/types.h>
037741a6d   Ingo Molnar   sched/headers: Pr...
24
  #include <linux/rtmutex.h>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
25
  #include <linux/atomic.h>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
26
  #include <linux/moduleparam.h>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
27
  #include <linux/delay.h>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
28
  #include <linux/slab.h>
617783dd9   Paul E. McKenney   locktorture: Add ...
29
  #include <linux/percpu-rwsem.h>
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
30
31
32
  #include <linux/torture.h>
  
  MODULE_LICENSE("GPL");
5a4eb3cb2   Paul E. McKenney   locking/locktortu...
33
  MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
34
35
36
  
  torture_param(int, nwriters_stress, -1,
  	     "Number of write-locking stress-test threads");
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
37
38
  torture_param(int, nreaders_stress, -1,
  	     "Number of read-locking stress-test threads");
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
39
40
41
42
43
44
45
46
47
  torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
  torture_param(int, onoff_interval, 0,
  	     "Time between CPU hotplugs (s), 0=disable");
  torture_param(int, shuffle_interval, 3,
  	     "Number of jiffies between shuffles, 0=disable");
  torture_param(int, shutdown_secs, 0, "Shutdown time (j), <= zero to disable.");
  torture_param(int, stat_interval, 60,
  	     "Number of seconds between stats printk()s");
  torture_param(int, stutter, 5, "Number of jiffies to run/halt test, 0=disable");
90127d605   Paul E. McKenney   torture: Make onl...
48
  torture_param(int, verbose, 1,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
49
50
51
52
53
  	     "Enable verbose debugging printk()s");
  
  static char *torture_type = "spin_lock";
  module_param(torture_type, charp, 0444);
  MODULE_PARM_DESC(torture_type,
42ddc75dd   Davidlohr Bueso   locktorture: Supp...
54
  		 "Type of lock to torture (spin_lock, spin_lock_irq, mutex_lock, ...)");
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
55

0af3fe1ef   Paul E. McKenney   locktorture: Add ...
56
57
  static struct task_struct *stats_task;
  static struct task_struct **writer_tasks;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
58
  static struct task_struct **reader_tasks;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
59

0af3fe1ef   Paul E. McKenney   locktorture: Add ...
60
  static bool lock_is_write_held;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
61
  static bool lock_is_read_held;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
62

1e6757a92   Davidlohr Bueso   locktorture: Make...
63
64
65
  struct lock_stress_stats {
  	long n_lock_fail;
  	long n_lock_acquired;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
66
  };
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
67

0af3fe1ef   Paul E. McKenney   locktorture: Add ...
68
69
70
71
72
73
74
75
76
77
  /* Forward reference. */
  static void lock_torture_cleanup(void);
  
  /*
   * Operations vector for selecting different types of tests.
   */
  struct lock_torture_ops {
  	void (*init)(void);
  	int (*writelock)(void);
  	void (*write_delay)(struct torture_random_state *trsp);
095777c41   Davidlohr Bueso   locktorture: Supp...
78
  	void (*task_boost)(struct torture_random_state *trsp);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
79
  	void (*writeunlock)(void);
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
80
81
82
  	int (*readlock)(void);
  	void (*read_delay)(struct torture_random_state *trsp);
  	void (*readunlock)(void);
095777c41   Davidlohr Bueso   locktorture: Supp...
83
84
  
  	unsigned long flags; /* for irq spinlocks */
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
85
86
  	const char *name;
  };
630952c22   Davidlohr Bueso   locktorture: Intr...
87
88
89
90
91
92
93
94
95
96
97
98
  struct lock_torture_cxt {
  	int nrealwriters_stress;
  	int nrealreaders_stress;
  	bool debug_lock;
  	atomic_t n_lock_torture_errors;
  	struct lock_torture_ops *cur_ops;
  	struct lock_stress_stats *lwsa; /* writer statistics */
  	struct lock_stress_stats *lrsa; /* reader statistics */
  };
  static struct lock_torture_cxt cxt = { 0, 0, false,
  				       ATOMIC_INIT(0),
  				       NULL, NULL};
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
99
100
101
  /*
   * Definitions for lock torture testing.
   */
e086481ba   Paul E. McKenney   rcutorture: Add a...
102
103
104
105
106
107
108
  static int torture_lock_busted_write_lock(void)
  {
  	return 0;  /* BUGGY, do not use in real life!!! */
  }
  
  static void torture_lock_busted_write_delay(struct torture_random_state *trsp)
  {
61d49d2f9   Paul E. McKenney   locktorture: Chan...
109
  	const unsigned long longdelay_ms = 100;
e086481ba   Paul E. McKenney   rcutorture: Add a...
110
111
112
  
  	/* We want a long delay occasionally to force massive contention.  */
  	if (!(torture_random(trsp) %
61d49d2f9   Paul E. McKenney   locktorture: Chan...
113
114
  	      (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
  		mdelay(longdelay_ms);
630952c22   Davidlohr Bueso   locktorture: Intr...
115
  	if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
cc1321c96   Paul E. McKenney   torture: Reduce #...
116
  		torture_preempt_schedule();  /* Allow test to be preempted. */
e086481ba   Paul E. McKenney   rcutorture: Add a...
117
118
119
120
121
122
  }
  
  static void torture_lock_busted_write_unlock(void)
  {
  	  /* BUGGY, do not use in real life!!! */
  }
095777c41   Davidlohr Bueso   locktorture: Supp...
123
124
125
126
  static void torture_boost_dummy(struct torture_random_state *trsp)
  {
  	/* Only rtmutexes care about priority */
  }
e086481ba   Paul E. McKenney   rcutorture: Add a...
127
128
129
  static struct lock_torture_ops lock_busted_ops = {
  	.writelock	= torture_lock_busted_write_lock,
  	.write_delay	= torture_lock_busted_write_delay,
095777c41   Davidlohr Bueso   locktorture: Supp...
130
  	.task_boost     = torture_boost_dummy,
e086481ba   Paul E. McKenney   rcutorture: Add a...
131
  	.writeunlock	= torture_lock_busted_write_unlock,
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
132
133
134
  	.readlock       = NULL,
  	.read_delay     = NULL,
  	.readunlock     = NULL,
e086481ba   Paul E. McKenney   rcutorture: Add a...
135
136
  	.name		= "lock_busted"
  };
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
137
138
139
140
141
142
143
144
145
146
147
  static DEFINE_SPINLOCK(torture_spinlock);
  
  static int torture_spin_lock_write_lock(void) __acquires(torture_spinlock)
  {
  	spin_lock(&torture_spinlock);
  	return 0;
  }
  
  static void torture_spin_lock_write_delay(struct torture_random_state *trsp)
  {
  	const unsigned long shortdelay_us = 2;
61d49d2f9   Paul E. McKenney   locktorture: Chan...
148
  	const unsigned long longdelay_ms = 100;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
149
150
151
152
153
  
  	/* We want a short delay mostly to emulate likely code, and
  	 * we want a long delay occasionally to force massive contention.
  	 */
  	if (!(torture_random(trsp) %
61d49d2f9   Paul E. McKenney   locktorture: Chan...
154
155
  	      (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
  		mdelay(longdelay_ms);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
156
  	if (!(torture_random(trsp) %
630952c22   Davidlohr Bueso   locktorture: Intr...
157
  	      (cxt.nrealwriters_stress * 2 * shortdelay_us)))
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
158
  		udelay(shortdelay_us);
630952c22   Davidlohr Bueso   locktorture: Intr...
159
  	if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
cc1321c96   Paul E. McKenney   torture: Reduce #...
160
  		torture_preempt_schedule();  /* Allow test to be preempted. */
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
161
162
163
164
165
166
167
168
169
170
  }
  
  static void torture_spin_lock_write_unlock(void) __releases(torture_spinlock)
  {
  	spin_unlock(&torture_spinlock);
  }
  
  static struct lock_torture_ops spin_lock_ops = {
  	.writelock	= torture_spin_lock_write_lock,
  	.write_delay	= torture_spin_lock_write_delay,
095777c41   Davidlohr Bueso   locktorture: Supp...
171
  	.task_boost     = torture_boost_dummy,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
172
  	.writeunlock	= torture_spin_lock_write_unlock,
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
173
174
175
  	.readlock       = NULL,
  	.read_delay     = NULL,
  	.readunlock     = NULL,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
176
177
178
179
  	.name		= "spin_lock"
  };
  
  static int torture_spin_lock_write_lock_irq(void)
219f800f9   Davidlohr Bueso   locktorture: Fix ...
180
  __acquires(torture_spinlock)
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
181
182
183
184
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&torture_spinlock, flags);
630952c22   Davidlohr Bueso   locktorture: Intr...
185
  	cxt.cur_ops->flags = flags;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
186
187
188
189
190
191
  	return 0;
  }
  
  static void torture_lock_spin_write_unlock_irq(void)
  __releases(torture_spinlock)
  {
630952c22   Davidlohr Bueso   locktorture: Intr...
192
  	spin_unlock_irqrestore(&torture_spinlock, cxt.cur_ops->flags);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
193
194
195
196
197
  }
  
  static struct lock_torture_ops spin_lock_irq_ops = {
  	.writelock	= torture_spin_lock_write_lock_irq,
  	.write_delay	= torture_spin_lock_write_delay,
095777c41   Davidlohr Bueso   locktorture: Supp...
198
  	.task_boost     = torture_boost_dummy,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
199
  	.writeunlock	= torture_lock_spin_write_unlock_irq,
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
200
201
202
  	.readlock       = NULL,
  	.read_delay     = NULL,
  	.readunlock     = NULL,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
203
204
  	.name		= "spin_lock_irq"
  };
e34191fad   Davidlohr Bueso   locktorture: Supp...
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  static DEFINE_RWLOCK(torture_rwlock);
  
  static int torture_rwlock_write_lock(void) __acquires(torture_rwlock)
  {
  	write_lock(&torture_rwlock);
  	return 0;
  }
  
  static void torture_rwlock_write_delay(struct torture_random_state *trsp)
  {
  	const unsigned long shortdelay_us = 2;
  	const unsigned long longdelay_ms = 100;
  
  	/* We want a short delay mostly to emulate likely code, and
  	 * we want a long delay occasionally to force massive contention.
  	 */
  	if (!(torture_random(trsp) %
  	      (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
  		mdelay(longdelay_ms);
  	else
  		udelay(shortdelay_us);
  }
  
  static void torture_rwlock_write_unlock(void) __releases(torture_rwlock)
  {
  	write_unlock(&torture_rwlock);
  }
  
  static int torture_rwlock_read_lock(void) __acquires(torture_rwlock)
  {
  	read_lock(&torture_rwlock);
  	return 0;
  }
  
  static void torture_rwlock_read_delay(struct torture_random_state *trsp)
  {
  	const unsigned long shortdelay_us = 10;
  	const unsigned long longdelay_ms = 100;
  
  	/* We want a short delay mostly to emulate likely code, and
  	 * we want a long delay occasionally to force massive contention.
  	 */
  	if (!(torture_random(trsp) %
  	      (cxt.nrealreaders_stress * 2000 * longdelay_ms)))
  		mdelay(longdelay_ms);
  	else
  		udelay(shortdelay_us);
  }
  
  static void torture_rwlock_read_unlock(void) __releases(torture_rwlock)
  {
  	read_unlock(&torture_rwlock);
  }
  
  static struct lock_torture_ops rw_lock_ops = {
  	.writelock	= torture_rwlock_write_lock,
  	.write_delay	= torture_rwlock_write_delay,
095777c41   Davidlohr Bueso   locktorture: Supp...
262
  	.task_boost     = torture_boost_dummy,
e34191fad   Davidlohr Bueso   locktorture: Supp...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  	.writeunlock	= torture_rwlock_write_unlock,
  	.readlock       = torture_rwlock_read_lock,
  	.read_delay     = torture_rwlock_read_delay,
  	.readunlock     = torture_rwlock_read_unlock,
  	.name		= "rw_lock"
  };
  
  static int torture_rwlock_write_lock_irq(void) __acquires(torture_rwlock)
  {
  	unsigned long flags;
  
  	write_lock_irqsave(&torture_rwlock, flags);
  	cxt.cur_ops->flags = flags;
  	return 0;
  }
  
  static void torture_rwlock_write_unlock_irq(void)
  __releases(torture_rwlock)
  {
  	write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags);
  }
  
  static int torture_rwlock_read_lock_irq(void) __acquires(torture_rwlock)
  {
  	unsigned long flags;
  
  	read_lock_irqsave(&torture_rwlock, flags);
  	cxt.cur_ops->flags = flags;
  	return 0;
  }
  
  static void torture_rwlock_read_unlock_irq(void)
  __releases(torture_rwlock)
  {
f548d99ef   Alexey Kodanev   locktorture: fix ...
297
  	read_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags);
e34191fad   Davidlohr Bueso   locktorture: Supp...
298
299
300
301
302
  }
  
  static struct lock_torture_ops rw_lock_irq_ops = {
  	.writelock	= torture_rwlock_write_lock_irq,
  	.write_delay	= torture_rwlock_write_delay,
095777c41   Davidlohr Bueso   locktorture: Supp...
303
  	.task_boost     = torture_boost_dummy,
e34191fad   Davidlohr Bueso   locktorture: Supp...
304
305
306
307
308
309
  	.writeunlock	= torture_rwlock_write_unlock_irq,
  	.readlock       = torture_rwlock_read_lock_irq,
  	.read_delay     = torture_rwlock_read_delay,
  	.readunlock     = torture_rwlock_read_unlock_irq,
  	.name		= "rw_lock_irq"
  };
42ddc75dd   Davidlohr Bueso   locktorture: Supp...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  static DEFINE_MUTEX(torture_mutex);
  
  static int torture_mutex_lock(void) __acquires(torture_mutex)
  {
  	mutex_lock(&torture_mutex);
  	return 0;
  }
  
  static void torture_mutex_delay(struct torture_random_state *trsp)
  {
  	const unsigned long longdelay_ms = 100;
  
  	/* We want a long delay occasionally to force massive contention.  */
  	if (!(torture_random(trsp) %
630952c22   Davidlohr Bueso   locktorture: Intr...
324
  	      (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
42ddc75dd   Davidlohr Bueso   locktorture: Supp...
325
326
327
  		mdelay(longdelay_ms * 5);
  	else
  		mdelay(longdelay_ms / 5);
630952c22   Davidlohr Bueso   locktorture: Intr...
328
  	if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
cc1321c96   Paul E. McKenney   torture: Reduce #...
329
  		torture_preempt_schedule();  /* Allow test to be preempted. */
42ddc75dd   Davidlohr Bueso   locktorture: Supp...
330
331
332
333
334
335
336
337
338
339
  }
  
  static void torture_mutex_unlock(void) __releases(torture_mutex)
  {
  	mutex_unlock(&torture_mutex);
  }
  
  static struct lock_torture_ops mutex_lock_ops = {
  	.writelock	= torture_mutex_lock,
  	.write_delay	= torture_mutex_delay,
095777c41   Davidlohr Bueso   locktorture: Supp...
340
  	.task_boost     = torture_boost_dummy,
42ddc75dd   Davidlohr Bueso   locktorture: Supp...
341
  	.writeunlock	= torture_mutex_unlock,
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
342
343
344
  	.readlock       = NULL,
  	.read_delay     = NULL,
  	.readunlock     = NULL,
42ddc75dd   Davidlohr Bueso   locktorture: Supp...
345
346
  	.name		= "mutex_lock"
  };
0186a6cbd   Chris Wilson   locking/ww_mutex:...
347
  #include <linux/ww_mutex.h>
08295b3b5   Thomas Hellstrom   locking: Implemen...
348
  static DEFINE_WD_CLASS(torture_ww_class);
0186a6cbd   Chris Wilson   locking/ww_mutex:...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  static DEFINE_WW_MUTEX(torture_ww_mutex_0, &torture_ww_class);
  static DEFINE_WW_MUTEX(torture_ww_mutex_1, &torture_ww_class);
  static DEFINE_WW_MUTEX(torture_ww_mutex_2, &torture_ww_class);
  
  static int torture_ww_mutex_lock(void)
  __acquires(torture_ww_mutex_0)
  __acquires(torture_ww_mutex_1)
  __acquires(torture_ww_mutex_2)
  {
  	LIST_HEAD(list);
  	struct reorder_lock {
  		struct list_head link;
  		struct ww_mutex *lock;
  	} locks[3], *ll, *ln;
  	struct ww_acquire_ctx ctx;
  
  	locks[0].lock = &torture_ww_mutex_0;
  	list_add(&locks[0].link, &list);
  
  	locks[1].lock = &torture_ww_mutex_1;
  	list_add(&locks[1].link, &list);
  
  	locks[2].lock = &torture_ww_mutex_2;
  	list_add(&locks[2].link, &list);
  
  	ww_acquire_init(&ctx, &torture_ww_class);
  
  	list_for_each_entry(ll, &list, link) {
  		int err;
  
  		err = ww_mutex_lock(ll->lock, &ctx);
  		if (!err)
  			continue;
  
  		ln = ll;
  		list_for_each_entry_continue_reverse(ln, &list, link)
  			ww_mutex_unlock(ln->lock);
  
  		if (err != -EDEADLK)
  			return err;
  
  		ww_mutex_lock_slow(ll->lock, &ctx);
  		list_move(&ll->link, &list);
  	}
  
  	ww_acquire_fini(&ctx);
  	return 0;
  }
  
  static void torture_ww_mutex_unlock(void)
  __releases(torture_ww_mutex_0)
  __releases(torture_ww_mutex_1)
  __releases(torture_ww_mutex_2)
  {
  	ww_mutex_unlock(&torture_ww_mutex_0);
  	ww_mutex_unlock(&torture_ww_mutex_1);
  	ww_mutex_unlock(&torture_ww_mutex_2);
  }
  
  static struct lock_torture_ops ww_mutex_lock_ops = {
  	.writelock	= torture_ww_mutex_lock,
  	.write_delay	= torture_mutex_delay,
  	.task_boost     = torture_boost_dummy,
  	.writeunlock	= torture_ww_mutex_unlock,
  	.readlock       = NULL,
  	.read_delay     = NULL,
  	.readunlock     = NULL,
  	.name		= "ww_mutex_lock"
  };
095777c41   Davidlohr Bueso   locktorture: Supp...
418
419
420
421
422
423
424
425
426
427
428
  #ifdef CONFIG_RT_MUTEXES
  static DEFINE_RT_MUTEX(torture_rtmutex);
  
  static int torture_rtmutex_lock(void) __acquires(torture_rtmutex)
  {
  	rt_mutex_lock(&torture_rtmutex);
  	return 0;
  }
  
  static void torture_rtmutex_boost(struct torture_random_state *trsp)
  {
095777c41   Davidlohr Bueso   locktorture: Supp...
429
430
431
432
  	const unsigned int factor = 50000; /* yes, quite arbitrary */
  
  	if (!rt_task(current)) {
  		/*
1f1909318   Davidlohr Bueso   locking/locktortu...
433
  		 * Boost priority once every ~50k operations. When the
095777c41   Davidlohr Bueso   locktorture: Supp...
434
435
436
  		 * task tries to take the lock, the rtmutex it will account
  		 * for the new priority, and do any corresponding pi-dance.
  		 */
1f1909318   Davidlohr Bueso   locking/locktortu...
437
438
  		if (trsp && !(torture_random(trsp) %
  			      (cxt.nrealwriters_stress * factor))) {
93db9129f   Peter Zijlstra   sched,locktorture...
439
  			sched_set_fifo(current);
095777c41   Davidlohr Bueso   locktorture: Supp...
440
441
442
443
444
445
446
447
448
449
450
451
  		} else /* common case, do nothing */
  			return;
  	} else {
  		/*
  		 * The task will remain boosted for another ~500k operations,
  		 * then restored back to its original prio, and so forth.
  		 *
  		 * When @trsp is nil, we want to force-reset the task for
  		 * stopping the kthread.
  		 */
  		if (!trsp || !(torture_random(trsp) %
  			       (cxt.nrealwriters_stress * factor * 2))) {
93db9129f   Peter Zijlstra   sched,locktorture...
452
  			sched_set_normal(current, 0);
095777c41   Davidlohr Bueso   locktorture: Supp...
453
454
455
  		} else /* common case, do nothing */
  			return;
  	}
095777c41   Davidlohr Bueso   locktorture: Supp...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  }
  
  static void torture_rtmutex_delay(struct torture_random_state *trsp)
  {
  	const unsigned long shortdelay_us = 2;
  	const unsigned long longdelay_ms = 100;
  
  	/*
  	 * We want a short delay mostly to emulate likely code, and
  	 * we want a long delay occasionally to force massive contention.
  	 */
  	if (!(torture_random(trsp) %
  	      (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
  		mdelay(longdelay_ms);
  	if (!(torture_random(trsp) %
  	      (cxt.nrealwriters_stress * 2 * shortdelay_us)))
  		udelay(shortdelay_us);
095777c41   Davidlohr Bueso   locktorture: Supp...
473
  	if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
cc1321c96   Paul E. McKenney   torture: Reduce #...
474
  		torture_preempt_schedule();  /* Allow test to be preempted. */
095777c41   Davidlohr Bueso   locktorture: Supp...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  }
  
  static void torture_rtmutex_unlock(void) __releases(torture_rtmutex)
  {
  	rt_mutex_unlock(&torture_rtmutex);
  }
  
  static struct lock_torture_ops rtmutex_lock_ops = {
  	.writelock	= torture_rtmutex_lock,
  	.write_delay	= torture_rtmutex_delay,
  	.task_boost     = torture_rtmutex_boost,
  	.writeunlock	= torture_rtmutex_unlock,
  	.readlock       = NULL,
  	.read_delay     = NULL,
  	.readunlock     = NULL,
  	.name		= "rtmutex_lock"
  };
  #endif
4a3b427f0   Davidlohr Bueso   locktorture: Supp...
493
494
495
496
497
498
499
500
501
502
503
504
505
  static DECLARE_RWSEM(torture_rwsem);
  static int torture_rwsem_down_write(void) __acquires(torture_rwsem)
  {
  	down_write(&torture_rwsem);
  	return 0;
  }
  
  static void torture_rwsem_write_delay(struct torture_random_state *trsp)
  {
  	const unsigned long longdelay_ms = 100;
  
  	/* We want a long delay occasionally to force massive contention.  */
  	if (!(torture_random(trsp) %
630952c22   Davidlohr Bueso   locktorture: Intr...
506
  	      (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
4a3b427f0   Davidlohr Bueso   locktorture: Supp...
507
508
509
  		mdelay(longdelay_ms * 10);
  	else
  		mdelay(longdelay_ms / 10);
630952c22   Davidlohr Bueso   locktorture: Intr...
510
  	if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
cc1321c96   Paul E. McKenney   torture: Reduce #...
511
  		torture_preempt_schedule();  /* Allow test to be preempted. */
4a3b427f0   Davidlohr Bueso   locktorture: Supp...
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  }
  
  static void torture_rwsem_up_write(void) __releases(torture_rwsem)
  {
  	up_write(&torture_rwsem);
  }
  
  static int torture_rwsem_down_read(void) __acquires(torture_rwsem)
  {
  	down_read(&torture_rwsem);
  	return 0;
  }
  
  static void torture_rwsem_read_delay(struct torture_random_state *trsp)
  {
  	const unsigned long longdelay_ms = 100;
  
  	/* We want a long delay occasionally to force massive contention.  */
  	if (!(torture_random(trsp) %
f2f762608   Davidlohr Bueso   locking/locktortu...
531
  	      (cxt.nrealreaders_stress * 2000 * longdelay_ms)))
4a3b427f0   Davidlohr Bueso   locktorture: Supp...
532
533
534
  		mdelay(longdelay_ms * 2);
  	else
  		mdelay(longdelay_ms / 2);
630952c22   Davidlohr Bueso   locktorture: Intr...
535
  	if (!(torture_random(trsp) % (cxt.nrealreaders_stress * 20000)))
cc1321c96   Paul E. McKenney   torture: Reduce #...
536
  		torture_preempt_schedule();  /* Allow test to be preempted. */
4a3b427f0   Davidlohr Bueso   locktorture: Supp...
537
538
539
540
541
542
543
544
545
546
  }
  
  static void torture_rwsem_up_read(void) __releases(torture_rwsem)
  {
  	up_read(&torture_rwsem);
  }
  
  static struct lock_torture_ops rwsem_lock_ops = {
  	.writelock	= torture_rwsem_down_write,
  	.write_delay	= torture_rwsem_write_delay,
095777c41   Davidlohr Bueso   locktorture: Supp...
547
  	.task_boost     = torture_boost_dummy,
4a3b427f0   Davidlohr Bueso   locktorture: Supp...
548
549
550
551
552
553
  	.writeunlock	= torture_rwsem_up_write,
  	.readlock       = torture_rwsem_down_read,
  	.read_delay     = torture_rwsem_read_delay,
  	.readunlock     = torture_rwsem_up_read,
  	.name		= "rwsem_lock"
  };
617783dd9   Paul E. McKenney   locktorture: Add ...
554
555
  #include <linux/percpu-rwsem.h>
  static struct percpu_rw_semaphore pcpu_rwsem;
d49bed9ab   Wei Yongjun   locktorture: Make...
556
  static void torture_percpu_rwsem_init(void)
617783dd9   Paul E. McKenney   locktorture: Add ...
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  {
  	BUG_ON(percpu_init_rwsem(&pcpu_rwsem));
  }
  
  static int torture_percpu_rwsem_down_write(void) __acquires(pcpu_rwsem)
  {
  	percpu_down_write(&pcpu_rwsem);
  	return 0;
  }
  
  static void torture_percpu_rwsem_up_write(void) __releases(pcpu_rwsem)
  {
  	percpu_up_write(&pcpu_rwsem);
  }
  
  static int torture_percpu_rwsem_down_read(void) __acquires(pcpu_rwsem)
  {
  	percpu_down_read(&pcpu_rwsem);
  	return 0;
  }
  
  static void torture_percpu_rwsem_up_read(void) __releases(pcpu_rwsem)
  {
  	percpu_up_read(&pcpu_rwsem);
  }
  
  static struct lock_torture_ops percpu_rwsem_lock_ops = {
  	.init		= torture_percpu_rwsem_init,
  	.writelock	= torture_percpu_rwsem_down_write,
  	.write_delay	= torture_rwsem_write_delay,
  	.task_boost     = torture_boost_dummy,
  	.writeunlock	= torture_percpu_rwsem_up_write,
  	.readlock       = torture_percpu_rwsem_down_read,
  	.read_delay     = torture_rwsem_read_delay,
  	.readunlock     = torture_percpu_rwsem_up_read,
  	.name		= "percpu_rwsem_lock"
  };
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
594
595
596
597
598
599
  /*
   * Lock torture writer kthread.  Repeatedly acquires and releases
   * the lock, checking for duplicate acquisitions.
   */
  static int lock_torture_writer(void *arg)
  {
1e6757a92   Davidlohr Bueso   locktorture: Make...
600
  	struct lock_stress_stats *lwsp = arg;
c0e1472d8   Paul E. McKenney   locktorture: Use ...
601
  	DEFINE_TORTURE_RANDOM(rand);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
602
603
  
  	VERBOSE_TOROUT_STRING("lock_torture_writer task started");
8698a745d   Dongsheng Yang   sched, treewide: ...
604
  	set_user_nice(current, MAX_NICE);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
605
606
  
  	do {
da601c63f   Paul E. McKenney   torture: Intensif...
607
608
  		if ((torture_random(&rand) & 0xfffff) == 0)
  			schedule_timeout_uninterruptible(1);
a12294910   Davidlohr Bueso   locktorture: Cann...
609

095777c41   Davidlohr Bueso   locktorture: Supp...
610
  		cxt.cur_ops->task_boost(&rand);
630952c22   Davidlohr Bueso   locktorture: Intr...
611
  		cxt.cur_ops->writelock();
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
612
  		if (WARN_ON_ONCE(lock_is_write_held))
1e6757a92   Davidlohr Bueso   locktorture: Make...
613
  			lwsp->n_lock_fail++;
d02c6b52d   Zou Wei   locktorture: Use ...
614
  		lock_is_write_held = true;
a12294910   Davidlohr Bueso   locktorture: Cann...
615
616
  		if (WARN_ON_ONCE(lock_is_read_held))
  			lwsp->n_lock_fail++; /* rare, but... */
1e6757a92   Davidlohr Bueso   locktorture: Make...
617
  		lwsp->n_lock_acquired++;
630952c22   Davidlohr Bueso   locktorture: Intr...
618
  		cxt.cur_ops->write_delay(&rand);
d02c6b52d   Zou Wei   locktorture: Use ...
619
  		lock_is_write_held = false;
630952c22   Davidlohr Bueso   locktorture: Intr...
620
  		cxt.cur_ops->writeunlock();
a12294910   Davidlohr Bueso   locktorture: Cann...
621

0af3fe1ef   Paul E. McKenney   locktorture: Add ...
622
623
  		stutter_wait("lock_torture_writer");
  	} while (!torture_must_stop());
095777c41   Davidlohr Bueso   locktorture: Supp...
624
625
  
  	cxt.cur_ops->task_boost(NULL); /* reset prio */
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
626
627
628
629
630
  	torture_kthread_stopping("lock_torture_writer");
  	return 0;
  }
  
  /*
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
631
632
633
634
635
636
   * Lock torture reader kthread.  Repeatedly acquires and releases
   * the reader lock.
   */
  static int lock_torture_reader(void *arg)
  {
  	struct lock_stress_stats *lrsp = arg;
c0e1472d8   Paul E. McKenney   locktorture: Use ...
637
  	DEFINE_TORTURE_RANDOM(rand);
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
638
639
640
641
642
643
644
  
  	VERBOSE_TOROUT_STRING("lock_torture_reader task started");
  	set_user_nice(current, MAX_NICE);
  
  	do {
  		if ((torture_random(&rand) & 0xfffff) == 0)
  			schedule_timeout_uninterruptible(1);
a12294910   Davidlohr Bueso   locktorture: Cann...
645

630952c22   Davidlohr Bueso   locktorture: Intr...
646
  		cxt.cur_ops->readlock();
d02c6b52d   Zou Wei   locktorture: Use ...
647
  		lock_is_read_held = true;
a12294910   Davidlohr Bueso   locktorture: Cann...
648
649
  		if (WARN_ON_ONCE(lock_is_write_held))
  			lrsp->n_lock_fail++; /* rare, but... */
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
650
  		lrsp->n_lock_acquired++;
630952c22   Davidlohr Bueso   locktorture: Intr...
651
  		cxt.cur_ops->read_delay(&rand);
d02c6b52d   Zou Wei   locktorture: Use ...
652
  		lock_is_read_held = false;
630952c22   Davidlohr Bueso   locktorture: Intr...
653
  		cxt.cur_ops->readunlock();
a12294910   Davidlohr Bueso   locktorture: Cann...
654

4f6332c1d   Davidlohr Bueso   locktorture: Add ...
655
656
657
658
659
660
661
  		stutter_wait("lock_torture_reader");
  	} while (!torture_must_stop());
  	torture_kthread_stopping("lock_torture_reader");
  	return 0;
  }
  
  /*
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
662
663
   * Create an lock-torture-statistics message in the specified buffer.
   */
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
664
665
  static void __torture_print_stats(char *page,
  				  struct lock_stress_stats *statp, bool write)
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
666
  {
d02c6b52d   Zou Wei   locktorture: Use ...
667
  	bool fail = false;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
668
  	int i, n_stress;
2ce77d16d   Davidlohr Bueso   locking/locktortu...
669
  	long max = 0, min = statp ? statp[0].n_lock_acquired : 0;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
670
  	long long sum = 0;
630952c22   Davidlohr Bueso   locktorture: Intr...
671
  	n_stress = write ? cxt.nrealwriters_stress : cxt.nrealreaders_stress;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
672
673
  	for (i = 0; i < n_stress; i++) {
  		if (statp[i].n_lock_fail)
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
674
  			fail = true;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
675
  		sum += statp[i].n_lock_acquired;
80c503e0e   Paul E. McKenney   locktorture: Prin...
676
677
678
679
  		if (max < statp[i].n_lock_acquired)
  			max = statp[i].n_lock_acquired;
  		if (min > statp[i].n_lock_acquired)
  			min = statp[i].n_lock_acquired;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
680
  	}
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
681
  	page += sprintf(page,
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
682
683
684
  			"%s:  Total: %lld  Max/Min: %ld/%ld %s  Fail: %d %s
  ",
  			write ? "Writes" : "Reads ",
28e09a2e4   Paul E. McKenney   locktorture: Forg...
685
686
  			sum, max, min,
  			!onoff_interval && max / 2 > min ? "???" : "",
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
687
688
  			fail, fail ? "!!!" : "");
  	if (fail)
630952c22   Davidlohr Bueso   locktorture: Intr...
689
  		atomic_inc(&cxt.n_lock_torture_errors);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
690
691
692
693
694
695
696
697
698
699
700
701
  }
  
  /*
   * 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 lock_torture_stats kthread full control
   * (or the init/cleanup functions when lock_torture_stats thread is not
   * running).
   */
  static void lock_torture_stats_print(void)
  {
630952c22   Davidlohr Bueso   locktorture: Intr...
702
  	int size = cxt.nrealwriters_stress * 200 + 8192;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
703
  	char *buf;
630952c22   Davidlohr Bueso   locktorture: Intr...
704
705
  	if (cxt.cur_ops->readlock)
  		size += cxt.nrealreaders_stress * 200 + 8192;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
706

0af3fe1ef   Paul E. McKenney   locktorture: Add ...
707
708
709
710
711
712
  	buf = kmalloc(size, GFP_KERNEL);
  	if (!buf) {
  		pr_err("lock_torture_stats_print: Out of memory, need: %d",
  		       size);
  		return;
  	}
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
713

630952c22   Davidlohr Bueso   locktorture: Intr...
714
  	__torture_print_stats(buf, cxt.lwsa, true);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
715
716
  	pr_alert("%s", buf);
  	kfree(buf);
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
717

630952c22   Davidlohr Bueso   locktorture: Intr...
718
  	if (cxt.cur_ops->readlock) {
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
719
720
721
722
723
724
  		buf = kmalloc(size, GFP_KERNEL);
  		if (!buf) {
  			pr_err("lock_torture_stats_print: Out of memory, need: %d",
  			       size);
  			return;
  		}
630952c22   Davidlohr Bueso   locktorture: Intr...
725
  		__torture_print_stats(buf, cxt.lrsa, false);
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
726
727
728
  		pr_alert("%s", buf);
  		kfree(buf);
  	}
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  }
  
  /*
   * 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 lock_torture_stats(void *arg)
  {
  	VERBOSE_TOROUT_STRING("lock_torture_stats task started");
  	do {
  		schedule_timeout_interruptible(stat_interval * HZ);
  		lock_torture_stats_print();
  		torture_shutdown_absorb("lock_torture_stats");
  	} while (!torture_must_stop());
  	torture_kthread_stopping("lock_torture_stats");
  	return 0;
  }
  
  static inline void
  lock_torture_print_module_parms(struct lock_torture_ops *cur_ops,
  				const char *tag)
  {
  	pr_alert("%s" TORTURE_FLAG
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
755
756
  		 "--- %s%s: nwriters_stress=%d nreaders_stress=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d
  ",
630952c22   Davidlohr Bueso   locktorture: Intr...
757
758
  		 torture_type, tag, cxt.debug_lock ? " [debug]": "",
  		 cxt.nrealwriters_stress, cxt.nrealreaders_stress, stat_interval,
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
759
  		 verbose, shuffle_interval, stutter, shutdown_secs,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
760
761
762
763
764
765
  		 onoff_interval, onoff_holdoff);
  }
  
  static void lock_torture_cleanup(void)
  {
  	int i;
d36a7a0d5   Davidlohr Bueso   torture: Address ...
766
  	if (torture_cleanup_begin())
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
767
  		return;
c1c33b92d   Davidlohr Bueso   locking/locktortu...
768
769
770
771
772
773
  	/*
  	 * Indicates early cleanup, meaning that the test has not run,
  	 * such as when passing bogus args when loading the module. As
  	 * such, only perform the underlying torture-specific cleanups,
  	 * and avoid anything related to locktorture.
  	 */
2ce77d16d   Davidlohr Bueso   locking/locktortu...
774
  	if (!cxt.lwsa && !cxt.lrsa)
c1c33b92d   Davidlohr Bueso   locking/locktortu...
775
  		goto end;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
776
  	if (writer_tasks) {
630952c22   Davidlohr Bueso   locktorture: Intr...
777
  		for (i = 0; i < cxt.nrealwriters_stress; i++)
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
778
779
780
781
782
  			torture_stop_kthread(lock_torture_writer,
  					     writer_tasks[i]);
  		kfree(writer_tasks);
  		writer_tasks = NULL;
  	}
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
783
  	if (reader_tasks) {
630952c22   Davidlohr Bueso   locktorture: Intr...
784
  		for (i = 0; i < cxt.nrealreaders_stress; i++)
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
785
786
787
788
789
  			torture_stop_kthread(lock_torture_reader,
  					     reader_tasks[i]);
  		kfree(reader_tasks);
  		reader_tasks = NULL;
  	}
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
790
791
  	torture_stop_kthread(lock_torture_stats, stats_task);
  	lock_torture_stats_print();  /* -After- the stats thread is stopped! */
630952c22   Davidlohr Bueso   locktorture: Intr...
792
793
  	if (atomic_read(&cxt.n_lock_torture_errors))
  		lock_torture_print_module_parms(cxt.cur_ops,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
794
795
  						"End of test: FAILURE");
  	else if (torture_onoff_failures())
630952c22   Davidlohr Bueso   locktorture: Intr...
796
  		lock_torture_print_module_parms(cxt.cur_ops,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
797
798
  						"End of test: LOCK_HOTPLUG");
  	else
630952c22   Davidlohr Bueso   locktorture: Intr...
799
  		lock_torture_print_module_parms(cxt.cur_ops,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
800
  						"End of test: SUCCESS");
f4dbba591   Yang Shi   locktorture: Fix ...
801
802
  
  	kfree(cxt.lwsa);
a9d6938dd   Paul E. McKenney   locktorture: NULL...
803
  	cxt.lwsa = NULL;
f4dbba591   Yang Shi   locktorture: Fix ...
804
  	kfree(cxt.lrsa);
a9d6938dd   Paul E. McKenney   locktorture: NULL...
805
  	cxt.lrsa = NULL;
f4dbba591   Yang Shi   locktorture: Fix ...
806

c1c33b92d   Davidlohr Bueso   locking/locktortu...
807
  end:
d36a7a0d5   Davidlohr Bueso   torture: Address ...
808
  	torture_cleanup_end();
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
809
810
811
812
  }
  
  static int __init lock_torture_init(void)
  {
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
813
  	int i, j;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
814
815
  	int firsterr = 0;
  	static struct lock_torture_ops *torture_ops[] = {
e34191fad   Davidlohr Bueso   locktorture: Supp...
816
817
818
819
  		&lock_busted_ops,
  		&spin_lock_ops, &spin_lock_irq_ops,
  		&rw_lock_ops, &rw_lock_irq_ops,
  		&mutex_lock_ops,
0186a6cbd   Chris Wilson   locking/ww_mutex:...
820
  		&ww_mutex_lock_ops,
095777c41   Davidlohr Bueso   locktorture: Supp...
821
822
823
  #ifdef CONFIG_RT_MUTEXES
  		&rtmutex_lock_ops,
  #endif
e34191fad   Davidlohr Bueso   locktorture: Supp...
824
  		&rwsem_lock_ops,
617783dd9   Paul E. McKenney   locktorture: Add ...
825
  		&percpu_rwsem_lock_ops,
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
826
  	};
a2f2577d9   Paul E. McKenney   torture: Eliminat...
827
  	if (!torture_init_begin(torture_type, verbose))
5228084ee   Paul E. McKenney   torture: Check fo...
828
  		return -EBUSY;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
829
830
831
  
  	/* Process args and tell the world that the torturer is on the job. */
  	for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
630952c22   Davidlohr Bueso   locktorture: Intr...
832
833
  		cxt.cur_ops = torture_ops[i];
  		if (strcmp(torture_type, cxt.cur_ops->name) == 0)
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
834
835
836
837
838
839
840
841
842
843
844
  			break;
  	}
  	if (i == ARRAY_SIZE(torture_ops)) {
  		pr_alert("lock-torture: invalid torture type: \"%s\"
  ",
  			 torture_type);
  		pr_alert("lock-torture types:");
  		for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
  			pr_alert(" %s", torture_ops[i]->name);
  		pr_alert("
  ");
a36a99618   Paul E. McKenney   locktorture: Fix ...
845
846
  		firsterr = -EINVAL;
  		goto unwind;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
847
  	}
2ce77d16d   Davidlohr Bueso   locking/locktortu...
848
849
850
851
852
853
854
  
  	if (nwriters_stress == 0 && nreaders_stress == 0) {
  		pr_alert("lock-torture: must run at least one locking thread
  ");
  		firsterr = -EINVAL;
  		goto unwind;
  	}
630952c22   Davidlohr Bueso   locktorture: Intr...
855
  	if (cxt.cur_ops->init)
a36a99618   Paul E. McKenney   locktorture: Fix ...
856
  		cxt.cur_ops->init();
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
857
858
  
  	if (nwriters_stress >= 0)
630952c22   Davidlohr Bueso   locktorture: Intr...
859
  		cxt.nrealwriters_stress = nwriters_stress;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
860
  	else
630952c22   Davidlohr Bueso   locktorture: Intr...
861
  		cxt.nrealwriters_stress = 2 * num_online_cpus();
f095bfc0e   Davidlohr Bueso   locktorture: Teac...
862
863
  
  #ifdef CONFIG_DEBUG_MUTEXES
c5d3c8ca2   Chuhong Yuan   locktorture: Repl...
864
  	if (str_has_prefix(torture_type, "mutex"))
630952c22   Davidlohr Bueso   locktorture: Intr...
865
  		cxt.debug_lock = true;
f095bfc0e   Davidlohr Bueso   locktorture: Teac...
866
  #endif
095777c41   Davidlohr Bueso   locktorture: Supp...
867
  #ifdef CONFIG_DEBUG_RT_MUTEXES
c5d3c8ca2   Chuhong Yuan   locktorture: Repl...
868
  	if (str_has_prefix(torture_type, "rtmutex"))
095777c41   Davidlohr Bueso   locktorture: Supp...
869
870
  		cxt.debug_lock = true;
  #endif
f095bfc0e   Davidlohr Bueso   locktorture: Teac...
871
  #ifdef CONFIG_DEBUG_SPINLOCK
c5d3c8ca2   Chuhong Yuan   locktorture: Repl...
872
873
  	if ((str_has_prefix(torture_type, "spin")) ||
  	    (str_has_prefix(torture_type, "rw_lock")))
630952c22   Davidlohr Bueso   locktorture: Intr...
874
  		cxt.debug_lock = true;
f095bfc0e   Davidlohr Bueso   locktorture: Teac...
875
  #endif
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
876
877
  
  	/* Initialize the statistics so that each run gets its own numbers. */
2ce77d16d   Davidlohr Bueso   locking/locktortu...
878
  	if (nwriters_stress) {
d02c6b52d   Zou Wei   locktorture: Use ...
879
  		lock_is_write_held = false;
6da2ec560   Kees Cook   treewide: kmalloc...
880
881
882
  		cxt.lwsa = kmalloc_array(cxt.nrealwriters_stress,
  					 sizeof(*cxt.lwsa),
  					 GFP_KERNEL);
2ce77d16d   Davidlohr Bueso   locking/locktortu...
883
884
885
886
887
  		if (cxt.lwsa == NULL) {
  			VERBOSE_TOROUT_STRING("cxt.lwsa: Out of memory");
  			firsterr = -ENOMEM;
  			goto unwind;
  		}
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
888

2ce77d16d   Davidlohr Bueso   locking/locktortu...
889
890
891
892
  		for (i = 0; i < cxt.nrealwriters_stress; i++) {
  			cxt.lwsa[i].n_lock_fail = 0;
  			cxt.lwsa[i].n_lock_acquired = 0;
  		}
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
893
  	}
630952c22   Davidlohr Bueso   locktorture: Intr...
894
  	if (cxt.cur_ops->readlock) {
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
895
  		if (nreaders_stress >= 0)
630952c22   Davidlohr Bueso   locktorture: Intr...
896
  			cxt.nrealreaders_stress = nreaders_stress;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
897
898
899
900
901
902
903
  		else {
  			/*
  			 * By default distribute evenly the number of
  			 * readers and writers. We still run the same number
  			 * of threads as the writer-only locks default.
  			 */
  			if (nwriters_stress < 0) /* user doesn't care */
630952c22   Davidlohr Bueso   locktorture: Intr...
904
905
  				cxt.nrealwriters_stress = num_online_cpus();
  			cxt.nrealreaders_stress = cxt.nrealwriters_stress;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
906
  		}
2ce77d16d   Davidlohr Bueso   locking/locktortu...
907
  		if (nreaders_stress) {
d02c6b52d   Zou Wei   locktorture: Use ...
908
  			lock_is_read_held = false;
6da2ec560   Kees Cook   treewide: kmalloc...
909
910
911
  			cxt.lrsa = kmalloc_array(cxt.nrealreaders_stress,
  						 sizeof(*cxt.lrsa),
  						 GFP_KERNEL);
2ce77d16d   Davidlohr Bueso   locking/locktortu...
912
913
914
915
916
917
918
919
920
921
922
923
  			if (cxt.lrsa == NULL) {
  				VERBOSE_TOROUT_STRING("cxt.lrsa: Out of memory");
  				firsterr = -ENOMEM;
  				kfree(cxt.lwsa);
  				cxt.lwsa = NULL;
  				goto unwind;
  			}
  
  			for (i = 0; i < cxt.nrealreaders_stress; i++) {
  				cxt.lrsa[i].n_lock_fail = 0;
  				cxt.lrsa[i].n_lock_acquired = 0;
  			}
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
924
925
  		}
  	}
c1c33b92d   Davidlohr Bueso   locking/locktortu...
926

630952c22   Davidlohr Bueso   locktorture: Intr...
927
  	lock_torture_print_module_parms(cxt.cur_ops, "Start of test");
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
928
929
  
  	/* Prepare torture context. */
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
930
931
  	if (onoff_interval > 0) {
  		firsterr = torture_onoff_init(onoff_holdoff * HZ,
3a6cb58f1   Paul E. McKenney   rcutorture: Add g...
932
  					      onoff_interval * HZ, NULL);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
  		if (firsterr)
  			goto unwind;
  	}
  	if (shuffle_interval > 0) {
  		firsterr = torture_shuffle_init(shuffle_interval);
  		if (firsterr)
  			goto unwind;
  	}
  	if (shutdown_secs > 0) {
  		firsterr = torture_shutdown_init(shutdown_secs,
  						 lock_torture_cleanup);
  		if (firsterr)
  			goto unwind;
  	}
  	if (stutter > 0) {
ff3bf92d9   Paul E. McKenney   torture: Allow in...
948
  		firsterr = torture_stutter_init(stutter, stutter);
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
949
950
951
  		if (firsterr)
  			goto unwind;
  	}
2ce77d16d   Davidlohr Bueso   locking/locktortu...
952
  	if (nwriters_stress) {
6396bb221   Kees Cook   treewide: kzalloc...
953
954
  		writer_tasks = kcalloc(cxt.nrealwriters_stress,
  				       sizeof(writer_tasks[0]),
2ce77d16d   Davidlohr Bueso   locking/locktortu...
955
956
957
958
959
960
  				       GFP_KERNEL);
  		if (writer_tasks == NULL) {
  			VERBOSE_TOROUT_ERRSTRING("writer_tasks: Out of memory");
  			firsterr = -ENOMEM;
  			goto unwind;
  		}
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
961
  	}
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
962

630952c22   Davidlohr Bueso   locktorture: Intr...
963
  	if (cxt.cur_ops->readlock) {
6396bb221   Kees Cook   treewide: kzalloc...
964
965
  		reader_tasks = kcalloc(cxt.nrealreaders_stress,
  				       sizeof(reader_tasks[0]),
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
966
967
968
  				       GFP_KERNEL);
  		if (reader_tasks == NULL) {
  			VERBOSE_TOROUT_ERRSTRING("reader_tasks: Out of memory");
f4dbba591   Yang Shi   locktorture: Fix ...
969
970
  			kfree(writer_tasks);
  			writer_tasks = NULL;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
971
972
973
974
975
976
977
978
979
980
981
982
983
  			firsterr = -ENOMEM;
  			goto unwind;
  		}
  	}
  
  	/*
  	 * Create the kthreads and start torturing (oh, those poor little locks).
  	 *
  	 * TODO: Note that we interleave writers with readers, giving writers a
  	 * slight advantage, by creating its kthread first. This can be modified
  	 * for very specific needs, or even let the user choose the policy, if
  	 * ever wanted.
  	 */
630952c22   Davidlohr Bueso   locktorture: Intr...
984
985
986
  	for (i = 0, j = 0; i < cxt.nrealwriters_stress ||
  		    j < cxt.nrealreaders_stress; i++, j++) {
  		if (i >= cxt.nrealwriters_stress)
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
987
988
989
  			goto create_reader;
  
  		/* Create writer. */
630952c22   Davidlohr Bueso   locktorture: Intr...
990
  		firsterr = torture_create_kthread(lock_torture_writer, &cxt.lwsa[i],
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
991
992
993
  						  writer_tasks[i]);
  		if (firsterr)
  			goto unwind;
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
994
995
  
  	create_reader:
630952c22   Davidlohr Bueso   locktorture: Intr...
996
  		if (cxt.cur_ops->readlock == NULL || (j >= cxt.nrealreaders_stress))
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
997
998
  			continue;
  		/* Create reader. */
630952c22   Davidlohr Bueso   locktorture: Intr...
999
  		firsterr = torture_create_kthread(lock_torture_reader, &cxt.lrsa[j],
4f6332c1d   Davidlohr Bueso   locktorture: Add ...
1000
1001
1002
  						  reader_tasks[j]);
  		if (firsterr)
  			goto unwind;
0af3fe1ef   Paul E. McKenney   locktorture: Add ...
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
  	}
  	if (stat_interval > 0) {
  		firsterr = torture_create_kthread(lock_torture_stats, NULL,
  						  stats_task);
  		if (firsterr)
  			goto unwind;
  	}
  	torture_init_end();
  	return 0;
  
  unwind:
  	torture_init_end();
  	lock_torture_cleanup();
  	return firsterr;
  }
  
  module_init(lock_torture_init);
  module_exit(lock_torture_cleanup);