aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-10-09 02:39:25 -0400
committerIngo Molnar <mingo@kernel.org>2014-10-09 02:39:25 -0400
commitfd19bda491207f66d39aeba93487197a087bc00b (patch)
tree55d7b07835f045144e2d529bb20136486d1b6691
parent62731433591156ece255e23ffd69ea4544b424f1 (diff)
parent3e28e377204badfc3c4119ff2abda473127ee0ff (diff)
Merge branch 'rcu/next' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu into core/rcu
Pull additional commits for locktorture, from Paul E. McKenney. Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--Documentation/locking/locktorture.txt5
-rw-r--r--kernel/locking/locktorture.c141
-rw-r--r--kernel/workqueue.c5
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/CFLIST1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK046
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot1
6 files changed, 140 insertions, 19 deletions
diff --git a/Documentation/locking/locktorture.txt b/Documentation/locking/locktorture.txt
index be715015e0f7..619f2bb136a5 100644
--- a/Documentation/locking/locktorture.txt
+++ b/Documentation/locking/locktorture.txt
@@ -45,6 +45,11 @@ torture_type Type of lock to torture. By default, only spinlocks will
45 o "spin_lock_irq": spin_lock_irq() and spin_unlock_irq() 45 o "spin_lock_irq": spin_lock_irq() and spin_unlock_irq()
46 pairs. 46 pairs.
47 47
48 o "rw_lock": read/write lock() and unlock() rwlock pairs.
49
50 o "rw_lock_irq": read/write lock_irq() and unlock_irq()
51 rwlock pairs.
52
48 o "mutex_lock": mutex_lock() and mutex_unlock() pairs. 53 o "mutex_lock": mutex_lock() and mutex_unlock() pairs.
49 54
50 o "rwsem_lock": read/write down() and up() semaphore pairs. 55 o "rwsem_lock": read/write down() and up() semaphore pairs.
diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
index 540d5dfe1112..ec8cce259779 100644
--- a/kernel/locking/locktorture.c
+++ b/kernel/locking/locktorture.c
@@ -20,31 +20,20 @@
20 * Author: Paul E. McKenney <paulmck@us.ibm.com> 20 * Author: Paul E. McKenney <paulmck@us.ibm.com>
21 * Based on kernel/rcu/torture.c. 21 * Based on kernel/rcu/torture.c.
22 */ 22 */
23#include <linux/types.h>
24#include <linux/kernel.h> 23#include <linux/kernel.h>
25#include <linux/init.h>
26#include <linux/module.h> 24#include <linux/module.h>
27#include <linux/kthread.h> 25#include <linux/kthread.h>
28#include <linux/err.h>
29#include <linux/spinlock.h> 26#include <linux/spinlock.h>
27#include <linux/rwlock.h>
30#include <linux/mutex.h> 28#include <linux/mutex.h>
29#include <linux/rwsem.h>
31#include <linux/smp.h> 30#include <linux/smp.h>
32#include <linux/interrupt.h> 31#include <linux/interrupt.h>
33#include <linux/sched.h> 32#include <linux/sched.h>
34#include <linux/atomic.h> 33#include <linux/atomic.h>
35#include <linux/bitops.h>
36#include <linux/completion.h>
37#include <linux/moduleparam.h> 34#include <linux/moduleparam.h>
38#include <linux/percpu.h>
39#include <linux/notifier.h>
40#include <linux/reboot.h>
41#include <linux/freezer.h>
42#include <linux/cpu.h>
43#include <linux/delay.h> 35#include <linux/delay.h>
44#include <linux/stat.h>
45#include <linux/slab.h> 36#include <linux/slab.h>
46#include <linux/trace_clock.h>
47#include <asm/byteorder.h>
48#include <linux/torture.h> 37#include <linux/torture.h>
49 38
50MODULE_LICENSE("GPL"); 39MODULE_LICENSE("GPL");
@@ -204,7 +193,7 @@ static struct lock_torture_ops spin_lock_ops = {
204}; 193};
205 194
206static int torture_spin_lock_write_lock_irq(void) 195static int torture_spin_lock_write_lock_irq(void)
207__acquires(torture_spinlock_irq) 196__acquires(torture_spinlock)
208{ 197{
209 unsigned long flags; 198 unsigned long flags;
210 199
@@ -229,6 +218,110 @@ static struct lock_torture_ops spin_lock_irq_ops = {
229 .name = "spin_lock_irq" 218 .name = "spin_lock_irq"
230}; 219};
231 220
221static DEFINE_RWLOCK(torture_rwlock);
222
223static int torture_rwlock_write_lock(void) __acquires(torture_rwlock)
224{
225 write_lock(&torture_rwlock);
226 return 0;
227}
228
229static void torture_rwlock_write_delay(struct torture_random_state *trsp)
230{
231 const unsigned long shortdelay_us = 2;
232 const unsigned long longdelay_ms = 100;
233
234 /* We want a short delay mostly to emulate likely code, and
235 * we want a long delay occasionally to force massive contention.
236 */
237 if (!(torture_random(trsp) %
238 (cxt.nrealwriters_stress * 2000 * longdelay_ms)))
239 mdelay(longdelay_ms);
240 else
241 udelay(shortdelay_us);
242}
243
244static void torture_rwlock_write_unlock(void) __releases(torture_rwlock)
245{
246 write_unlock(&torture_rwlock);
247}
248
249static int torture_rwlock_read_lock(void) __acquires(torture_rwlock)
250{
251 read_lock(&torture_rwlock);
252 return 0;
253}
254
255static void torture_rwlock_read_delay(struct torture_random_state *trsp)
256{
257 const unsigned long shortdelay_us = 10;
258 const unsigned long longdelay_ms = 100;
259
260 /* We want a short delay mostly to emulate likely code, and
261 * we want a long delay occasionally to force massive contention.
262 */
263 if (!(torture_random(trsp) %
264 (cxt.nrealreaders_stress * 2000 * longdelay_ms)))
265 mdelay(longdelay_ms);
266 else
267 udelay(shortdelay_us);
268}
269
270static void torture_rwlock_read_unlock(void) __releases(torture_rwlock)
271{
272 read_unlock(&torture_rwlock);
273}
274
275static struct lock_torture_ops rw_lock_ops = {
276 .writelock = torture_rwlock_write_lock,
277 .write_delay = torture_rwlock_write_delay,
278 .writeunlock = torture_rwlock_write_unlock,
279 .readlock = torture_rwlock_read_lock,
280 .read_delay = torture_rwlock_read_delay,
281 .readunlock = torture_rwlock_read_unlock,
282 .name = "rw_lock"
283};
284
285static int torture_rwlock_write_lock_irq(void) __acquires(torture_rwlock)
286{
287 unsigned long flags;
288
289 write_lock_irqsave(&torture_rwlock, flags);
290 cxt.cur_ops->flags = flags;
291 return 0;
292}
293
294static void torture_rwlock_write_unlock_irq(void)
295__releases(torture_rwlock)
296{
297 write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags);
298}
299
300static int torture_rwlock_read_lock_irq(void) __acquires(torture_rwlock)
301{
302 unsigned long flags;
303
304 read_lock_irqsave(&torture_rwlock, flags);
305 cxt.cur_ops->flags = flags;
306 return 0;
307}
308
309static void torture_rwlock_read_unlock_irq(void)
310__releases(torture_rwlock)
311{
312 write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags);
313}
314
315static struct lock_torture_ops rw_lock_irq_ops = {
316 .writelock = torture_rwlock_write_lock_irq,
317 .write_delay = torture_rwlock_write_delay,
318 .writeunlock = torture_rwlock_write_unlock_irq,
319 .readlock = torture_rwlock_read_lock_irq,
320 .read_delay = torture_rwlock_read_delay,
321 .readunlock = torture_rwlock_read_unlock_irq,
322 .name = "rw_lock_irq"
323};
324
232static DEFINE_MUTEX(torture_mutex); 325static DEFINE_MUTEX(torture_mutex);
233 326
234static int torture_mutex_lock(void) __acquires(torture_mutex) 327static int torture_mutex_lock(void) __acquires(torture_mutex)
@@ -348,14 +441,19 @@ static int lock_torture_writer(void *arg)
348 do { 441 do {
349 if ((torture_random(&rand) & 0xfffff) == 0) 442 if ((torture_random(&rand) & 0xfffff) == 0)
350 schedule_timeout_uninterruptible(1); 443 schedule_timeout_uninterruptible(1);
444
351 cxt.cur_ops->writelock(); 445 cxt.cur_ops->writelock();
352 if (WARN_ON_ONCE(lock_is_write_held)) 446 if (WARN_ON_ONCE(lock_is_write_held))
353 lwsp->n_lock_fail++; 447 lwsp->n_lock_fail++;
354 lock_is_write_held = 1; 448 lock_is_write_held = 1;
449 if (WARN_ON_ONCE(lock_is_read_held))
450 lwsp->n_lock_fail++; /* rare, but... */
451
355 lwsp->n_lock_acquired++; 452 lwsp->n_lock_acquired++;
356 cxt.cur_ops->write_delay(&rand); 453 cxt.cur_ops->write_delay(&rand);
357 lock_is_write_held = 0; 454 lock_is_write_held = 0;
358 cxt.cur_ops->writeunlock(); 455 cxt.cur_ops->writeunlock();
456
359 stutter_wait("lock_torture_writer"); 457 stutter_wait("lock_torture_writer");
360 } while (!torture_must_stop()); 458 } while (!torture_must_stop());
361 torture_kthread_stopping("lock_torture_writer"); 459 torture_kthread_stopping("lock_torture_writer");
@@ -377,12 +475,17 @@ static int lock_torture_reader(void *arg)
377 do { 475 do {
378 if ((torture_random(&rand) & 0xfffff) == 0) 476 if ((torture_random(&rand) & 0xfffff) == 0)
379 schedule_timeout_uninterruptible(1); 477 schedule_timeout_uninterruptible(1);
478
380 cxt.cur_ops->readlock(); 479 cxt.cur_ops->readlock();
381 lock_is_read_held = 1; 480 lock_is_read_held = 1;
481 if (WARN_ON_ONCE(lock_is_write_held))
482 lrsp->n_lock_fail++; /* rare, but... */
483
382 lrsp->n_lock_acquired++; 484 lrsp->n_lock_acquired++;
383 cxt.cur_ops->read_delay(&rand); 485 cxt.cur_ops->read_delay(&rand);
384 lock_is_read_held = 0; 486 lock_is_read_held = 0;
385 cxt.cur_ops->readunlock(); 487 cxt.cur_ops->readunlock();
488
386 stutter_wait("lock_torture_reader"); 489 stutter_wait("lock_torture_reader");
387 } while (!torture_must_stop()); 490 } while (!torture_must_stop());
388 torture_kthread_stopping("lock_torture_reader"); 491 torture_kthread_stopping("lock_torture_reader");
@@ -535,8 +638,11 @@ static int __init lock_torture_init(void)
535 int i, j; 638 int i, j;
536 int firsterr = 0; 639 int firsterr = 0;
537 static struct lock_torture_ops *torture_ops[] = { 640 static struct lock_torture_ops *torture_ops[] = {
538 &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops, 641 &lock_busted_ops,
539 &mutex_lock_ops, &rwsem_lock_ops, 642 &spin_lock_ops, &spin_lock_irq_ops,
643 &rw_lock_ops, &rw_lock_irq_ops,
644 &mutex_lock_ops,
645 &rwsem_lock_ops,
540 }; 646 };
541 647
542 if (!torture_init_begin(torture_type, verbose, &torture_runnable)) 648 if (!torture_init_begin(torture_type, verbose, &torture_runnable))
@@ -571,7 +677,8 @@ static int __init lock_torture_init(void)
571 cxt.debug_lock = true; 677 cxt.debug_lock = true;
572#endif 678#endif
573#ifdef CONFIG_DEBUG_SPINLOCK 679#ifdef CONFIG_DEBUG_SPINLOCK
574 if (strncmp(torture_type, "spin", 4) == 0) 680 if ((strncmp(torture_type, "spin", 4) == 0) ||
681 (strncmp(torture_type, "rw_lock", 7) == 0))
575 cxt.debug_lock = true; 682 cxt.debug_lock = true;
576#endif 683#endif
577 684
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 5dbe22aa3efd..09b685daee3d 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -2043,9 +2043,10 @@ __acquires(&pool->lock)
2043 * kernels, where a requeueing work item waiting for something to 2043 * kernels, where a requeueing work item waiting for something to
2044 * happen could deadlock with stop_machine as such work item could 2044 * happen could deadlock with stop_machine as such work item could
2045 * indefinitely requeue itself while all other CPUs are trapped in 2045 * indefinitely requeue itself while all other CPUs are trapped in
2046 * stop_machine. 2046 * stop_machine. At the same time, report a quiescent RCU state so
2047 * the same condition doesn't freeze RCU.
2047 */ 2048 */
2048 cond_resched(); 2049 cond_resched_rcu_qs();
2049 2050
2050 spin_lock_irq(&pool->lock); 2051 spin_lock_irq(&pool->lock);
2051 2052
diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFLIST b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
index 6108137da770..6910b7370761 100644
--- a/tools/testing/selftests/rcutorture/configs/lock/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
@@ -1,3 +1,4 @@
1LOCK01 1LOCK01
2LOCK02 2LOCK02
3LOCK03 3LOCK03
4LOCK04 \ No newline at end of file
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK04 b/tools/testing/selftests/rcutorture/configs/lock/LOCK04
new file mode 100644
index 000000000000..1d1da1477fc3
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK04
@@ -0,0 +1,6 @@
1CONFIG_SMP=y
2CONFIG_NR_CPUS=4
3CONFIG_HOTPLUG_CPU=y
4CONFIG_PREEMPT_NONE=n
5CONFIG_PREEMPT_VOLUNTARY=n
6CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot
new file mode 100644
index 000000000000..48c04fe47fb4
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot
@@ -0,0 +1 @@
locktorture.torture_type=rw_lock