diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-10-09 02:39:25 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-10-09 02:39:25 -0400 |
commit | fd19bda491207f66d39aeba93487197a087bc00b (patch) | |
tree | 55d7b07835f045144e2d529bb20136486d1b6691 | |
parent | 62731433591156ece255e23ffd69ea4544b424f1 (diff) | |
parent | 3e28e377204badfc3c4119ff2abda473127ee0ff (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.txt | 5 | ||||
-rw-r--r-- | kernel/locking/locktorture.c | 141 | ||||
-rw-r--r-- | kernel/workqueue.c | 5 | ||||
-rw-r--r-- | tools/testing/selftests/rcutorture/configs/lock/CFLIST | 1 | ||||
-rw-r--r-- | tools/testing/selftests/rcutorture/configs/lock/LOCK04 | 6 | ||||
-rw-r--r-- | tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot | 1 |
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 | ||
50 | MODULE_LICENSE("GPL"); | 39 | MODULE_LICENSE("GPL"); |
@@ -204,7 +193,7 @@ static struct lock_torture_ops spin_lock_ops = { | |||
204 | }; | 193 | }; |
205 | 194 | ||
206 | static int torture_spin_lock_write_lock_irq(void) | 195 | static 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 | ||
221 | static DEFINE_RWLOCK(torture_rwlock); | ||
222 | |||
223 | static int torture_rwlock_write_lock(void) __acquires(torture_rwlock) | ||
224 | { | ||
225 | write_lock(&torture_rwlock); | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static 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 | |||
244 | static void torture_rwlock_write_unlock(void) __releases(torture_rwlock) | ||
245 | { | ||
246 | write_unlock(&torture_rwlock); | ||
247 | } | ||
248 | |||
249 | static int torture_rwlock_read_lock(void) __acquires(torture_rwlock) | ||
250 | { | ||
251 | read_lock(&torture_rwlock); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static 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 | |||
270 | static void torture_rwlock_read_unlock(void) __releases(torture_rwlock) | ||
271 | { | ||
272 | read_unlock(&torture_rwlock); | ||
273 | } | ||
274 | |||
275 | static 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 | |||
285 | static 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 | |||
294 | static void torture_rwlock_write_unlock_irq(void) | ||
295 | __releases(torture_rwlock) | ||
296 | { | ||
297 | write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags); | ||
298 | } | ||
299 | |||
300 | static 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 | |||
309 | static void torture_rwlock_read_unlock_irq(void) | ||
310 | __releases(torture_rwlock) | ||
311 | { | ||
312 | write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags); | ||
313 | } | ||
314 | |||
315 | static 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 | |||
232 | static DEFINE_MUTEX(torture_mutex); | 325 | static DEFINE_MUTEX(torture_mutex); |
233 | 326 | ||
234 | static int torture_mutex_lock(void) __acquires(torture_mutex) | 327 | static 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 @@ | |||
1 | LOCK01 | 1 | LOCK01 |
2 | LOCK02 | 2 | LOCK02 |
3 | LOCK03 | 3 | LOCK03 |
4 | LOCK04 \ 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 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=4 | ||
3 | CONFIG_HOTPLUG_CPU=y | ||
4 | CONFIG_PREEMPT_NONE=n | ||
5 | CONFIG_PREEMPT_VOLUNTARY=n | ||
6 | CONFIG_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 | |||