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 /kernel | |
| 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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/locking/locktorture.c | 115 |
1 files changed, 112 insertions, 3 deletions
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 | ||
