Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'locktorture.2023.04.04a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu

Pull locktorture updates from Paul McKenney:
"This adds tests for nested locking and also adds support for testing
raw spinlocks in PREEMPT_RT kernels"

* tag 'locktorture.2023.04.04a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu:
locktorture: Add raw_spinlock* torture tests for PREEMPT_RT kernels
locktorture: With nested locks, occasionally skip main lock
locktorture: Add nested locking to rtmutex torture tests
locktorture: Add nested locking to mutex torture tests
locktorture: Add nested_[un]lock() hooks and nlocks parameter

+188 -16
+172 -16
kernel/locking/locktorture.c
··· 51 51 torture_param(int, rt_boost_factor, 50, "A factor determining how often rt-boost happens."); 52 52 torture_param(int, verbose, 1, 53 53 "Enable verbose debugging printk()s"); 54 + torture_param(int, nested_locks, 0, "Number of nested locks (max = 8)"); 55 + /* Going much higher trips "BUG: MAX_LOCKDEP_CHAIN_HLOCKS too low!" errors */ 56 + #define MAX_NESTED_LOCKS 8 54 57 55 - static char *torture_type = "spin_lock"; 58 + static char *torture_type = IS_ENABLED(CONFIG_PREEMPT_RT) ? "raw_spin_lock" : "spin_lock"; 56 59 module_param(torture_type, charp, 0444); 57 60 MODULE_PARM_DESC(torture_type, 58 61 "Type of lock to torture (spin_lock, spin_lock_irq, mutex_lock, ...)"); ··· 82 79 struct lock_torture_ops { 83 80 void (*init)(void); 84 81 void (*exit)(void); 82 + int (*nested_lock)(int tid, u32 lockset); 85 83 int (*writelock)(int tid); 86 84 void (*write_delay)(struct torture_random_state *trsp); 87 85 void (*task_boost)(struct torture_random_state *trsp); 88 86 void (*writeunlock)(int tid); 87 + void (*nested_unlock)(int tid, u32 lockset); 89 88 int (*readlock)(int tid); 90 89 void (*read_delay)(struct torture_random_state *trsp); 91 90 void (*readunlock)(int tid); ··· 257 252 .name = "spin_lock_irq" 258 253 }; 259 254 255 + static DEFINE_RAW_SPINLOCK(torture_raw_spinlock); 256 + 257 + static int torture_raw_spin_lock_write_lock(int tid __maybe_unused) 258 + __acquires(torture_raw_spinlock) 259 + { 260 + raw_spin_lock(&torture_raw_spinlock); 261 + return 0; 262 + } 263 + 264 + static void torture_raw_spin_lock_write_unlock(int tid __maybe_unused) 265 + __releases(torture_raw_spinlock) 266 + { 267 + raw_spin_unlock(&torture_raw_spinlock); 268 + } 269 + 270 + static struct lock_torture_ops raw_spin_lock_ops = { 271 + .writelock = torture_raw_spin_lock_write_lock, 272 + .write_delay = torture_spin_lock_write_delay, 273 + .task_boost = torture_rt_boost, 274 + .writeunlock = torture_raw_spin_lock_write_unlock, 275 + .readlock = NULL, 276 + .read_delay = NULL, 277 + .readunlock = NULL, 278 + .name = "raw_spin_lock" 279 + }; 280 + 281 + static int torture_raw_spin_lock_write_lock_irq(int tid __maybe_unused) 282 + __acquires(torture_raw_spinlock) 283 + { 284 + unsigned long flags; 285 + 286 + raw_spin_lock_irqsave(&torture_raw_spinlock, flags); 287 + cxt.cur_ops->flags = flags; 288 + return 0; 289 + } 290 + 291 + static void torture_raw_spin_lock_write_unlock_irq(int tid __maybe_unused) 292 + __releases(torture_raw_spinlock) 293 + { 294 + raw_spin_unlock_irqrestore(&torture_raw_spinlock, cxt.cur_ops->flags); 295 + } 296 + 297 + static struct lock_torture_ops raw_spin_lock_irq_ops = { 298 + .writelock = torture_raw_spin_lock_write_lock_irq, 299 + .write_delay = torture_spin_lock_write_delay, 300 + .task_boost = torture_rt_boost, 301 + .writeunlock = torture_raw_spin_lock_write_unlock_irq, 302 + .readlock = NULL, 303 + .read_delay = NULL, 304 + .readunlock = NULL, 305 + .name = "raw_spin_lock_irq" 306 + }; 307 + 260 308 static DEFINE_RWLOCK(torture_rwlock); 261 309 262 310 static int torture_rwlock_write_lock(int tid __maybe_unused) ··· 423 365 }; 424 366 425 367 static DEFINE_MUTEX(torture_mutex); 368 + static struct mutex torture_nested_mutexes[MAX_NESTED_LOCKS]; 369 + static struct lock_class_key nested_mutex_keys[MAX_NESTED_LOCKS]; 370 + 371 + static void torture_mutex_init(void) 372 + { 373 + int i; 374 + 375 + for (i = 0; i < MAX_NESTED_LOCKS; i++) 376 + __mutex_init(&torture_nested_mutexes[i], __func__, 377 + &nested_mutex_keys[i]); 378 + } 379 + 380 + static int torture_mutex_nested_lock(int tid __maybe_unused, 381 + u32 lockset) 382 + { 383 + int i; 384 + 385 + for (i = 0; i < nested_locks; i++) 386 + if (lockset & (1 << i)) 387 + mutex_lock(&torture_nested_mutexes[i]); 388 + return 0; 389 + } 426 390 427 391 static int torture_mutex_lock(int tid __maybe_unused) 428 392 __acquires(torture_mutex) ··· 473 393 mutex_unlock(&torture_mutex); 474 394 } 475 395 396 + static void torture_mutex_nested_unlock(int tid __maybe_unused, 397 + u32 lockset) 398 + { 399 + int i; 400 + 401 + for (i = nested_locks - 1; i >= 0; i--) 402 + if (lockset & (1 << i)) 403 + mutex_unlock(&torture_nested_mutexes[i]); 404 + } 405 + 476 406 static struct lock_torture_ops mutex_lock_ops = { 407 + .init = torture_mutex_init, 408 + .nested_lock = torture_mutex_nested_lock, 477 409 .writelock = torture_mutex_lock, 478 410 .write_delay = torture_mutex_delay, 479 411 .task_boost = torture_rt_boost, 480 412 .writeunlock = torture_mutex_unlock, 413 + .nested_unlock = torture_mutex_nested_unlock, 481 414 .readlock = NULL, 482 415 .read_delay = NULL, 483 416 .readunlock = NULL, ··· 597 504 598 505 #ifdef CONFIG_RT_MUTEXES 599 506 static DEFINE_RT_MUTEX(torture_rtmutex); 507 + static struct rt_mutex torture_nested_rtmutexes[MAX_NESTED_LOCKS]; 508 + static struct lock_class_key nested_rtmutex_keys[MAX_NESTED_LOCKS]; 509 + 510 + static void torture_rtmutex_init(void) 511 + { 512 + int i; 513 + 514 + for (i = 0; i < MAX_NESTED_LOCKS; i++) 515 + __rt_mutex_init(&torture_nested_rtmutexes[i], __func__, 516 + &nested_rtmutex_keys[i]); 517 + } 518 + 519 + static int torture_rtmutex_nested_lock(int tid __maybe_unused, 520 + u32 lockset) 521 + { 522 + int i; 523 + 524 + for (i = 0; i < nested_locks; i++) 525 + if (lockset & (1 << i)) 526 + rt_mutex_lock(&torture_nested_rtmutexes[i]); 527 + return 0; 528 + } 600 529 601 530 static int torture_rtmutex_lock(int tid __maybe_unused) 602 531 __acquires(torture_rtmutex) ··· 660 545 __torture_rt_boost(trsp); 661 546 } 662 547 548 + static void torture_rtmutex_nested_unlock(int tid __maybe_unused, 549 + u32 lockset) 550 + { 551 + int i; 552 + 553 + for (i = nested_locks - 1; i >= 0; i--) 554 + if (lockset & (1 << i)) 555 + rt_mutex_unlock(&torture_nested_rtmutexes[i]); 556 + } 557 + 663 558 static struct lock_torture_ops rtmutex_lock_ops = { 559 + .init = torture_rtmutex_init, 560 + .nested_lock = torture_rtmutex_nested_lock, 664 561 .writelock = torture_rtmutex_lock, 665 562 .write_delay = torture_rtmutex_delay, 666 563 .task_boost = torture_rt_boost_rtmutex, 667 564 .writeunlock = torture_rtmutex_unlock, 565 + .nested_unlock = torture_rtmutex_nested_unlock, 668 566 .readlock = NULL, 669 567 .read_delay = NULL, 670 568 .readunlock = NULL, ··· 812 684 struct lock_stress_stats *lwsp = arg; 813 685 int tid = lwsp - cxt.lwsa; 814 686 DEFINE_TORTURE_RANDOM(rand); 687 + u32 lockset_mask; 688 + bool skip_main_lock; 815 689 816 690 VERBOSE_TOROUT_STRING("lock_torture_writer task started"); 817 691 set_user_nice(current, MAX_NICE); ··· 822 692 if ((torture_random(&rand) & 0xfffff) == 0) 823 693 schedule_timeout_uninterruptible(1); 824 694 825 - cxt.cur_ops->task_boost(&rand); 826 - cxt.cur_ops->writelock(tid); 827 - if (WARN_ON_ONCE(lock_is_write_held)) 828 - lwsp->n_lock_fail++; 829 - lock_is_write_held = true; 830 - if (WARN_ON_ONCE(atomic_read(&lock_is_read_held))) 831 - lwsp->n_lock_fail++; /* rare, but... */ 695 + lockset_mask = torture_random(&rand); 696 + /* 697 + * When using nested_locks, we want to occasionally 698 + * skip the main lock so we can avoid always serializing 699 + * the lock chains on that central lock. By skipping the 700 + * main lock occasionally, we can create different 701 + * contention patterns (allowing for multiple disjoint 702 + * blocked trees) 703 + */ 704 + skip_main_lock = (nested_locks && 705 + !(torture_random(&rand) % 100)); 832 706 833 - lwsp->n_lock_acquired++; 707 + cxt.cur_ops->task_boost(&rand); 708 + if (cxt.cur_ops->nested_lock) 709 + cxt.cur_ops->nested_lock(tid, lockset_mask); 710 + 711 + if (!skip_main_lock) { 712 + cxt.cur_ops->writelock(tid); 713 + if (WARN_ON_ONCE(lock_is_write_held)) 714 + lwsp->n_lock_fail++; 715 + lock_is_write_held = true; 716 + if (WARN_ON_ONCE(atomic_read(&lock_is_read_held))) 717 + lwsp->n_lock_fail++; /* rare, but... */ 718 + 719 + lwsp->n_lock_acquired++; 720 + } 834 721 cxt.cur_ops->write_delay(&rand); 835 - lock_is_write_held = false; 836 - WRITE_ONCE(last_lock_release, jiffies); 837 - cxt.cur_ops->writeunlock(tid); 722 + if (!skip_main_lock) { 723 + lock_is_write_held = false; 724 + WRITE_ONCE(last_lock_release, jiffies); 725 + cxt.cur_ops->writeunlock(tid); 726 + } 727 + if (cxt.cur_ops->nested_unlock) 728 + cxt.cur_ops->nested_unlock(tid, lockset_mask); 838 729 839 730 stutter_wait("lock_torture_writer"); 840 731 } while (!torture_must_stop()); ··· 996 845 const char *tag) 997 846 { 998 847 pr_alert("%s" TORTURE_FLAG 999 - "--- %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\n", 848 + "--- %s%s: nwriters_stress=%d nreaders_stress=%d nested_locks=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d\n", 1000 849 torture_type, tag, cxt.debug_lock ? " [debug]": "", 1001 - cxt.nrealwriters_stress, cxt.nrealreaders_stress, stat_interval, 1002 - verbose, shuffle_interval, stutter, shutdown_secs, 1003 - onoff_interval, onoff_holdoff); 850 + cxt.nrealwriters_stress, cxt.nrealreaders_stress, 851 + nested_locks, stat_interval, verbose, shuffle_interval, 852 + stutter, shutdown_secs, onoff_interval, onoff_holdoff); 1004 853 } 1005 854 1006 855 static void lock_torture_cleanup(void) ··· 1070 919 static struct lock_torture_ops *torture_ops[] = { 1071 920 &lock_busted_ops, 1072 921 &spin_lock_ops, &spin_lock_irq_ops, 922 + &raw_spin_lock_ops, &raw_spin_lock_irq_ops, 1073 923 &rw_lock_ops, &rw_lock_irq_ops, 1074 924 &mutex_lock_ops, 1075 925 &ww_mutex_lock_ops, ··· 1219 1067 goto unwind; 1220 1068 } 1221 1069 } 1070 + 1071 + /* cap nested_locks to MAX_NESTED_LOCKS */ 1072 + if (nested_locks > MAX_NESTED_LOCKS) 1073 + nested_locks = MAX_NESTED_LOCKS; 1222 1074 1223 1075 if (cxt.cur_ops->readlock) { 1224 1076 reader_tasks = kcalloc(cxt.nrealreaders_stress,
+2
tools/testing/selftests/rcutorture/configs/lock/CFLIST
··· 5 5 LOCK05 6 6 LOCK06 7 7 LOCK07 8 + LOCK08 9 + LOCK09
+6
tools/testing/selftests/rcutorture/configs/lock/LOCK08
··· 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
+1
tools/testing/selftests/rcutorture/configs/lock/LOCK08.boot
··· 1 + locktorture.torture_type=mutex_lock locktorture.nested_locks=8
+6
tools/testing/selftests/rcutorture/configs/lock/LOCK09
··· 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
+1
tools/testing/selftests/rcutorture/configs/lock/LOCK09.boot
··· 1 + locktorture.torture_type=rtmutex_lock locktorture.nested_locks=8