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

Configure Feed

Select the types of activity you want to include in your feed.

rcutorture: Add a textbook-style trivial preemptible RCU

This commit adds a trivial textbook implementation of preemptible RCU
to rcutorture ("torture_type=trivial-preempt"), similar in spirit to the
existing "torture_type=trivial" textbook implementation of non-preemptible
RCU. Neither trivial RCU implementation has any value for production use,
and are intended only to keep Paul honest in his introductory writings
and presentations.

[ paulmck: Apply kernel test robot feedback. ]

Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>

authored by

Paul E. McKenney and committed by
Joel Fernandes
c6f4e552 7aaa8047

+112 -1
+4
include/linux/sched.h
··· 949 949 struct srcu_ctr __percpu *trc_reader_scp; 950 950 #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */ 951 951 952 + #ifdef CONFIG_TRIVIAL_PREEMPT_RCU 953 + int rcu_trivial_preempt_nesting; 954 + #endif /* #ifdef CONFIG_TRIVIAL_PREEMPT_RCU */ 955 + 952 956 struct sched_info sched_info; 953 957 954 958 struct list_head tasks;
+11
kernel/rcu/Kconfig.debug
··· 228 228 229 229 This has no value for production and is only for testing. 230 230 231 + config TRIVIAL_PREEMPT_RCU 232 + bool "Textbook trivial preemptible RCU in rcutorture" 233 + depends on RCU_EXPERT && RCU_TORTURE_TEST 234 + default n 235 + help 236 + This option enables a textbook preemptible RCU that is 237 + implemented in rcutorture. Its sole purpose is to validate 238 + code used in books, papers, and presentations. 239 + 240 + This has no value for production and is only for testing. 241 + 231 242 endmenu # "RCU Debugging"
+4
kernel/rcu/rcu.h
··· 691 691 static inline int rcu_stall_notifier_call_chain(unsigned long val, void *v) { return NOTIFY_DONE; } 692 692 #endif // #else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER) 693 693 694 + #ifdef CONFIG_TRIVIAL_PREEMPT_RCU 695 + void synchronize_rcu_trivial_preempt(void); 696 + #endif // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU 697 + 694 698 #endif /* __LINUX_RCU_H */
+56 -1
kernel/rcu/rcutorture.c
··· 1061 1061 .name = "trivial" 1062 1062 }; 1063 1063 1064 + #ifdef CONFIG_TRIVIAL_PREEMPT_RCU 1065 + 1066 + /* 1067 + * Definitions for trivial CONFIG_PREEMPT=y torture testing. This 1068 + * implementation does not work well with large numbers of tasks or with 1069 + * long-term preemption. Either or both get you RCU CPU stall warnings. 1070 + */ 1071 + 1072 + static void rcu_sync_torture_init_trivial_preempt(void) 1073 + { 1074 + rcu_sync_torture_init(); 1075 + if (WARN_ONCE(onoff_interval || shuffle_interval, "%s: Non-zero onoff_interval (%d) or shuffle_interval (%d) breaks trivial RCU, resetting to zero", __func__, onoff_interval, shuffle_interval)) { 1076 + onoff_interval = 0; 1077 + shuffle_interval = 0; 1078 + } 1079 + } 1080 + 1081 + static int rcu_torture_read_lock_trivial_preempt(void) 1082 + { 1083 + struct task_struct *t = current; 1084 + 1085 + WRITE_ONCE(t->rcu_trivial_preempt_nesting, t->rcu_trivial_preempt_nesting + 1); 1086 + smp_mb(); 1087 + return 0; 1088 + } 1089 + 1090 + static void rcu_torture_read_unlock_trivial_preempt(int idx) 1091 + { 1092 + struct task_struct *t = current; 1093 + 1094 + smp_store_release(&t->rcu_trivial_preempt_nesting, t->rcu_trivial_preempt_nesting - 1); 1095 + } 1096 + 1097 + static struct rcu_torture_ops trivial_preempt_ops = { 1098 + .ttype = RCU_TRIVIAL_FLAVOR, 1099 + .init = rcu_sync_torture_init_trivial_preempt, 1100 + .readlock = rcu_torture_read_lock_trivial_preempt, 1101 + .read_delay = rcu_read_delay, // just reuse rcu's version. 1102 + .readunlock = rcu_torture_read_unlock_trivial_preempt, 1103 + .readlock_held = torture_readlock_not_held, 1104 + .get_gp_seq = rcu_no_completed, 1105 + .sync = synchronize_rcu_trivial_preempt, 1106 + .exp_sync = synchronize_rcu_trivial_preempt, 1107 + .irq_capable = 0, // In theory it should be, but let's keep it trivial. 1108 + .name = "trivial-preempt" 1109 + }; 1110 + 1111 + #define TRIVIAL_PREEMPT_OPS &trivial_preempt_ops, 1112 + 1113 + #else // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU 1114 + 1115 + #define TRIVIAL_PREEMPT_OPS 1116 + 1117 + #endif // #else // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU 1118 + 1064 1119 #ifdef CONFIG_TASKS_RCU 1065 1120 1066 1121 /* ··· 4504 4449 static struct rcu_torture_ops *torture_ops[] = { 4505 4450 &rcu_ops, &rcu_busted_ops, &srcu_ops, &srcud_ops, &busted_srcud_ops, 4506 4451 TASKS_OPS TASKS_RUDE_OPS TASKS_TRACING_OPS 4507 - &trivial_ops, 4452 + &trivial_ops, TRIVIAL_PREEMPT_OPS 4508 4453 }; 4509 4454 4510 4455 if (!torture_init_begin(torture_type, verbose))
+22
kernel/rcu/update.c
··· 538 538 EXPORT_SYMBOL_GPL(torture_sched_setaffinity); 539 539 #endif 540 540 541 + #if IS_ENABLED(CONFIG_TRIVIAL_PREEMPT_RCU) 542 + // Trivial and stupid grace-period wait. Defined here so that lockdep 543 + // kernels can find tasklist_lock. 544 + void synchronize_rcu_trivial_preempt(void) 545 + { 546 + struct task_struct *g; 547 + struct task_struct *t; 548 + 549 + smp_mb(); // Order prior accesses before grace-period start. 550 + rcu_read_lock(); // Protect task list. 551 + for_each_process_thread(g, t) { 552 + if (t == current) 553 + continue; // Don't deadlock on ourselves! 554 + // Order later rcu_read_lock() on other tasks after QS. 555 + while (smp_load_acquire(&t->rcu_trivial_preempt_nesting)) 556 + continue; 557 + } 558 + rcu_read_unlock(); 559 + } 560 + EXPORT_SYMBOL_GPL(synchronize_rcu_trivial_preempt); 561 + #endif // #if IS_ENABLED(CONFIG_TRIVIAL_PREEMPT_RCU) 562 + 541 563 int rcu_cpu_stall_notifiers __read_mostly; // !0 = provide stall notifiers (rarely useful) 542 564 EXPORT_SYMBOL_GPL(rcu_cpu_stall_notifiers); 543 565
+12
tools/testing/selftests/rcutorture/configs/rcu/TRIVIAL-PREEMPT
··· 1 + CONFIG_SMP=y 2 + CONFIG_NR_CPUS=8 3 + CONFIG_PREEMPT_NONE=n 4 + CONFIG_PREEMPT_VOLUNTARY=n 5 + CONFIG_PREEMPT=y 6 + CONFIG_HZ_PERIODIC=n 7 + CONFIG_NO_HZ_IDLE=y 8 + CONFIG_NO_HZ_FULL=n 9 + CONFIG_DEBUG_LOCK_ALLOC=n 10 + CONFIG_DEBUG_OBJECTS_RCU_HEAD=n 11 + CONFIG_RCU_EXPERT=y 12 + CONFIG_TRIVIAL_PREEMPT_RCU=y
+3
tools/testing/selftests/rcutorture/configs/rcu/TRIVIAL-PREEMPT.boot
··· 1 + rcutorture.torture_type=trivial-preempt 2 + rcutorture.onoff_interval=0 3 + rcutorture.shuffle_interval=0