#define pr_fmt(fmt) …
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/err.h>
#include <linux/spinlock.h>
#include <linux/smp.h>
#include <linux/rcupdate_wait.h>
#include <linux/rcu_notifier.h>
#include <linux/interrupt.h>
#include <linux/sched/signal.h>
#include <uapi/linux/sched/types.h>
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/moduleparam.h>
#include <linux/percpu.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/freezer.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/stat.h>
#include <linux/srcu.h>
#include <linux/slab.h>
#include <linux/trace_clock.h>
#include <asm/byteorder.h>
#include <linux/torture.h>
#include <linux/vmalloc.h>
#include <linux/sched/debug.h>
#include <linux/sched/sysctl.h>
#include <linux/oom.h>
#include <linux/tick.h>
#include <linux/rcupdate_trace.h>
#include <linux/nmi.h>
#include "rcu.h"
MODULE_DESCRIPTION(…) …;
MODULE_LICENSE(…) …;
MODULE_AUTHOR(…) …;
#define RCUTORTURE_RDR_SHIFT_1 …
#define RCUTORTURE_RDR_MASK_1 …
#define RCUTORTURE_RDR_SHIFT_2 …
#define RCUTORTURE_RDR_MASK_2 …
#define RCUTORTURE_RDR_BH …
#define RCUTORTURE_RDR_IRQ …
#define RCUTORTURE_RDR_PREEMPT …
#define RCUTORTURE_RDR_RBH …
#define RCUTORTURE_RDR_SCHED …
#define RCUTORTURE_RDR_RCU_1 …
#define RCUTORTURE_RDR_RCU_2 …
#define RCUTORTURE_RDR_NBITS …
#define RCUTORTURE_MAX_EXTEND …
#define RCUTORTURE_RDR_MAX_LOOPS …
#define RCUTORTURE_RDR_MAX_SEGS …
torture_param(int, extendables, RCUTORTURE_MAX_EXTEND,
"Extend readers by disabling bh (1), irqs (2), or preempt (4)");
torture_param(int, fqs_duration, 0, "Duration of fqs bursts (us), 0 to disable");
torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)");
torture_param(int, fqs_stutter, 3, "Wait time between fqs bursts (s)");
torture_param(int, fwd_progress, 1, "Number of grace-period forward progress tasks (0 to disable)");
torture_param(int, fwd_progress_div, 4, "Fraction of CPU stall to wait");
torture_param(int, fwd_progress_holdoff, 60, "Time between forward-progress tests (s)");
torture_param(bool, fwd_progress_need_resched, 1, "Hide cond_resched() behind need_resched()");
torture_param(bool, gp_cond, false, "Use conditional/async GP wait primitives");
torture_param(bool, gp_cond_exp, false, "Use conditional/async expedited GP wait primitives");
torture_param(bool, gp_cond_full, false, "Use conditional/async full-state GP wait primitives");
torture_param(bool, gp_cond_exp_full, false,
"Use conditional/async full-stateexpedited GP wait primitives");
torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
torture_param(bool, gp_normal, false, "Use normal (non-expedited) GP wait primitives");
torture_param(bool, gp_poll, false, "Use polling GP wait primitives");
torture_param(bool, gp_poll_exp, false, "Use polling expedited GP wait primitives");
torture_param(bool, gp_poll_full, false, "Use polling full-state GP wait primitives");
torture_param(bool, gp_poll_exp_full, false, "Use polling full-state expedited GP wait primitives");
torture_param(bool, gp_sync, false, "Use synchronous GP wait primitives");
torture_param(int, irqreader, 1, "Allow RCU readers from irq handlers");
torture_param(int, leakpointer, 0, "Leak pointer dereferences from readers");
torture_param(int, n_barrier_cbs, 0, "# of callbacks/kthreads for barrier testing");
torture_param(int, nfakewriters, 4, "Number of RCU fake writer threads");
torture_param(int, nreaders, -1, "Number of RCU reader threads");
torture_param(int, object_debug, 0, "Enable debug-object double call_rcu() testing");
torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
torture_param(int, onoff_interval, 0, "Time between CPU hotplugs (jiffies), 0=disable");
torture_param(int, nocbs_nthreads, 0, "Number of NOCB toggle threads, 0 to disable");
torture_param(int, nocbs_toggle, 1000, "Time between toggling nocb state (ms)");
torture_param(int, read_exit_delay, 13, "Delay between read-then-exit episodes (s)");
torture_param(int, read_exit_burst, 16, "# of read-then-exit bursts per episode, zero to disable");
torture_param(int, shuffle_interval, 3, "Number of seconds between shuffles");
torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
torture_param(int, stall_cpu, 0, "Stall duration (s), zero to disable.");
torture_param(int, stall_cpu_holdoff, 10, "Time to wait before starting stall (s).");
torture_param(bool, stall_no_softlockup, false, "Avoid softlockup warning during cpu stall.");
torture_param(int, stall_cpu_irqsoff, 0, "Disable interrupts while stalling.");
torture_param(int, stall_cpu_block, 0, "Sleep while stalling.");
torture_param(int, stall_gp_kthread, 0, "Grace-period kthread stall duration (s).");
torture_param(int, stat_interval, 60, "Number of seconds between stats printk()s");
torture_param(int, stutter, 5, "Number of seconds to run/halt test");
torture_param(int, test_boost, 1, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
torture_param(int, test_boost_duration, 4, "Duration of each boost test, seconds.");
torture_param(int, test_boost_interval, 7, "Interval between boost tests, seconds.");
torture_param(int, test_nmis, 0, "End-test NMI tests, 0 to disable.");
torture_param(bool, test_no_idle_hz, true, "Test support for tickless idle CPUs");
torture_param(int, test_srcu_lockdep, 0, "Test specified SRCU deadlock scenario.");
torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
static char *torture_type = …;
module_param(torture_type, charp, 0444);
MODULE_PARM_DESC(…) …;
static int nrealnocbers;
static int nrealreaders;
static struct task_struct *writer_task;
static struct task_struct **fakewriter_tasks;
static struct task_struct **reader_tasks;
static struct task_struct **nocb_tasks;
static struct task_struct *stats_task;
static struct task_struct *fqs_task;
static struct task_struct *boost_tasks[NR_CPUS];
static struct task_struct *stall_task;
static struct task_struct **fwd_prog_tasks;
static struct task_struct **barrier_cbs_tasks;
static struct task_struct *barrier_task;
static struct task_struct *read_exit_task;
#define RCU_TORTURE_PIPE_LEN …
struct rcu_torture_reader_check { … } ____cacheline_internodealigned_in_smp;
struct rcu_torture { … };
static LIST_HEAD(rcu_torture_freelist);
static struct rcu_torture __rcu *rcu_torture_current;
static unsigned long rcu_torture_current_version;
static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
static DEFINE_SPINLOCK(rcu_torture_lock);
static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count);
static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch);
static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
static struct rcu_torture_reader_check *rcu_torture_reader_mbchk;
static atomic_t n_rcu_torture_alloc;
static atomic_t n_rcu_torture_alloc_fail;
static atomic_t n_rcu_torture_free;
static atomic_t n_rcu_torture_mberror;
static atomic_t n_rcu_torture_mbchk_fail;
static atomic_t n_rcu_torture_mbchk_tries;
static atomic_t n_rcu_torture_error;
static long n_rcu_torture_barrier_error;
static long n_rcu_torture_boost_ktrerror;
static long n_rcu_torture_boost_failure;
static long n_rcu_torture_boosts;
static atomic_long_t n_rcu_torture_timers;
static long n_barrier_attempts;
static long n_barrier_successes;
static unsigned long n_read_exits;
static struct list_head rcu_torture_removed;
static unsigned long shutdown_jiffies;
static unsigned long start_gp_seq;
static atomic_long_t n_nocb_offload;
static atomic_long_t n_nocb_deoffload;
static int rcu_torture_writer_state;
#define RTWS_FIXED_DELAY …
#define RTWS_DELAY …
#define RTWS_REPLACE …
#define RTWS_DEF_FREE …
#define RTWS_EXP_SYNC …
#define RTWS_COND_GET …
#define RTWS_COND_GET_FULL …
#define RTWS_COND_GET_EXP …
#define RTWS_COND_GET_EXP_FULL …
#define RTWS_COND_SYNC …
#define RTWS_COND_SYNC_FULL …
#define RTWS_COND_SYNC_EXP …
#define RTWS_COND_SYNC_EXP_FULL …
#define RTWS_POLL_GET …
#define RTWS_POLL_GET_FULL …
#define RTWS_POLL_GET_EXP …
#define RTWS_POLL_GET_EXP_FULL …
#define RTWS_POLL_WAIT …
#define RTWS_POLL_WAIT_FULL …
#define RTWS_POLL_WAIT_EXP …
#define RTWS_POLL_WAIT_EXP_FULL …
#define RTWS_SYNC …
#define RTWS_STUTTER …
#define RTWS_STOPPING …
static const char * const rcu_torture_writer_state_names[] = …;
struct rt_read_seg { … };
static int err_segs_recorded;
static struct rt_read_seg err_segs[RCUTORTURE_RDR_MAX_SEGS];
static int rt_read_nsegs;
static const char *rcu_torture_writer_state_getname(void)
{ … }
#ifdef CONFIG_RCU_TRACE
static u64 notrace rcu_trace_clock_local(void)
{ … }
#else
static u64 notrace rcu_trace_clock_local(void)
{
return 0ULL;
}
#endif
static bool shutdown_time_arrived(void)
{ … }
static unsigned long boost_starttime;
static DEFINE_MUTEX(boost_mutex);
static atomic_t barrier_cbs_count;
static bool barrier_phase;
static atomic_t barrier_cbs_invoked;
static wait_queue_head_t *barrier_cbs_wq;
static DECLARE_WAIT_QUEUE_HEAD(barrier_wq);
static atomic_t rcu_fwd_cb_nodelay;
static struct rcu_torture *
rcu_torture_alloc(void)
{ … }
static void
rcu_torture_free(struct rcu_torture *p)
{ … }
struct rcu_torture_ops { … };
static struct rcu_torture_ops *cur_ops;
static int torture_readlock_not_held(void)
{ … }
static int rcu_torture_read_lock(void)
{ … }
static void
rcu_read_delay(struct torture_random_state *rrsp, struct rt_read_seg *rtrsp)
{ … }
static void rcu_torture_read_unlock(int idx)
{ … }
static bool
rcu_torture_pipe_update_one(struct rcu_torture *rp)
{ … }
static void
rcu_torture_pipe_update(struct rcu_torture *old_rp)
{ … }
static void
rcu_torture_cb(struct rcu_head *p)
{ … }
static unsigned long rcu_no_completed(void)
{ … }
static void rcu_torture_deferred_free(struct rcu_torture *p)
{ … }
static void rcu_sync_torture_init(void)
{ … }
static bool rcu_poll_need_2gp(bool poll, bool poll_full)
{ … }
static struct rcu_torture_ops rcu_ops = …;
static void rcu_busted_torture_deferred_free(struct rcu_torture *p)
{ … }
static void synchronize_rcu_busted(void)
{ … }
static void
call_rcu_busted(struct rcu_head *head, rcu_callback_t func)
{ … }
static struct rcu_torture_ops rcu_busted_ops = …;
DEFINE_STATIC_SRCU(…);
static struct srcu_struct srcu_ctld;
static struct srcu_struct *srcu_ctlp = …;
static struct rcu_torture_ops srcud_ops;
static void srcu_get_gp_data(int *flags, unsigned long *gp_seq)
{ … }
static int srcu_torture_read_lock(void)
{ … }
static void
srcu_read_delay(struct torture_random_state *rrsp, struct rt_read_seg *rtrsp)
{ … }
static void srcu_torture_read_unlock(int idx)
{ … }
static int torture_srcu_read_lock_held(void)
{ … }
static unsigned long srcu_torture_completed(void)
{ … }
static void srcu_torture_deferred_free(struct rcu_torture *rp)
{ … }
static void srcu_torture_synchronize(void)
{ … }
static unsigned long srcu_torture_get_gp_state(void)
{ … }
static unsigned long srcu_torture_start_gp_poll(void)
{ … }
static bool srcu_torture_poll_gp_state(unsigned long oldstate)
{ … }
static void srcu_torture_call(struct rcu_head *head,
rcu_callback_t func)
{ … }
static void srcu_torture_barrier(void)
{ … }
static void srcu_torture_stats(void)
{ … }
static void srcu_torture_synchronize_expedited(void)
{ … }
static struct rcu_torture_ops srcu_ops = …;
static void srcu_torture_init(void)
{ … }
static void srcu_torture_cleanup(void)
{ … }
static struct rcu_torture_ops srcud_ops = …;
static struct rcu_torture_ops busted_srcud_ops = …;
static void synchronize_rcu_trivial(void)
{ … }
static int rcu_torture_read_lock_trivial(void)
{ … }
static void rcu_torture_read_unlock_trivial(int idx)
{ … }
static struct rcu_torture_ops trivial_ops = …;
#ifdef CONFIG_TASKS_RCU
static int tasks_torture_read_lock(void)
{ … }
static void tasks_torture_read_unlock(int idx)
{ … }
static void rcu_tasks_torture_deferred_free(struct rcu_torture *p)
{ … }
static void synchronize_rcu_mult_test(void)
{ … }
static struct rcu_torture_ops tasks_ops = …;
#define TASKS_OPS …
#else
#define TASKS_OPS
#endif
#ifdef CONFIG_TASKS_RUDE_RCU
static void rcu_tasks_rude_torture_deferred_free(struct rcu_torture *p)
{ … }
static struct rcu_torture_ops tasks_rude_ops = …;
#define TASKS_RUDE_OPS …
#else
#define TASKS_RUDE_OPS
#endif
#ifdef CONFIG_TASKS_TRACE_RCU
static int tasks_tracing_torture_read_lock(void)
{ … }
static void tasks_tracing_torture_read_unlock(int idx)
{ … }
static void rcu_tasks_tracing_torture_deferred_free(struct rcu_torture *p)
{ … }
static struct rcu_torture_ops tasks_tracing_ops = …;
#define TASKS_TRACING_OPS …
#else
#define TASKS_TRACING_OPS
#endif
static unsigned long rcutorture_seq_diff(unsigned long new, unsigned long old)
{ … }
static int old_rt_runtime = …;
static void rcu_torture_disable_rt_throttle(void)
{ … }
static void rcu_torture_enable_rt_throttle(void)
{ … }
static bool rcu_torture_boost_failed(unsigned long gp_state, unsigned long *start)
{ … }
static int rcu_torture_boost(void *arg)
{ … }
static int
rcu_torture_fqs(void *arg)
{ … }
static int synctype[ARRAY_SIZE(rcu_torture_writer_state_names)] = …;
static int nsynctypes;
static void rcu_torture_write_types(void)
{ … }
static void do_rtws_sync(struct torture_random_state *trsp, void (*sync)(void))
{ … }
static int
rcu_torture_writer(void *arg)
{ … }
static int
rcu_torture_fakewriter(void *arg)
{ … }
static void rcu_torture_timer_cb(struct rcu_head *rhp)
{ … }
static void rcu_torture_reader_do_mbchk(long myid, struct rcu_torture *rtp,
struct torture_random_state *trsp)
{ … }
static void rcutorture_one_extend(int *readstate, int newstate,
struct torture_random_state *trsp,
struct rt_read_seg *rtrsp)
{ … }
static int rcutorture_extend_mask_max(void)
{ … }
static int
rcutorture_extend_mask(int oldmask, struct torture_random_state *trsp)
{ … }
static struct rt_read_seg *
rcutorture_loop_extend(int *readstate, struct torture_random_state *trsp,
struct rt_read_seg *rtrsp)
{ … }
static bool rcu_torture_one_read(struct torture_random_state *trsp, long myid)
{ … }
static DEFINE_TORTURE_RANDOM_PERCPU(rcu_torture_timer_rand);
static void rcu_torture_timer(struct timer_list *unused)
{ … }
static int
rcu_torture_reader(void *arg)
{ … }
static int rcu_nocb_toggle(void *arg)
{ … }
static void
rcu_torture_stats_print(void)
{ … }
static int
rcu_torture_stats(void *arg)
{ … }
static void rcu_torture_mem_dump_obj(void)
{ … }
static void
rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
{ … }
static int rcutorture_booster_cleanup(unsigned int cpu)
{ … }
static int rcutorture_booster_init(unsigned int cpu)
{ … }
static int rcu_torture_stall_nf(struct notifier_block *nb, unsigned long v, void *ptr)
{ … }
static struct notifier_block rcu_torture_stall_block = …;
static int rcu_torture_stall(void *args)
{ … }
static int __init rcu_torture_stall_init(void)
{ … }
struct fwd_cb_state { … };
static void rcu_torture_fwd_prog_cb(struct rcu_head *rhp)
{ … }
struct rcu_fwd_cb { … };
#define MAX_FWD_CB_JIFFIES …
#define MIN_FWD_CB_LAUNDERS …
#define MIN_FWD_CBS_LAUNDERED …
#define FWD_CBS_HIST_DIV …
#define N_LAUNDERS_HIST …
struct rcu_launder_hist { … };
struct rcu_fwd { … };
static DEFINE_MUTEX(rcu_fwd_mutex);
static struct rcu_fwd *rcu_fwds;
static unsigned long rcu_fwd_seq;
static atomic_long_t rcu_fwd_max_cbs;
static bool rcu_fwd_emergency_stop;
static void rcu_torture_fwd_cb_hist(struct rcu_fwd *rfp)
{ … }
static void rcu_torture_fwd_cb_cr(struct rcu_head *rhp)
{ … }
static void rcu_torture_fwd_prog_cond_resched(unsigned long iter)
{ … }
static unsigned long rcu_torture_fwd_prog_cbfree(struct rcu_fwd *rfp)
{ … }
static void rcu_torture_fwd_prog_nr(struct rcu_fwd *rfp,
int *tested, int *tested_tries)
{ … }
static void rcu_torture_fwd_prog_cr(struct rcu_fwd *rfp)
{ … }
static int rcutorture_oom_notify(struct notifier_block *self,
unsigned long notused, void *nfreed)
{ … }
static struct notifier_block rcutorture_oom_nb = …;
static int rcu_torture_fwd_prog(void *args)
{ … }
static int __init rcu_torture_fwd_prog_init(void)
{ … }
static void rcu_torture_fwd_prog_cleanup(void)
{ … }
static void rcu_torture_barrier_cbf(struct rcu_head *rcu)
{ … }
static int rcu_torture_barrier1cb(void *rcu_void)
{ … }
static int rcu_torture_barrier_cbs(void *arg)
{ … }
static int rcu_torture_barrier(void *arg)
{ … }
static int rcu_torture_barrier_init(void)
{ … }
static void rcu_torture_barrier_cleanup(void)
{ … }
static bool rcu_torture_can_boost(void)
{ … }
static bool read_exit_child_stop;
static bool read_exit_child_stopped;
static wait_queue_head_t read_exit_wq;
static int rcu_torture_read_exit_child(void *trsp_in)
{ … }
static int rcu_torture_read_exit(void *unused)
{ … }
static int rcu_torture_read_exit_init(void)
{ … }
static void rcu_torture_read_exit_cleanup(void)
{ … }
static void rcutorture_test_nmis(int n)
{ … }
static enum cpuhp_state rcutor_hp;
static void
rcu_torture_cleanup(void)
{ … }
static void rcu_torture_leak_cb(struct rcu_head *rhp)
{ … }
static void rcu_torture_err_cb(struct rcu_head *rhp)
{ … }
static void rcu_test_debug_objects(void)
{ … }
static void rcutorture_sync(void)
{ … }
static DEFINE_MUTEX(mut0);
static DEFINE_MUTEX(mut1);
static DEFINE_MUTEX(mut2);
static DEFINE_MUTEX(mut3);
static DEFINE_MUTEX(mut4);
static DEFINE_MUTEX(mut5);
static DEFINE_MUTEX(mut6);
static DEFINE_MUTEX(mut7);
static DEFINE_MUTEX(mut8);
static DEFINE_MUTEX(mut9);
static DECLARE_RWSEM(rwsem0);
static DECLARE_RWSEM(rwsem1);
static DECLARE_RWSEM(rwsem2);
static DECLARE_RWSEM(rwsem3);
static DECLARE_RWSEM(rwsem4);
static DECLARE_RWSEM(rwsem5);
static DECLARE_RWSEM(rwsem6);
static DECLARE_RWSEM(rwsem7);
static DECLARE_RWSEM(rwsem8);
static DECLARE_RWSEM(rwsem9);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
DEFINE_STATIC_SRCU(…);
static int srcu_lockdep_next(const char *f, const char *fl, const char *fs, const char *fu, int i,
int cyclelen, int deadlock)
{ … }
static void rcu_torture_init_srcu_lockdep(void)
{ … }
static int __init
rcu_torture_init(void)
{ … }
module_init(…) …;
module_exit(rcu_torture_cleanup);