diff options
| author | Davidlohr Bueso <dave@stgolabs.net> | 2014-09-29 09:14:23 -0400 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2014-09-30 03:10:00 -0400 |
| commit | e34191fad8e5d9fe4e76f6d03b5e29e3eae7535a (patch) | |
| tree | bdf4b88a473d2a7c416cf44dc826cb8393cb0b4a | |
| parent | dd56af42bd829c6e770ed69812bd65a04eaeb1e4 (diff) | |
locktorture: Support rwlocks
Add a "rw_lock" torture test to stress kernel rwlocks and their irq
variant. Reader critical regions are 5x longer than writers. As such
a similar ratio of lock acquisitions is seen in the statistics. In the
case of massive contention, both hold the lock for 1/10 of a second.
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
| -rw-r--r-- | Documentation/locking/locktorture.txt | 5 | ||||
| -rw-r--r-- | kernel/locking/locktorture.c | 115 | ||||
| -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 |
5 files changed, 125 insertions, 3 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..0762b25b4110 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/kthread.h> | 27 | #include <linux/kthread.h> |
| 28 | #include <linux/err.h> | 28 | #include <linux/err.h> |
| 29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
| 30 | #include <linux/rwlock.h> | ||
| 30 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
| 31 | #include <linux/smp.h> | 32 | #include <linux/smp.h> |
| 32 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
| @@ -229,6 +230,110 @@ static struct lock_torture_ops spin_lock_irq_ops = { | |||
| 229 | .name = "spin_lock_irq" | 230 | .name = "spin_lock_irq" |
| 230 | }; | 231 | }; |
| 231 | 232 | ||
| 233 | static DEFINE_RWLOCK(torture_rwlock); | ||
| 234 | |||
| 235 | static int torture_rwlock_write_lock(void) __acquires(torture_rwlock) | ||
| 236 | { | ||
| 237 | write_lock(&torture_rwlock); | ||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | static void torture_rwlock_write_delay(struct torture_random_state *trsp) | ||
| 242 | { | ||
| 243 | const unsigned long shortdelay_us = 2; | ||
| 244 | const unsigned long longdelay_ms = 100; | ||
| 245 | |||
| 246 | /* We want a short delay mostly to emulate likely code, and | ||
| 247 | * we want a long delay occasionally to force massive contention. | ||
| 248 | */ | ||
| 249 | if (!(torture_random(trsp) % | ||
| 250 | (cxt.nrealwriters_stress * 2000 * longdelay_ms))) | ||
| 251 | mdelay(longdelay_ms); | ||
| 252 | else | ||
| 253 | udelay(shortdelay_us); | ||
| 254 | } | ||
| 255 | |||
| 256 | static void torture_rwlock_write_unlock(void) __releases(torture_rwlock) | ||
| 257 | { | ||
| 258 | write_unlock(&torture_rwlock); | ||
| 259 | } | ||
| 260 | |||
| 261 | static int torture_rwlock_read_lock(void) __acquires(torture_rwlock) | ||
| 262 | { | ||
| 263 | read_lock(&torture_rwlock); | ||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | static void torture_rwlock_read_delay(struct torture_random_state *trsp) | ||
| 268 | { | ||
| 269 | const unsigned long shortdelay_us = 10; | ||
| 270 | const unsigned long longdelay_ms = 100; | ||
| 271 | |||
| 272 | /* We want a short delay mostly to emulate likely code, and | ||
| 273 | * we want a long delay occasionally to force massive contention. | ||
| 274 | */ | ||
| 275 | if (!(torture_random(trsp) % | ||
| 276 | (cxt.nrealreaders_stress * 2000 * longdelay_ms))) | ||
| 277 | mdelay(longdelay_ms); | ||
| 278 | else | ||
| 279 | udelay(shortdelay_us); | ||
| 280 | } | ||
| 281 | |||
| 282 | static void torture_rwlock_read_unlock(void) __releases(torture_rwlock) | ||
| 283 | { | ||
| 284 | read_unlock(&torture_rwlock); | ||
| 285 | } | ||
| 286 | |||
| 287 | static struct lock_torture_ops rw_lock_ops = { | ||
| 288 | .writelock = torture_rwlock_write_lock, | ||
| 289 | .write_delay = torture_rwlock_write_delay, | ||
| 290 | .writeunlock = torture_rwlock_write_unlock, | ||
| 291 | .readlock = torture_rwlock_read_lock, | ||
| 292 | .read_delay = torture_rwlock_read_delay, | ||
| 293 | .readunlock = torture_rwlock_read_unlock, | ||
| 294 | .name = "rw_lock" | ||
| 295 | }; | ||
| 296 | |||
| 297 | static int torture_rwlock_write_lock_irq(void) __acquires(torture_rwlock) | ||
| 298 | { | ||
| 299 | unsigned long flags; | ||
| 300 | |||
| 301 | write_lock_irqsave(&torture_rwlock, flags); | ||
| 302 | cxt.cur_ops->flags = flags; | ||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | |||
| 306 | static void torture_rwlock_write_unlock_irq(void) | ||
| 307 | __releases(torture_rwlock) | ||
| 308 | { | ||
| 309 | write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags); | ||
| 310 | } | ||
| 311 | |||
| 312 | static int torture_rwlock_read_lock_irq(void) __acquires(torture_rwlock) | ||
| 313 | { | ||
| 314 | unsigned long flags; | ||
| 315 | |||
| 316 | read_lock_irqsave(&torture_rwlock, flags); | ||
| 317 | cxt.cur_ops->flags = flags; | ||
| 318 | return 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | static void torture_rwlock_read_unlock_irq(void) | ||
| 322 | __releases(torture_rwlock) | ||
| 323 | { | ||
| 324 | write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags); | ||
| 325 | } | ||
| 326 | |||
| 327 | static struct lock_torture_ops rw_lock_irq_ops = { | ||
| 328 | .writelock = torture_rwlock_write_lock_irq, | ||
| 329 | .write_delay = torture_rwlock_write_delay, | ||
| 330 | .writeunlock = torture_rwlock_write_unlock_irq, | ||
| 331 | .readlock = torture_rwlock_read_lock_irq, | ||
| 332 | .read_delay = torture_rwlock_read_delay, | ||
| 333 | .readunlock = torture_rwlock_read_unlock_irq, | ||
| 334 | .name = "rw_lock_irq" | ||
| 335 | }; | ||
| 336 | |||
| 232 | static DEFINE_MUTEX(torture_mutex); | 337 | static DEFINE_MUTEX(torture_mutex); |
| 233 | 338 | ||
| 234 | static int torture_mutex_lock(void) __acquires(torture_mutex) | 339 | static int torture_mutex_lock(void) __acquires(torture_mutex) |
| @@ -535,8 +640,11 @@ static int __init lock_torture_init(void) | |||
| 535 | int i, j; | 640 | int i, j; |
| 536 | int firsterr = 0; | 641 | int firsterr = 0; |
| 537 | static struct lock_torture_ops *torture_ops[] = { | 642 | static struct lock_torture_ops *torture_ops[] = { |
| 538 | &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops, | 643 | &lock_busted_ops, |
| 539 | &mutex_lock_ops, &rwsem_lock_ops, | 644 | &spin_lock_ops, &spin_lock_irq_ops, |
| 645 | &rw_lock_ops, &rw_lock_irq_ops, | ||
| 646 | &mutex_lock_ops, | ||
| 647 | &rwsem_lock_ops, | ||
| 540 | }; | 648 | }; |
| 541 | 649 | ||
| 542 | if (!torture_init_begin(torture_type, verbose, &torture_runnable)) | 650 | if (!torture_init_begin(torture_type, verbose, &torture_runnable)) |
| @@ -571,7 +679,8 @@ static int __init lock_torture_init(void) | |||
| 571 | cxt.debug_lock = true; | 679 | cxt.debug_lock = true; |
| 572 | #endif | 680 | #endif |
| 573 | #ifdef CONFIG_DEBUG_SPINLOCK | 681 | #ifdef CONFIG_DEBUG_SPINLOCK |
| 574 | if (strncmp(torture_type, "spin", 4) == 0) | 682 | if ((strncmp(torture_type, "spin", 4) == 0) || |
| 683 | (strncmp(torture_type, "rw_lock", 7) == 0)) | ||
| 575 | cxt.debug_lock = true; | 684 | cxt.debug_lock = true; |
| 576 | #endif | 685 | #endif |
| 577 | 686 | ||
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/too | |||
