mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 02:01:18 -04:00
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>
This commit is contained in:
committed by
Joel Fernandes
parent
7aaa8047ea
commit
c6f4e552e1
@@ -949,6 +949,10 @@ struct task_struct {
|
||||
struct srcu_ctr __percpu *trc_reader_scp;
|
||||
#endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
|
||||
|
||||
#ifdef CONFIG_TRIVIAL_PREEMPT_RCU
|
||||
int rcu_trivial_preempt_nesting;
|
||||
#endif /* #ifdef CONFIG_TRIVIAL_PREEMPT_RCU */
|
||||
|
||||
struct sched_info sched_info;
|
||||
|
||||
struct list_head tasks;
|
||||
|
||||
@@ -228,4 +228,15 @@ config RCU_DYNTICKS_TORTURE
|
||||
|
||||
This has no value for production and is only for testing.
|
||||
|
||||
config TRIVIAL_PREEMPT_RCU
|
||||
bool "Textbook trivial preemptible RCU in rcutorture"
|
||||
depends on RCU_EXPERT && RCU_TORTURE_TEST
|
||||
default n
|
||||
help
|
||||
This option enables a textbook preemptible RCU that is
|
||||
implemented in rcutorture. Its sole purpose is to validate
|
||||
code used in books, papers, and presentations.
|
||||
|
||||
This has no value for production and is only for testing.
|
||||
|
||||
endmenu # "RCU Debugging"
|
||||
|
||||
@@ -691,4 +691,8 @@ int rcu_stall_notifier_call_chain(unsigned long val, void *v);
|
||||
static inline int rcu_stall_notifier_call_chain(unsigned long val, void *v) { return NOTIFY_DONE; }
|
||||
#endif // #else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
|
||||
|
||||
#ifdef CONFIG_TRIVIAL_PREEMPT_RCU
|
||||
void synchronize_rcu_trivial_preempt(void);
|
||||
#endif // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU
|
||||
|
||||
#endif /* __LINUX_RCU_H */
|
||||
|
||||
@@ -1061,6 +1061,61 @@ static struct rcu_torture_ops trivial_ops = {
|
||||
.name = "trivial"
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TRIVIAL_PREEMPT_RCU
|
||||
|
||||
/*
|
||||
* Definitions for trivial CONFIG_PREEMPT=y torture testing. This
|
||||
* implementation does not work well with large numbers of tasks or with
|
||||
* long-term preemption. Either or both get you RCU CPU stall warnings.
|
||||
*/
|
||||
|
||||
static void rcu_sync_torture_init_trivial_preempt(void)
|
||||
{
|
||||
rcu_sync_torture_init();
|
||||
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)) {
|
||||
onoff_interval = 0;
|
||||
shuffle_interval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int rcu_torture_read_lock_trivial_preempt(void)
|
||||
{
|
||||
struct task_struct *t = current;
|
||||
|
||||
WRITE_ONCE(t->rcu_trivial_preempt_nesting, t->rcu_trivial_preempt_nesting + 1);
|
||||
smp_mb();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcu_torture_read_unlock_trivial_preempt(int idx)
|
||||
{
|
||||
struct task_struct *t = current;
|
||||
|
||||
smp_store_release(&t->rcu_trivial_preempt_nesting, t->rcu_trivial_preempt_nesting - 1);
|
||||
}
|
||||
|
||||
static struct rcu_torture_ops trivial_preempt_ops = {
|
||||
.ttype = RCU_TRIVIAL_FLAVOR,
|
||||
.init = rcu_sync_torture_init_trivial_preempt,
|
||||
.readlock = rcu_torture_read_lock_trivial_preempt,
|
||||
.read_delay = rcu_read_delay, // just reuse rcu's version.
|
||||
.readunlock = rcu_torture_read_unlock_trivial_preempt,
|
||||
.readlock_held = torture_readlock_not_held,
|
||||
.get_gp_seq = rcu_no_completed,
|
||||
.sync = synchronize_rcu_trivial_preempt,
|
||||
.exp_sync = synchronize_rcu_trivial_preempt,
|
||||
.irq_capable = 0, // In theory it should be, but let's keep it trivial.
|
||||
.name = "trivial-preempt"
|
||||
};
|
||||
|
||||
#define TRIVIAL_PREEMPT_OPS &trivial_preempt_ops,
|
||||
|
||||
#else // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU
|
||||
|
||||
#define TRIVIAL_PREEMPT_OPS
|
||||
|
||||
#endif // #else // #ifdef CONFIG_TRIVIAL_PREEMPT_RCU
|
||||
|
||||
#ifdef CONFIG_TASKS_RCU
|
||||
|
||||
/*
|
||||
@@ -4449,7 +4504,7 @@ rcu_torture_init(void)
|
||||
static struct rcu_torture_ops *torture_ops[] = {
|
||||
&rcu_ops, &rcu_busted_ops, &srcu_ops, &srcud_ops, &busted_srcud_ops,
|
||||
TASKS_OPS TASKS_RUDE_OPS TASKS_TRACING_OPS
|
||||
&trivial_ops,
|
||||
&trivial_ops, TRIVIAL_PREEMPT_OPS
|
||||
};
|
||||
|
||||
if (!torture_init_begin(torture_type, verbose))
|
||||
|
||||
@@ -538,6 +538,28 @@ long torture_sched_setaffinity(pid_t pid, const struct cpumask *in_mask, bool do
|
||||
EXPORT_SYMBOL_GPL(torture_sched_setaffinity);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_TRIVIAL_PREEMPT_RCU)
|
||||
// Trivial and stupid grace-period wait. Defined here so that lockdep
|
||||
// kernels can find tasklist_lock.
|
||||
void synchronize_rcu_trivial_preempt(void)
|
||||
{
|
||||
struct task_struct *g;
|
||||
struct task_struct *t;
|
||||
|
||||
smp_mb(); // Order prior accesses before grace-period start.
|
||||
rcu_read_lock(); // Protect task list.
|
||||
for_each_process_thread(g, t) {
|
||||
if (t == current)
|
||||
continue; // Don't deadlock on ourselves!
|
||||
// Order later rcu_read_lock() on other tasks after QS.
|
||||
while (smp_load_acquire(&t->rcu_trivial_preempt_nesting))
|
||||
continue;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(synchronize_rcu_trivial_preempt);
|
||||
#endif // #if IS_ENABLED(CONFIG_TRIVIAL_PREEMPT_RCU)
|
||||
|
||||
int rcu_cpu_stall_notifiers __read_mostly; // !0 = provide stall notifiers (rarely useful)
|
||||
EXPORT_SYMBOL_GPL(rcu_cpu_stall_notifiers);
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
CONFIG_SMP=y
|
||||
CONFIG_NR_CPUS=8
|
||||
CONFIG_PREEMPT_NONE=n
|
||||
CONFIG_PREEMPT_VOLUNTARY=n
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_HZ_PERIODIC=n
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NO_HZ_FULL=n
|
||||
CONFIG_DEBUG_LOCK_ALLOC=n
|
||||
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
|
||||
CONFIG_RCU_EXPERT=y
|
||||
CONFIG_TRIVIAL_PREEMPT_RCU=y
|
||||
@@ -0,0 +1,3 @@
|
||||
rcutorture.torture_type=trivial-preempt
|
||||
rcutorture.onoff_interval=0
|
||||
rcutorture.shuffle_interval=0
|
||||
Reference in New Issue
Block a user