2019-01-18 02:16:42 +08:00
// SPDX-License-Identifier: GPL-2.0+
2005-10-31 07:03:12 +08:00
/*
2006-06-27 17:54:02 +08:00
* Read - Copy Update module - based torture test facility
2005-10-31 07:03:12 +08:00
*
2006-10-04 17:17:13 +08:00
* Copyright ( C ) IBM Corporation , 2005 , 2006
2005-10-31 07:03:12 +08:00
*
2019-01-18 02:16:42 +08:00
* Authors : Paul E . McKenney < paulmck @ linux . ibm . com >
2014-07-31 07:08:42 +08:00
* Josh Triplett < josh @ joshtriplett . org >
2005-10-31 07:03:12 +08:00
*
2020-04-22 01:04:06 +08:00
* See also : Documentation / RCU / torture . rst
2005-10-31 07:03:12 +08:00
*/
2018-05-16 03:25:05 +08:00
# define pr_fmt(fmt) fmt
2005-10-31 07:03:12 +08:00
# 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>
2020-03-07 06:00:46 +08:00
# include <linux/rcupdate_wait.h>
2005-10-31 07:03:12 +08:00
# include <linux/interrupt.h>
2017-02-03 02:15:33 +08:00
# include <linux/sched/signal.h>
2017-02-02 01:07:51 +08:00
# include <uapi/linux/sched/types.h>
2011-07-27 07:09:06 +08:00
# include <linux/atomic.h>
2005-10-31 07:03:12 +08:00
# include <linux/bitops.h>
# include <linux/completion.h>
# include <linux/moduleparam.h>
# include <linux/percpu.h>
# include <linux/notifier.h>
2008-12-16 08:13:07 +08:00
# include <linux/reboot.h>
2007-07-17 19:03:35 +08:00
# include <linux/freezer.h>
2005-10-31 07:03:12 +08:00
# include <linux/cpu.h>
# include <linux/delay.h>
# include <linux/stat.h>
2006-10-04 17:17:03 +08:00
# include <linux/srcu.h>
2008-04-29 15:59:25 +08:00
# include <linux/slab.h>
2012-11-15 08:26:40 +08:00
# include <linux/trace_clock.h>
2008-10-21 01:23:38 +08:00
# include <asm/byteorder.h>
2014-01-28 03:49:39 +08:00
# include <linux/torture.h>
2014-08-19 12:12:17 +08:00
# include <linux/vmalloc.h>
2017-08-31 01:40:17 +08:00
# include <linux/sched/debug.h>
2018-06-11 07:45:43 +08:00
# include <linux/sched/sysctl.h>
2018-10-02 08:40:54 +08:00
# include <linux/oom.h>
2019-07-29 03:00:48 +08:00
# include <linux/tick.h>
2020-03-11 01:32:30 +08:00
# include <linux/rcupdate_trace.h>
2021-11-10 22:37:45 +08:00
# include <linux/nmi.h>
2005-10-31 07:03:12 +08:00
2017-05-04 00:51:55 +08:00
# include "rcu.h"
2005-10-31 07:03:12 +08:00
MODULE_LICENSE ( " GPL " ) ;
2019-01-18 02:16:42 +08:00
MODULE_AUTHOR ( " Paul E. McKenney <paulmck@linux.ibm.com> and Josh Triplett <josh@joshtriplett.org> " ) ;
2005-10-31 07:03:12 +08:00
2018-05-25 22:29:25 +08:00
/* Bits for ->extendables field, extendables param, and related definitions. */
2021-09-23 11:49:12 +08:00
# define RCUTORTURE_RDR_SHIFT_1 8 /* Put SRCU index in upper bits. */
# define RCUTORTURE_RDR_MASK_1 (1 << RCUTORTURE_RDR_SHIFT_1)
# define RCUTORTURE_RDR_SHIFT_2 9 /* Put SRCU index in upper bits. */
# define RCUTORTURE_RDR_MASK_2 (1 << RCUTORTURE_RDR_SHIFT_2)
2018-07-07 06:16:12 +08:00
# define RCUTORTURE_RDR_BH 0x01 /* Extend readers by disabling bh. */
# define RCUTORTURE_RDR_IRQ 0x02 /* ... disabling interrupts. */
# define RCUTORTURE_RDR_PREEMPT 0x04 /* ... disabling preemption. */
# define RCUTORTURE_RDR_RBH 0x08 /* ... rcu_read_lock_bh(). */
# define RCUTORTURE_RDR_SCHED 0x10 /* ... rcu_read_lock_sched(). */
2021-09-23 11:49:12 +08:00
# define RCUTORTURE_RDR_RCU_1 0x20 /* ... entering another RCU reader. */
# define RCUTORTURE_RDR_RCU_2 0x40 /* ... entering another RCU reader. */
# define RCUTORTURE_RDR_NBITS 7 /* Number of bits defined above. */
2018-07-07 06:16:12 +08:00
# define RCUTORTURE_MAX_EXTEND \
( RCUTORTURE_RDR_BH | RCUTORTURE_RDR_IRQ | RCUTORTURE_RDR_PREEMPT | \
RCUTORTURE_RDR_RBH | RCUTORTURE_RDR_SCHED )
2018-05-25 22:29:25 +08:00
# define RCUTORTURE_RDR_MAX_LOOPS 0x7 /* Maximum reader extensions. */
/* Must be power of two minus one. */
2018-07-14 03:09:14 +08:00
# define RCUTORTURE_RDR_MAX_SEGS (RCUTORTURE_RDR_MAX_LOOPS + 3)
2018-05-25 22:29:25 +08:00
torture_param ( int , extendables , RCUTORTURE_MAX_EXTEND ,
" Extend readers by disabling bh (1), irqs (2), or preempt (4) " ) ;
2022-04-18 11:43:13 +08:00
torture_param ( int , fqs_duration , 0 , " Duration of fqs bursts (us), 0 to disable " ) ;
2014-01-28 08:27:00 +08:00
torture_param ( int , fqs_holdoff , 0 , " Holdoff time within fqs bursts (us) " ) ;
torture_param ( int , fqs_stutter , 3 , " Wait time between fqs bursts (s) " ) ;
2022-04-18 11:43:13 +08:00
torture_param ( int , fwd_progress , 1 , " Number of grace-period forward progress tasks (0 to disable) " ) ;
2018-07-19 05:32:31 +08:00
torture_param ( int , fwd_progress_div , 4 , " Fraction of CPU stall to wait " ) ;
2022-04-18 11:43:13 +08:00
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() " ) ;
2014-03-19 06:57:41 +08:00
torture_param ( bool , gp_cond , false , " Use conditional/async GP wait primitives " ) ;
2022-02-01 23:01:20 +08:00
torture_param ( bool , gp_cond_exp , false , " Use conditional/async expedited GP wait primitives " ) ;
2022-08-05 04:46:05 +08:00
torture_param ( bool , gp_cond_full , false , " Use conditional/async full-state GP wait primitives " ) ;
2022-08-05 06:23:26 +08:00
torture_param ( bool , gp_cond_exp_full , false ,
" Use conditional/async full-stateexpedited GP wait primitives " ) ;
2014-01-28 08:27:00 +08:00
torture_param ( bool , gp_exp , false , " Use expedited GP wait primitives " ) ;
2022-04-18 11:43:13 +08:00
torture_param ( bool , gp_normal , false , " Use normal (non-expedited) GP wait primitives " ) ;
2020-11-14 12:43:59 +08:00
torture_param ( bool , gp_poll , false , " Use polling GP wait primitives " ) ;
2022-02-01 23:01:20 +08:00
torture_param ( bool , gp_poll_exp , false , " Use polling expedited GP wait primitives " ) ;
2022-08-03 08:04:54 +08:00
torture_param ( bool , gp_poll_full , false , " Use polling full-state GP wait primitives " ) ;
2022-08-04 03:38:51 +08:00
torture_param ( bool , gp_poll_exp_full , false , " Use polling full-state expedited GP wait primitives " ) ;
2014-03-22 07:17:56 +08:00
torture_param ( bool , gp_sync , false , " Use synchronous GP wait primitives " ) ;
2014-01-28 08:27:00 +08:00
torture_param ( int , irqreader , 1 , " Allow RCU readers from irq handlers " ) ;
2020-08-12 01:33:39 +08:00
torture_param ( int , leakpointer , 0 , " Leak pointer dereferences from readers " ) ;
2022-04-18 11:43:13 +08:00
torture_param ( int , n_barrier_cbs , 0 , " # of callbacks/kthreads for barrier testing " ) ;
2014-01-28 08:27:00 +08:00
torture_param ( int , nfakewriters , 4 , " Number of RCU fake writer threads " ) ;
torture_param ( int , nreaders , - 1 , " Number of RCU reader threads " ) ;
2022-04-18 11:43:13 +08:00
torture_param ( int , object_debug , 0 , " Enable debug-object double call_rcu() testing " ) ;
2014-01-28 08:27:00 +08:00
torture_param ( int , onoff_holdoff , 0 , " Time after boot before CPU hotplugs (s) " ) ;
2022-04-18 11:43:13 +08:00
torture_param ( int , onoff_interval , 0 , " Time between CPU hotplugs (jiffies), 0=disable " ) ;
2020-09-24 08:39:46 +08:00
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) " ) ;
2022-04-18 11:43:13 +08:00
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 " ) ;
2014-01-28 08:27:00 +08:00
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. " ) ;
2022-04-18 11:43:13 +08:00
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. " ) ;
2017-08-19 07:11:37 +08:00
torture_param ( int , stall_cpu_irqsoff , 0 , " Disable interrupts while stalling. " ) ;
2020-03-12 08:39:12 +08:00
torture_param ( int , stall_cpu_block , 0 , " Sleep while stalling. " ) ;
2022-04-18 11:43:13 +08:00
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 " ) ;
2014-01-28 08:27:00 +08:00
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. " ) ;
2022-04-18 11:43:13 +08:00
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. " ) ;
2022-12-20 03:21:09 +08:00
torture_param ( int , test_nmis , 0 , " End-test NMI tests, 0 to disable. " ) ;
2022-04-18 11:43:13 +08:00
torture_param ( bool , test_no_idle_hz , true , " Test support for tickless idle CPUs " ) ;
2023-01-14 13:34:27 +08:00
torture_param ( int , test_srcu_lockdep , 0 , " Test specified SRCU deadlock scenario. " ) ;
2022-04-18 11:43:13 +08:00
torture_param ( int , verbose , 1 , " Enable verbose debugging printk()s " ) ;
2014-01-28 08:27:00 +08:00
2013-06-14 06:12:24 +08:00
static char * torture_type = " rcu " ;
2007-03-06 17:42:13 +08:00
module_param ( torture_type , charp , 0444 ) ;
2018-07-08 01:28:07 +08:00
MODULE_PARM_DESC ( torture_type , " Type of RCU to torture (rcu, srcu, ...) " ) ;
2005-10-31 07:03:12 +08:00
2020-09-24 08:39:46 +08:00
static int nrealnocbers ;
2005-10-31 07:03:12 +08:00
static int nrealreaders ;
static struct task_struct * writer_task ;
2006-10-04 17:17:13 +08:00
static struct task_struct * * fakewriter_tasks ;
2005-10-31 07:03:12 +08:00
static struct task_struct * * reader_tasks ;
2020-09-24 08:39:46 +08:00
static struct task_struct * * nocb_tasks ;
2005-10-31 07:03:12 +08:00
static struct task_struct * stats_task ;
2010-01-05 07:09:10 +08:00
static struct task_struct * fqs_task ;
2010-09-03 07:16:14 +08:00
static struct task_struct * boost_tasks [ NR_CPUS ] ;
2012-01-21 07:36:33 +08:00
static struct task_struct * stall_task ;
2021-11-23 12:55:18 +08:00
static struct task_struct * * fwd_prog_tasks ;
2012-02-21 09:51:45 +08:00
static struct task_struct * * barrier_cbs_tasks ;
static struct task_struct * barrier_task ;
2020-04-25 02:21:40 +08:00
static struct task_struct * read_exit_task ;
2005-10-31 07:03:12 +08:00
# define RCU_TORTURE_PIPE_LEN 10
2020-10-30 06:08:57 +08:00
// Mailbox-like structure to check RCU global memory ordering.
struct rcu_torture_reader_check {
unsigned long rtc_myloops ;
int rtc_chkrdr ;
unsigned long rtc_chkloops ;
int rtc_ready ;
struct rcu_torture_reader_check * rtc_assigner ;
} ____cacheline_internodealigned_in_smp ;
// Update-side data structure used to check RCU readers.
2005-10-31 07:03:12 +08:00
struct rcu_torture {
struct rcu_head rtort_rcu ;
int rtort_pipe_count ;
struct list_head rtort_free ;
2005-11-18 17:10:50 +08:00
int rtort_mbtest ;
2020-10-30 06:08:57 +08:00
struct rcu_torture_reader_check * rtort_chkp ;
2005-10-31 07:03:12 +08:00
} ;
static LIST_HEAD ( rcu_torture_freelist ) ;
2010-09-20 12:06:14 +08:00
static struct rcu_torture __rcu * rcu_torture_current ;
2011-04-04 12:33:51 +08:00
static unsigned long rcu_torture_current_version ;
2005-10-31 07:03:12 +08:00
static struct rcu_torture rcu_tortures [ 10 * RCU_TORTURE_PIPE_LEN ] ;
static DEFINE_SPINLOCK ( rcu_torture_lock ) ;
2016-03-02 00:52:19 +08:00
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 ) ;
2005-10-31 07:03:12 +08:00
static atomic_t rcu_torture_wcount [ RCU_TORTURE_PIPE_LEN + 1 ] ;
2020-10-30 06:08:57 +08:00
static struct rcu_torture_reader_check * rcu_torture_reader_mbchk ;
2006-10-04 17:17:03 +08:00
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 ;
2020-10-30 06:08:57 +08:00
static atomic_t n_rcu_torture_mbchk_fail ;
static atomic_t n_rcu_torture_mbchk_tries ;
2006-10-04 17:17:03 +08:00
static atomic_t n_rcu_torture_error ;
2012-02-21 09:51:45 +08:00
static long n_rcu_torture_barrier_error ;
2010-09-03 07:16:14 +08:00
static long n_rcu_torture_boost_ktrerror ;
static long n_rcu_torture_boost_failure ;
static long n_rcu_torture_boosts ;
2018-05-23 02:17:51 +08:00
static atomic_long_t n_rcu_torture_timers ;
2012-02-21 09:51:45 +08:00
static long n_barrier_attempts ;
2018-06-20 06:14:19 +08:00
static long n_barrier_successes ; /* did rcu_barrier test succeed? */
2020-04-25 02:21:40 +08:00
static unsigned long n_read_exits ;
2006-10-04 17:17:14 +08:00
static struct list_head rcu_torture_removed ;
2019-07-10 23:30:00 +08:00
static unsigned long shutdown_jiffies ;
2020-06-19 04:29:55 +08:00
static unsigned long start_gp_seq ;
2020-09-24 08:39:46 +08:00
static atomic_long_t n_nocb_offload ;
static atomic_long_t n_nocb_deoffload ;
2008-06-18 20:21:44 +08:00
2014-02-20 02:51:42 +08:00
static int rcu_torture_writer_state ;
# define RTWS_FIXED_DELAY 0
# define RTWS_DELAY 1
# define RTWS_REPLACE 2
# define RTWS_DEF_FREE 3
# define RTWS_EXP_SYNC 4
2014-03-19 06:57:41 +08:00
# define RTWS_COND_GET 5
2022-08-05 04:46:05 +08:00
# define RTWS_COND_GET_FULL 6
# define RTWS_COND_GET_EXP 7
2022-08-05 06:23:26 +08:00
# define RTWS_COND_GET_EXP_FULL 8
# define RTWS_COND_SYNC 9
# define RTWS_COND_SYNC_FULL 10
# define RTWS_COND_SYNC_EXP 11
# define RTWS_COND_SYNC_EXP_FULL 12
# define RTWS_POLL_GET 13
# define RTWS_POLL_GET_FULL 14
# define RTWS_POLL_GET_EXP 15
# define RTWS_POLL_GET_EXP_FULL 16
# define RTWS_POLL_WAIT 17
# define RTWS_POLL_WAIT_FULL 18
# define RTWS_POLL_WAIT_EXP 19
# define RTWS_POLL_WAIT_EXP_FULL 20
# define RTWS_SYNC 21
# define RTWS_STUTTER 22
# define RTWS_STOPPING 23
2015-11-18 05:35:28 +08:00
static const char * const rcu_torture_writer_state_names [ ] = {
" RTWS_FIXED_DELAY " ,
" RTWS_DELAY " ,
" RTWS_REPLACE " ,
" RTWS_DEF_FREE " ,
" RTWS_EXP_SYNC " ,
" RTWS_COND_GET " ,
2022-08-05 04:46:05 +08:00
" RTWS_COND_GET_FULL " ,
2022-02-01 23:01:20 +08:00
" RTWS_COND_GET_EXP " ,
2022-08-05 06:23:26 +08:00
" RTWS_COND_GET_EXP_FULL " ,
2015-11-18 05:35:28 +08:00
" RTWS_COND_SYNC " ,
2022-08-05 04:46:05 +08:00
" RTWS_COND_SYNC_FULL " ,
2022-02-01 23:01:20 +08:00
" RTWS_COND_SYNC_EXP " ,
2022-08-05 06:23:26 +08:00
" RTWS_COND_SYNC_EXP_FULL " ,
2020-11-14 12:43:59 +08:00
" RTWS_POLL_GET " ,
2022-08-03 08:04:54 +08:00
" RTWS_POLL_GET_FULL " ,
2022-02-01 23:01:20 +08:00
" RTWS_POLL_GET_EXP " ,
2022-08-04 03:38:51 +08:00
" RTWS_POLL_GET_EXP_FULL " ,
2020-11-14 12:43:59 +08:00
" RTWS_POLL_WAIT " ,
2022-08-03 08:04:54 +08:00
" RTWS_POLL_WAIT_FULL " ,
2022-02-01 23:01:20 +08:00
" RTWS_POLL_WAIT_EXP " ,
2022-08-04 03:38:51 +08:00
" RTWS_POLL_WAIT_EXP_FULL " ,
2015-11-18 05:35:28 +08:00
" RTWS_SYNC " ,
" RTWS_STUTTER " ,
" RTWS_STOPPING " ,
} ;
2018-07-14 03:09:14 +08:00
/* Record reader segment types and duration for first failing read. */
struct rt_read_seg {
int rt_readstate ;
unsigned long rt_delay_jiffies ;
unsigned long rt_delay_ms ;
unsigned long rt_delay_us ;
bool rt_preempted ;
} ;
static int err_segs_recorded ;
static struct rt_read_seg err_segs [ RCUTORTURE_RDR_MAX_SEGS ] ;
static int rt_read_nsegs ;
2015-11-18 05:35:28 +08:00
static const char * rcu_torture_writer_state_getname ( void )
{
unsigned int i = READ_ONCE ( rcu_torture_writer_state ) ;
if ( i > = ARRAY_SIZE ( rcu_torture_writer_state_names ) )
return " ??? " ;
return rcu_torture_writer_state_names [ i ] ;
}
2014-02-20 02:51:42 +08:00
2013-02-05 02:36:13 +08:00
# ifdef CONFIG_RCU_TRACE
static u64 notrace rcu_trace_clock_local ( void )
{
u64 ts = trace_clock_local ( ) ;
2017-06-24 07:07:17 +08:00
( void ) do_div ( ts , NSEC_PER_USEC ) ;
2013-02-05 02:36:13 +08:00
return ts ;
}
# else /* #ifdef CONFIG_RCU_TRACE */
static u64 notrace rcu_trace_clock_local ( void )
{
return 0ULL ;
}
# endif /* #else #ifdef CONFIG_RCU_TRACE */
2019-07-10 23:30:00 +08:00
/*
* Stop aggressive CPU - hog tests a bit before the end of the test in order
* to avoid interfering with test shutdown .
*/
static bool shutdown_time_arrived ( void )
{
return shutdown_secs & & time_after ( jiffies , shutdown_jiffies - 30 * HZ ) ;
}
2010-09-03 07:16:14 +08:00
static unsigned long boost_starttime ; /* jiffies of next boost test start. */
2014-06-12 04:39:43 +08:00
static DEFINE_MUTEX ( boost_mutex ) ; /* protect setting boost_starttime */
2010-09-03 07:16:14 +08:00
/* and boost task create/destroy. */
2012-02-21 09:51:45 +08:00
static atomic_t barrier_cbs_count ; /* Barrier callbacks registered. */
2012-05-29 10:21:41 +08:00
static bool barrier_phase ; /* Test phase. */
2012-02-21 09:51:45 +08:00
static atomic_t barrier_cbs_invoked ; /* Barrier callbacks invoked. */
static wait_queue_head_t * barrier_cbs_wq ; /* Coordinate barrier testing. */
static DECLARE_WAIT_QUEUE_HEAD ( barrier_wq ) ;
2010-09-03 07:16:14 +08:00
2021-12-18 04:33:53 +08:00
static atomic_t rcu_fwd_cb_nodelay ; /* Short rcu_torture_delay() delays. */
2018-08-16 06:32:51 +08:00
2005-10-31 07:03:12 +08:00
/*
* Allocate an element from the rcu_tortures pool .
*/
2006-01-08 17:02:17 +08:00
static struct rcu_torture *
2005-10-31 07:03:12 +08:00
rcu_torture_alloc ( void )
{
struct list_head * p ;
2006-01-26 02:50:12 +08:00
spin_lock_bh ( & rcu_torture_lock ) ;
2005-10-31 07:03:12 +08:00
if ( list_empty ( & rcu_torture_freelist ) ) {
atomic_inc ( & n_rcu_torture_alloc_fail ) ;
2006-01-26 02:50:12 +08:00
spin_unlock_bh ( & rcu_torture_lock ) ;
2005-10-31 07:03:12 +08:00
return NULL ;
}
atomic_inc ( & n_rcu_torture_alloc ) ;
p = rcu_torture_freelist . next ;
list_del_init ( p ) ;
2006-01-26 02:50:12 +08:00
spin_unlock_bh ( & rcu_torture_lock ) ;
2005-10-31 07:03:12 +08:00
return container_of ( p , struct rcu_torture , rtort_free ) ;
}
/*
* Free an element to the rcu_tortures pool .
*/
static void
rcu_torture_free ( struct rcu_torture * p )
{
atomic_inc ( & n_rcu_torture_free ) ;
2006-01-26 02:50:12 +08:00
spin_lock_bh ( & rcu_torture_lock ) ;
2005-10-31 07:03:12 +08:00
list_add_tail ( & p - > rtort_free , & rcu_torture_freelist ) ;
2006-01-26 02:50:12 +08:00
spin_unlock_bh ( & rcu_torture_lock ) ;
2005-10-31 07:03:12 +08:00
}
2006-06-27 17:54:03 +08:00
/*
* Operations vector for selecting different types of tests .
*/
struct rcu_torture_ops {
2014-02-20 02:51:42 +08:00
int ttype ;
2006-06-27 17:54:03 +08:00
void ( * init ) ( void ) ;
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
void ( * cleanup ) ( void ) ;
2006-06-27 17:54:03 +08:00
int ( * readlock ) ( void ) ;
2018-07-14 03:09:14 +08:00
void ( * read_delay ) ( struct torture_random_state * rrsp ,
struct rt_read_seg * rtrsp ) ;
2006-06-27 17:54:03 +08:00
void ( * readunlock ) ( int idx ) ;
2021-03-14 12:05:31 +08:00
int ( * readlock_held ) ( void ) ;
2018-04-28 02:39:34 +08:00
unsigned long ( * get_gp_seq ) ( void ) ;
2018-05-16 06:24:41 +08:00
unsigned long ( * gp_diff ) ( unsigned long new , unsigned long old ) ;
2009-06-26 00:08:17 +08:00
void ( * deferred_free ) ( struct rcu_torture * p ) ;
2006-10-04 17:17:13 +08:00
void ( * sync ) ( void ) ;
2013-06-13 06:12:21 +08:00
void ( * exp_sync ) ( void ) ;
2022-02-01 23:01:20 +08:00
unsigned long ( * get_gp_state_exp ) ( void ) ;
unsigned long ( * start_gp_poll_exp ) ( void ) ;
2022-08-04 03:38:51 +08:00
void ( * start_gp_poll_exp_full ) ( struct rcu_gp_oldstate * rgosp ) ;
2022-02-01 23:01:20 +08:00
bool ( * poll_gp_state_exp ) ( unsigned long oldstate ) ;
void ( * cond_sync_exp ) ( unsigned long oldstate ) ;
2022-08-05 06:23:26 +08:00
void ( * cond_sync_exp_full ) ( struct rcu_gp_oldstate * rgosp ) ;
2022-08-26 06:47:09 +08:00
unsigned long ( * get_comp_state ) ( void ) ;
2022-08-26 04:37:59 +08:00
void ( * get_comp_state_full ) ( struct rcu_gp_oldstate * rgosp ) ;
2022-08-26 06:47:09 +08:00
bool ( * same_gp_state ) ( unsigned long oldstate1 , unsigned long oldstate2 ) ;
2022-08-26 04:37:59 +08:00
bool ( * same_gp_state_full ) ( struct rcu_gp_oldstate * rgosp1 , struct rcu_gp_oldstate * rgosp2 ) ;
2020-11-14 12:14:27 +08:00
unsigned long ( * get_gp_state ) ( void ) ;
2022-07-29 10:58:13 +08:00
void ( * get_gp_state_full ) ( struct rcu_gp_oldstate * rgosp ) ;
2022-04-14 07:14:02 +08:00
unsigned long ( * get_gp_completed ) ( void ) ;
2022-07-29 06:37:05 +08:00
void ( * get_gp_completed_full ) ( struct rcu_gp_oldstate * rgosp ) ;
2020-11-14 12:43:59 +08:00
unsigned long ( * start_gp_poll ) ( void ) ;
2022-08-03 08:04:54 +08:00
void ( * start_gp_poll_full ) ( struct rcu_gp_oldstate * rgosp ) ;
2020-11-14 12:43:59 +08:00
bool ( * poll_gp_state ) ( unsigned long oldstate ) ;
2022-07-29 06:37:05 +08:00
bool ( * poll_gp_state_full ) ( struct rcu_gp_oldstate * rgosp ) ;
2022-08-02 07:57:17 +08:00
bool ( * poll_need_2gp ) ( bool poll , bool poll_full ) ;
2014-03-19 06:57:41 +08:00
void ( * cond_sync ) ( unsigned long oldstate ) ;
2022-08-05 04:46:05 +08:00
void ( * cond_sync_full ) ( struct rcu_gp_oldstate * rgosp ) ;
2015-07-29 13:29:39 +08:00
call_rcu_func_t call ;
2008-05-13 03:21:05 +08:00
void ( * cb_barrier ) ( void ) ;
2010-01-05 07:09:10 +08:00
void ( * fqs ) ( void ) ;
2014-07-14 21:16:15 +08:00
void ( * stats ) ( void ) ;
2020-09-16 08:08:03 +08:00
void ( * gp_kthread_dbg ) ( void ) ;
2021-04-09 04:01:14 +08:00
bool ( * check_boost_failed ) ( unsigned long gp_state , int * cpup ) ;
2018-07-19 05:32:31 +08:00
int ( * stall_dur ) ( void ) ;
2021-11-24 03:53:52 +08:00
long cbflood_max ;
2009-06-26 00:08:17 +08:00
int irq_capable ;
2010-09-03 07:16:14 +08:00
int can_boost ;
2018-05-25 22:29:25 +08:00
int extendables ;
2019-04-13 00:02:46 +08:00
int slow_gps ;
2021-09-25 12:30:26 +08:00
int no_pi_lock ;
2013-07-13 04:50:28 +08:00
const char * name ;
2006-06-27 17:54:03 +08:00
} ;
2009-09-19 01:28:19 +08:00
static struct rcu_torture_ops * cur_ops ;
2006-06-27 17:54:03 +08:00
/*
* Definitions for rcu torture testing .
*/
2021-03-14 12:05:31 +08:00
static int torture_readlock_not_held ( void )
{
return rcu_read_lock_bh_held ( ) | | rcu_read_lock_sched_held ( ) ;
}
2022-12-17 01:47:28 +08:00
static int rcu_torture_read_lock ( void )
2006-06-27 17:54:03 +08:00
{
rcu_read_lock ( ) ;
return 0 ;
}
2018-07-14 03:09:14 +08:00
static void
rcu_read_delay ( struct torture_random_state * rrsp , struct rt_read_seg * rtrsp )
2006-10-04 17:17:03 +08:00
{
2016-10-11 09:26:04 +08:00
unsigned long started ;
unsigned long completed ;
2009-09-09 06:54:35 +08:00
const unsigned long shortdelay_us = 200 ;
2018-07-21 03:04:12 +08:00
unsigned long longdelay_ms = 300 ;
2016-10-11 09:26:04 +08:00
unsigned long long ts ;
2006-10-04 17:17:03 +08:00
2009-09-09 06:54:35 +08:00
/* We want a short delay sometimes to make a reader delay the grace
* period , and we want a long delay occasionally to trigger
* force_quiescent_state . */
2006-10-04 17:17:03 +08:00
2021-12-18 04:33:53 +08:00
if ( ! atomic_read ( & rcu_fwd_cb_nodelay ) & &
2018-08-16 06:32:51 +08:00
! ( torture_random ( rrsp ) % ( nrealreaders * 2000 * longdelay_ms ) ) ) {
2018-04-28 02:39:34 +08:00
started = cur_ops - > get_gp_seq ( ) ;
2016-10-11 09:26:04 +08:00
ts = rcu_trace_clock_local ( ) ;
2018-07-21 03:04:12 +08:00
if ( preempt_count ( ) & ( SOFTIRQ_MASK | HARDIRQ_MASK ) )
longdelay_ms = 5 ; /* Avoid triggering BH limits. */
2009-09-09 06:54:35 +08:00
mdelay ( longdelay_ms ) ;
2018-07-14 03:09:14 +08:00
rtrsp - > rt_delay_ms = longdelay_ms ;
2018-04-28 02:39:34 +08:00
completed = cur_ops - > get_gp_seq ( ) ;
2016-10-11 09:26:04 +08:00
do_trace_rcu_torture_read ( cur_ops - > name , NULL , ts ,
started , completed ) ;
}
2018-07-14 03:09:14 +08:00
if ( ! ( torture_random ( rrsp ) % ( nrealreaders * 2 * shortdelay_us ) ) ) {
2009-09-09 06:54:35 +08:00
udelay ( shortdelay_us ) ;
2018-07-14 03:09:14 +08:00
rtrsp - > rt_delay_us = shortdelay_us ;
}
2014-01-28 03:49:39 +08:00
if ( ! preempt_count ( ) & &
2018-07-14 03:09:14 +08:00
! ( torture_random ( rrsp ) % ( nrealreaders * 500 ) ) ) {
2017-10-17 02:05:03 +08:00
torture_preempt_schedule ( ) ; /* QS only if preemptible. */
2018-07-14 03:09:14 +08:00
rtrsp - > rt_preempted = true ;
}
2006-10-04 17:17:03 +08:00
}
2022-12-17 01:47:28 +08:00
static void rcu_torture_read_unlock ( int idx )
2006-06-27 17:54:03 +08:00
{
rcu_read_unlock ( ) ;
}
2014-03-19 06:57:41 +08:00
/*
* Update callback in the pipe . This should be invoked after a grace period .
*/
static bool
rcu_torture_pipe_update_one ( struct rcu_torture * rp )
{
int i ;
2020-10-30 06:08:57 +08:00
struct rcu_torture_reader_check * rtrcp = READ_ONCE ( rp - > rtort_chkp ) ;
2014-03-19 06:57:41 +08:00
2020-10-30 06:08:57 +08:00
if ( rtrcp ) {
WRITE_ONCE ( rp - > rtort_chkp , NULL ) ;
smp_store_release ( & rtrcp - > rtc_ready , 1 ) ; // Pair with smp_load_acquire().
}
2019-12-22 02:41:48 +08:00
i = READ_ONCE ( rp - > rtort_pipe_count ) ;
2014-03-19 06:57:41 +08:00
if ( i > RCU_TORTURE_PIPE_LEN )
i = RCU_TORTURE_PIPE_LEN ;
atomic_inc ( & rcu_torture_wcount [ i ] ) ;
2019-12-22 02:41:48 +08:00
WRITE_ONCE ( rp - > rtort_pipe_count , i + 1 ) ;
if ( rp - > rtort_pipe_count > = RCU_TORTURE_PIPE_LEN ) {
2014-03-19 06:57:41 +08:00
rp - > rtort_mbtest = 0 ;
return true ;
}
return false ;
}
/*
* Update all callbacks in the pipe . Suitable for synchronous grace - period
* primitives .
*/
static void
rcu_torture_pipe_update ( struct rcu_torture * old_rp )
{
struct rcu_torture * rp ;
struct rcu_torture * rp1 ;
if ( old_rp )
list_add ( & old_rp - > rtort_free , & rcu_torture_removed ) ;
list_for_each_entry_safe ( rp , rp1 , & rcu_torture_removed , rtort_free ) {
if ( rcu_torture_pipe_update_one ( rp ) ) {
list_del ( & rp - > rtort_free ) ;
rcu_torture_free ( rp ) ;
}
}
}
2006-06-27 17:54:03 +08:00
static void
rcu_torture_cb ( struct rcu_head * p )
{
struct rcu_torture * rp = container_of ( p , struct rcu_torture , rtort_rcu ) ;
2014-01-31 07:49:29 +08:00
if ( torture_must_stop_irq ( ) ) {
2006-06-27 17:54:03 +08:00
/* Test is ending, just drop callbacks on the floor. */
/* The next initialization will pick up the pieces. */
return ;
}
2014-03-19 06:57:41 +08:00
if ( rcu_torture_pipe_update_one ( rp ) )
2006-06-27 17:54:03 +08:00
rcu_torture_free ( rp ) ;
2014-03-19 06:57:41 +08:00
else
2009-06-26 00:08:17 +08:00
cur_ops - > deferred_free ( rp ) ;
2006-06-27 17:54:03 +08:00
}
2014-11-22 06:19:26 +08:00
static unsigned long rcu_no_completed ( void )
2009-12-03 04:10:15 +08:00
{
return 0 ;
}
2006-06-27 17:54:03 +08:00
static void rcu_torture_deferred_free ( struct rcu_torture * p )
{
2022-10-17 00:23:01 +08:00
call_rcu_hurry ( & p - > rtort_rcu , rcu_torture_cb ) ;
2006-06-27 17:54:03 +08:00
}
2006-10-04 17:17:14 +08:00
static void rcu_sync_torture_init ( void )
{
INIT_LIST_HEAD ( & rcu_torture_removed ) ;
}
2022-08-02 07:57:17 +08:00
static bool rcu_poll_need_2gp ( bool poll , bool poll_full )
{
2022-08-05 09:05:46 +08:00
return poll ;
2022-08-02 07:57:17 +08:00
}
2013-06-13 06:12:21 +08:00
static struct rcu_torture_ops rcu_ops = {
2021-04-09 04:01:14 +08:00
. ttype = RCU_FLAVOR ,
. init = rcu_sync_torture_init ,
. readlock = rcu_torture_read_lock ,
. read_delay = rcu_read_delay ,
. readunlock = rcu_torture_read_unlock ,
. readlock_held = torture_readlock_not_held ,
. get_gp_seq = rcu_get_gp_seq ,
. gp_diff = rcu_seq_diff ,
. deferred_free = rcu_torture_deferred_free ,
. sync = synchronize_rcu ,
. exp_sync = synchronize_rcu_expedited ,
2022-08-26 06:47:09 +08:00
. same_gp_state = same_state_synchronize_rcu ,
2022-08-26 04:37:59 +08:00
. same_gp_state_full = same_state_synchronize_rcu_full ,
2022-08-26 06:47:09 +08:00
. get_comp_state = get_completed_synchronize_rcu ,
2022-08-26 04:37:59 +08:00
. get_comp_state_full = get_completed_synchronize_rcu_full ,
2021-04-09 04:01:14 +08:00
. get_gp_state = get_state_synchronize_rcu ,
2022-07-29 10:58:13 +08:00
. get_gp_state_full = get_state_synchronize_rcu_full ,
2022-04-14 07:14:02 +08:00
. get_gp_completed = get_completed_synchronize_rcu ,
2022-07-29 06:37:05 +08:00
. get_gp_completed_full = get_completed_synchronize_rcu_full ,
2021-04-09 04:01:14 +08:00
. start_gp_poll = start_poll_synchronize_rcu ,
2022-08-03 08:04:54 +08:00
. start_gp_poll_full = start_poll_synchronize_rcu_full ,
2021-04-09 04:01:14 +08:00
. poll_gp_state = poll_state_synchronize_rcu ,
2022-07-29 06:37:05 +08:00
. poll_gp_state_full = poll_state_synchronize_rcu_full ,
2022-08-02 07:57:17 +08:00
. poll_need_2gp = rcu_poll_need_2gp ,
2021-04-09 04:01:14 +08:00
. cond_sync = cond_synchronize_rcu ,
2022-08-05 04:46:05 +08:00
. cond_sync_full = cond_synchronize_rcu_full ,
2022-02-01 23:01:20 +08:00
. get_gp_state_exp = get_state_synchronize_rcu ,
. start_gp_poll_exp = start_poll_synchronize_rcu_expedited ,
2022-08-04 03:38:51 +08:00
. start_gp_poll_exp_full = start_poll_synchronize_rcu_expedited_full ,
2022-02-01 23:01:20 +08:00
. poll_gp_state_exp = poll_state_synchronize_rcu ,
. cond_sync_exp = cond_synchronize_rcu_expedited ,
2022-10-17 00:23:01 +08:00
. call = call_rcu_hurry ,
2021-04-09 04:01:14 +08:00
. cb_barrier = rcu_barrier ,
. fqs = rcu_force_quiescent_state ,
. stats = NULL ,
. gp_kthread_dbg = show_rcu_gp_kthreads ,
. check_boost_failed = rcu_check_boost_fail ,
. stall_dur = rcu_jiffies_till_stall_check ,
. irq_capable = 1 ,
. can_boost = IS_ENABLED ( CONFIG_RCU_BOOST ) ,
. extendables = RCUTORTURE_MAX_EXTEND ,
. name = " rcu "
2009-12-03 04:10:15 +08:00
} ;
2014-02-07 00:45:56 +08:00
/*
* Don ' t even think about trying any of these in real life ! ! !
* The names includes " busted " , and they really means it !
* The only purpose of these functions is to provide a buggy RCU
* implementation to make sure that rcutorture correctly emits
* buggy - RCU error messages .
*/
static void rcu_busted_torture_deferred_free ( struct rcu_torture * p )
{
/* This is a deliberate bug for testing purposes only! */
rcu_torture_cb ( & p - > rtort_rcu ) ;
}
static void synchronize_rcu_busted ( void )
{
/* This is a deliberate bug for testing purposes only! */
}
static void
2015-07-29 13:29:38 +08:00
call_rcu_busted ( struct rcu_head * head , rcu_callback_t func )
2014-02-07 00:45:56 +08:00
{
/* This is a deliberate bug for testing purposes only! */
func ( head ) ;
}
static struct rcu_torture_ops rcu_busted_ops = {
2014-02-20 02:51:42 +08:00
. ttype = INVALID_RCU_FLAVOR ,
2014-02-07 00:45:56 +08:00
. init = rcu_sync_torture_init ,
. readlock = rcu_torture_read_lock ,
. read_delay = rcu_read_delay , /* just reuse rcu's version. */
. readunlock = rcu_torture_read_unlock ,
2021-03-14 12:05:31 +08:00
. readlock_held = torture_readlock_not_held ,
2018-04-28 02:39:34 +08:00
. get_gp_seq = rcu_no_completed ,
2014-02-07 00:45:56 +08:00
. deferred_free = rcu_busted_torture_deferred_free ,
. sync = synchronize_rcu_busted ,
. exp_sync = synchronize_rcu_busted ,
. call = call_rcu_busted ,
. cb_barrier = NULL ,
. fqs = NULL ,
. stats = NULL ,
. irq_capable = 1 ,
2017-06-07 07:39:00 +08:00
. name = " busted "
2014-02-07 00:45:56 +08:00
} ;
2006-10-04 17:17:03 +08:00
/*
* Definitions for srcu torture testing .
*/
2012-10-13 01:14:17 +08:00
DEFINE_STATIC_SRCU ( srcu_ctl ) ;
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
static struct srcu_struct srcu_ctld ;
static struct srcu_struct * srcu_ctlp = & srcu_ctl ;
srcu: Create an srcu_read_lock_nmisafe() and srcu_read_unlock_nmisafe()
On strict load-store architectures, the use of this_cpu_inc() by
srcu_read_lock() and srcu_read_unlock() is not NMI-safe in TREE SRCU.
To see this suppose that an NMI arrives in the middle of srcu_read_lock(),
just after it has read ->srcu_lock_count, but before it has written
the incremented value back to memory. If that NMI handler also does
srcu_read_lock() and srcu_read_lock() on that same srcu_struct structure,
then upon return from that NMI handler, the interrupted srcu_read_lock()
will overwrite the NMI handler's update to ->srcu_lock_count, but
leave unchanged the NMI handler's update by srcu_read_unlock() to
->srcu_unlock_count.
This can result in a too-short SRCU grace period, which can in turn
result in arbitrary memory corruption.
If the NMI handler instead interrupts the srcu_read_unlock(), this
can result in eternal SRCU grace periods, which is not much better.
This commit therefore creates a pair of new srcu_read_lock_nmisafe()
and srcu_read_unlock_nmisafe() functions, which allow SRCU readers in
both NMI handlers and in process and IRQ context. It is bad practice
to mix the existing and the new _nmisafe() primitives on the same
srcu_struct structure. Use one set or the other, not both.
Just to underline that "bad practice" point, using srcu_read_lock() at
process level and srcu_read_lock_nmisafe() in your NMI handler will not,
repeat NOT, work. If you do not immediately understand why this is the
case, please review the earlier paragraphs in this commit log.
[ paulmck: Apply kernel test robot feedback. ]
[ paulmck: Apply feedback from Randy Dunlap. ]
[ paulmck: Apply feedback from John Ogness. ]
[ paulmck: Apply feedback from Frederic Weisbecker. ]
Link: https://lore.kernel.org/all/20220910221947.171557773@linutronix.de/
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
Acked-by: Randy Dunlap <rdunlap@infradead.org> # build-tested
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: Petr Mladek <pmladek@suse.com>
2022-09-16 05:29:07 +08:00
static struct rcu_torture_ops srcud_ops ;
2006-10-04 17:17:03 +08:00
2022-12-17 01:47:28 +08:00
static int srcu_torture_read_lock ( void )
2006-10-04 17:17:03 +08:00
{
srcu: Create an srcu_read_lock_nmisafe() and srcu_read_unlock_nmisafe()
On strict load-store architectures, the use of this_cpu_inc() by
srcu_read_lock() and srcu_read_unlock() is not NMI-safe in TREE SRCU.
To see this suppose that an NMI arrives in the middle of srcu_read_lock(),
just after it has read ->srcu_lock_count, but before it has written
the incremented value back to memory. If that NMI handler also does
srcu_read_lock() and srcu_read_lock() on that same srcu_struct structure,
then upon return from that NMI handler, the interrupted srcu_read_lock()
will overwrite the NMI handler's update to ->srcu_lock_count, but
leave unchanged the NMI handler's update by srcu_read_unlock() to
->srcu_unlock_count.
This can result in a too-short SRCU grace period, which can in turn
result in arbitrary memory corruption.
If the NMI handler instead interrupts the srcu_read_unlock(), this
can result in eternal SRCU grace periods, which is not much better.
This commit therefore creates a pair of new srcu_read_lock_nmisafe()
and srcu_read_unlock_nmisafe() functions, which allow SRCU readers in
both NMI handlers and in process and IRQ context. It is bad practice
to mix the existing and the new _nmisafe() primitives on the same
srcu_struct structure. Use one set or the other, not both.
Just to underline that "bad practice" point, using srcu_read_lock() at
process level and srcu_read_lock_nmisafe() in your NMI handler will not,
repeat NOT, work. If you do not immediately understand why this is the
case, please review the earlier paragraphs in this commit log.
[ paulmck: Apply kernel test robot feedback. ]
[ paulmck: Apply feedback from Randy Dunlap. ]
[ paulmck: Apply feedback from John Ogness. ]
[ paulmck: Apply feedback from Frederic Weisbecker. ]
Link: https://lore.kernel.org/all/20220910221947.171557773@linutronix.de/
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
Acked-by: Randy Dunlap <rdunlap@infradead.org> # build-tested
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: Petr Mladek <pmladek@suse.com>
2022-09-16 05:29:07 +08:00
if ( cur_ops = = & srcud_ops )
return srcu_read_lock_nmisafe ( srcu_ctlp ) ;
else
return srcu_read_lock ( srcu_ctlp ) ;
2006-10-04 17:17:03 +08:00
}
2018-07-14 03:09:14 +08:00
static void
srcu_read_delay ( struct torture_random_state * rrsp , struct rt_read_seg * rtrsp )
2006-10-04 17:17:03 +08:00
{
long delay ;
const long uspertick = 1000000 / HZ ;
const long longdelay = 10 ;
/* We want there to be long-running readers, but not all the time. */
2014-01-28 03:49:39 +08:00
delay = torture_random ( rrsp ) %
( nrealreaders * 2 * longdelay * uspertick ) ;
2018-07-14 03:09:14 +08:00
if ( ! delay & & in_task ( ) ) {
2006-10-04 17:17:03 +08:00
schedule_timeout_interruptible ( longdelay ) ;
2018-07-14 03:09:14 +08:00
rtrsp - > rt_delay_jiffies = longdelay ;
} else {
rcu_read_delay ( rrsp , rtrsp ) ;
}
2006-10-04 17:17:03 +08:00
}
2022-12-17 01:47:28 +08:00
static void srcu_torture_read_unlock ( int idx )
2006-10-04 17:17:03 +08:00
{
srcu: Create an srcu_read_lock_nmisafe() and srcu_read_unlock_nmisafe()
On strict load-store architectures, the use of this_cpu_inc() by
srcu_read_lock() and srcu_read_unlock() is not NMI-safe in TREE SRCU.
To see this suppose that an NMI arrives in the middle of srcu_read_lock(),
just after it has read ->srcu_lock_count, but before it has written
the incremented value back to memory. If that NMI handler also does
srcu_read_lock() and srcu_read_lock() on that same srcu_struct structure,
then upon return from that NMI handler, the interrupted srcu_read_lock()
will overwrite the NMI handler's update to ->srcu_lock_count, but
leave unchanged the NMI handler's update by srcu_read_unlock() to
->srcu_unlock_count.
This can result in a too-short SRCU grace period, which can in turn
result in arbitrary memory corruption.
If the NMI handler instead interrupts the srcu_read_unlock(), this
can result in eternal SRCU grace periods, which is not much better.
This commit therefore creates a pair of new srcu_read_lock_nmisafe()
and srcu_read_unlock_nmisafe() functions, which allow SRCU readers in
both NMI handlers and in process and IRQ context. It is bad practice
to mix the existing and the new _nmisafe() primitives on the same
srcu_struct structure. Use one set or the other, not both.
Just to underline that "bad practice" point, using srcu_read_lock() at
process level and srcu_read_lock_nmisafe() in your NMI handler will not,
repeat NOT, work. If you do not immediately understand why this is the
case, please review the earlier paragraphs in this commit log.
[ paulmck: Apply kernel test robot feedback. ]
[ paulmck: Apply feedback from Randy Dunlap. ]
[ paulmck: Apply feedback from John Ogness. ]
[ paulmck: Apply feedback from Frederic Weisbecker. ]
Link: https://lore.kernel.org/all/20220910221947.171557773@linutronix.de/
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
Acked-by: Randy Dunlap <rdunlap@infradead.org> # build-tested
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: Petr Mladek <pmladek@suse.com>
2022-09-16 05:29:07 +08:00
if ( cur_ops = = & srcud_ops )
srcu_read_unlock_nmisafe ( srcu_ctlp , idx ) ;
else
srcu_read_unlock ( srcu_ctlp , idx ) ;
2006-10-04 17:17:03 +08:00
}
2021-03-14 12:05:31 +08:00
static int torture_srcu_read_lock_held ( void )
{
return srcu_read_lock_held ( srcu_ctlp ) ;
}
2014-11-22 06:19:26 +08:00
static unsigned long srcu_torture_completed ( void )
2006-10-04 17:17:03 +08:00
{
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
return srcu_batches_completed ( srcu_ctlp ) ;
2006-10-04 17:17:03 +08:00
}
2012-03-19 16:12:14 +08:00
static void srcu_torture_deferred_free ( struct rcu_torture * rp )
{
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
call_srcu ( srcu_ctlp , & rp - > rtort_rcu , rcu_torture_cb ) ;
2012-03-19 16:12:14 +08:00
}
2006-10-04 17:17:13 +08:00
static void srcu_torture_synchronize ( void )
{
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
synchronize_srcu ( srcu_ctlp ) ;
2006-10-04 17:17:13 +08:00
}
2020-11-14 12:43:59 +08:00
static unsigned long srcu_torture_get_gp_state ( void )
{
return get_state_synchronize_srcu ( srcu_ctlp ) ;
}
static unsigned long srcu_torture_start_gp_poll ( void )
{
return start_poll_synchronize_srcu ( srcu_ctlp ) ;
}
static bool srcu_torture_poll_gp_state ( unsigned long oldstate )
{
return poll_state_synchronize_srcu ( srcu_ctlp , oldstate ) ;
}
2012-05-09 01:21:50 +08:00
static void srcu_torture_call ( struct rcu_head * head ,
2015-07-29 13:29:38 +08:00
rcu_callback_t func )
2012-05-09 01:21:50 +08:00
{
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
call_srcu ( srcu_ctlp , head , func ) ;
2012-05-09 01:21:50 +08:00
}
static void srcu_torture_barrier ( void )
{
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
srcu_barrier ( srcu_ctlp ) ;
2012-05-09 01:21:50 +08:00
}
2014-07-14 21:16:15 +08:00
static void srcu_torture_stats ( void )
2006-10-04 17:17:03 +08:00
{
2017-05-23 04:31:03 +08:00
srcu_torture_stats_print ( srcu_ctlp , torture_type , TORTURE_FLAG ) ;
2006-10-04 17:17:03 +08:00
}
2013-06-13 06:12:21 +08:00
static void srcu_torture_synchronize_expedited ( void )
{
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
synchronize_srcu_expedited ( srcu_ctlp ) ;
2013-06-13 06:12:21 +08:00
}
2006-10-04 17:17:03 +08:00
static struct rcu_torture_ops srcu_ops = {
2014-02-20 02:51:42 +08:00
. ttype = SRCU_FLAVOR ,
2012-10-13 01:14:17 +08:00
. init = rcu_sync_torture_init ,
2009-06-26 00:08:17 +08:00
. readlock = srcu_torture_read_lock ,
. read_delay = srcu_read_delay ,
. readunlock = srcu_torture_read_unlock ,
2021-03-14 12:05:31 +08:00
. readlock_held = torture_srcu_read_lock_held ,
2018-04-28 02:39:34 +08:00
. get_gp_seq = srcu_torture_completed ,
2012-03-19 16:12:14 +08:00
. deferred_free = srcu_torture_deferred_free ,
2009-06-26 00:08:17 +08:00
. sync = srcu_torture_synchronize ,
2013-06-13 06:12:21 +08:00
. exp_sync = srcu_torture_synchronize_expedited ,
2020-11-14 12:43:59 +08:00
. get_gp_state = srcu_torture_get_gp_state ,
. start_gp_poll = srcu_torture_start_gp_poll ,
. poll_gp_state = srcu_torture_poll_gp_state ,
2012-05-09 01:21:50 +08:00
. call = srcu_torture_call ,
. cb_barrier = srcu_torture_barrier ,
2009-06-26 00:08:17 +08:00
. stats = srcu_torture_stats ,
2022-01-28 12:29:10 +08:00
. cbflood_max = 50000 ,
2017-06-07 03:52:44 +08:00
. irq_capable = 1 ,
2021-09-25 12:30:26 +08:00
. no_pi_lock = IS_ENABLED ( CONFIG_TINY_SRCU ) ,
2009-06-26 00:08:17 +08:00
. name = " srcu "
2006-10-04 17:17:03 +08:00
} ;
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
static void srcu_torture_init ( void )
{
rcu_sync_torture_init ( ) ;
WARN_ON ( init_srcu_struct ( & srcu_ctld ) ) ;
srcu_ctlp = & srcu_ctld ;
}
static void srcu_torture_cleanup ( void )
{
2019-02-14 05:54:37 +08:00
cleanup_srcu_struct ( & srcu_ctld ) ;
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
srcu_ctlp = & srcu_ctl ; /* In case of a later rcutorture run. */
}
/* As above, but dynamically allocated. */
static struct rcu_torture_ops srcud_ops = {
. ttype = SRCU_FLAVOR ,
. init = srcu_torture_init ,
. cleanup = srcu_torture_cleanup ,
. readlock = srcu_torture_read_lock ,
. read_delay = srcu_read_delay ,
. readunlock = srcu_torture_read_unlock ,
2021-03-14 12:05:31 +08:00
. readlock_held = torture_srcu_read_lock_held ,
2018-04-28 02:39:34 +08:00
. get_gp_seq = srcu_torture_completed ,
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
. deferred_free = srcu_torture_deferred_free ,
. sync = srcu_torture_synchronize ,
. exp_sync = srcu_torture_synchronize_expedited ,
2022-07-28 07:16:41 +08:00
. get_gp_state = srcu_torture_get_gp_state ,
. start_gp_poll = srcu_torture_start_gp_poll ,
. poll_gp_state = srcu_torture_poll_gp_state ,
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
. call = srcu_torture_call ,
. cb_barrier = srcu_torture_barrier ,
. stats = srcu_torture_stats ,
2022-01-28 12:29:10 +08:00
. cbflood_max = 50000 ,
2017-06-07 03:52:44 +08:00
. irq_capable = 1 ,
2021-09-25 12:30:26 +08:00
. no_pi_lock = IS_ENABLED ( CONFIG_TINY_SRCU ) ,
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
. name = " srcud "
} ;
2018-05-25 22:29:25 +08:00
/* As above, but broken due to inappropriate reader extension. */
static struct rcu_torture_ops busted_srcud_ops = {
. ttype = SRCU_FLAVOR ,
. init = srcu_torture_init ,
. cleanup = srcu_torture_cleanup ,
. readlock = srcu_torture_read_lock ,
. read_delay = rcu_read_delay ,
. readunlock = srcu_torture_read_unlock ,
2021-03-14 12:05:31 +08:00
. readlock_held = torture_srcu_read_lock_held ,
2018-05-25 22:29:25 +08:00
. get_gp_seq = srcu_torture_completed ,
. deferred_free = srcu_torture_deferred_free ,
. sync = srcu_torture_synchronize ,
. exp_sync = srcu_torture_synchronize_expedited ,
. call = srcu_torture_call ,
. cb_barrier = srcu_torture_barrier ,
. stats = srcu_torture_stats ,
. irq_capable = 1 ,
2021-09-25 12:30:26 +08:00
. no_pi_lock = IS_ENABLED ( CONFIG_TINY_SRCU ) ,
2018-05-25 22:29:25 +08:00
. extendables = RCUTORTURE_MAX_EXTEND ,
. name = " busted_srcud "
} ;
2022-03-18 04:29:59 +08:00
/*
* Definitions for trivial CONFIG_PREEMPT = n - only torture testing .
* This implementation does not necessarily work well with CPU hotplug .
*/
static void synchronize_rcu_trivial ( void )
{
int cpu ;
for_each_online_cpu ( cpu ) {
rcutorture_sched_setaffinity ( current - > pid , cpumask_of ( cpu ) ) ;
WARN_ON_ONCE ( raw_smp_processor_id ( ) ! = cpu ) ;
}
}
2022-12-17 01:47:28 +08:00
static int rcu_torture_read_lock_trivial ( void )
2022-03-18 04:29:59 +08:00
{
preempt_disable ( ) ;
return 0 ;
}
2022-12-17 01:47:28 +08:00
static void rcu_torture_read_unlock_trivial ( int idx )
2022-03-18 04:29:59 +08:00
{
preempt_enable ( ) ;
}
static struct rcu_torture_ops trivial_ops = {
. ttype = RCU_TRIVIAL_FLAVOR ,
. init = rcu_sync_torture_init ,
. readlock = rcu_torture_read_lock_trivial ,
. read_delay = rcu_read_delay , /* just reuse rcu's version. */
. readunlock = rcu_torture_read_unlock_trivial ,
. readlock_held = torture_readlock_not_held ,
. get_gp_seq = rcu_no_completed ,
. sync = synchronize_rcu_trivial ,
. exp_sync = synchronize_rcu_trivial ,
. fqs = NULL ,
. stats = NULL ,
. irq_capable = 1 ,
. name = " trivial "
} ;
2022-03-18 06:18:27 +08:00
# ifdef CONFIG_TASKS_RCU
2014-07-02 02:59:36 +08:00
/*
* Definitions for RCU - tasks torture testing .
*/
static int tasks_torture_read_lock ( void )
{
return 0 ;
}
static void tasks_torture_read_unlock ( int idx )
{
}
static void rcu_tasks_torture_deferred_free ( struct rcu_torture * p )
{
call_rcu_tasks ( & p - > rtort_rcu , rcu_torture_cb ) ;
}
2020-03-07 06:00:46 +08:00
static void synchronize_rcu_mult_test ( void )
{
2022-10-17 00:23:01 +08:00
synchronize_rcu_mult ( call_rcu_tasks , call_rcu_hurry ) ;
2020-03-07 06:00:46 +08:00
}
2014-07-02 02:59:36 +08:00
static struct rcu_torture_ops tasks_ops = {
. ttype = RCU_TASKS_FLAVOR ,
. init = rcu_sync_torture_init ,
. readlock = tasks_torture_read_lock ,
. read_delay = rcu_read_delay , /* just reuse rcu's version. */
. readunlock = tasks_torture_read_unlock ,
2018-04-28 02:39:34 +08:00
. get_gp_seq = rcu_no_completed ,
2014-07-02 02:59:36 +08:00
. deferred_free = rcu_tasks_torture_deferred_free ,
. sync = synchronize_rcu_tasks ,
2020-03-07 06:00:46 +08:00
. exp_sync = synchronize_rcu_mult_test ,
2014-07-02 02:59:36 +08:00
. call = call_rcu_tasks ,
. cb_barrier = rcu_barrier_tasks ,
2020-09-16 08:08:03 +08:00
. gp_kthread_dbg = show_rcu_tasks_classic_gp_kthread ,
2014-07-02 02:59:36 +08:00
. fqs = NULL ,
. stats = NULL ,
. irq_capable = 1 ,
2019-04-13 00:02:46 +08:00
. slow_gps = 1 ,
2014-07-02 02:59:36 +08:00
. name = " tasks "
} ;
2022-03-18 06:18:27 +08:00
# define TASKS_OPS &tasks_ops,
rcutorture: Add trivial RCU implementation
I have been showing off a trivial RCU implementation for non-preemptive
environments for some time now:
#define rcu_read_lock()
#define rcu_read_unlock()
#define rcu_dereference(p) READ_ONCE(p)
#define rcu_assign_pointer(p, v) smp_store_release(&(p), (v))
void synchronize_rcu(void)
{
int cpu;
for_each_online_cpu(cpu)
sched_setaffinity(current->pid, cpumask_of(cpu));
}
Trivial or not, as the old saying goes, "if it ain't tested, it don't
work!". This commit therefore adds a "trivial" flavor to rcutorture
and a corresponding TRIVIAL test scenario. This variant does not handle
CPU hotplug, which is unconditionally enabled on x86 for post-v5.1-rc3
kernels, which is why the TRIVIAL.boot says "rcutorture.onoff_interval=0".
This commit actually does handle CONFIG_PREEMPT=y kernels, but only
because it turns back the Linux-kernel clock in order to provide these
alternative definitions (or the moral equivalent thereof):
#define rcu_read_lock() preempt_disable()
#define rcu_read_unlock() preempt_enable()
In CONFIG_PREEMPT=n kernels without debugging, these are equivalent to
empty macros give or take a compiler barrier. However, the have been
successfully tested with actual empty macros as well.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
[ paulmck: Fix symbol issue reported by kbuild test robot <lkp@intel.com>. ]
[ paulmck: Work around sched_setaffinity() issue noted by Andrea Parri. ]
[ paulmck: Add rcutorture.shuffle_interval=0 to TRIVIAL.boot to fix
interaction with shuffler task noted by Peter Zijlstra. ]
Tested-by: Andrea Parri <andrea.parri@amarulasolutions.com>
2019-04-19 22:38:27 +08:00
2022-03-18 06:18:27 +08:00
# else // #ifdef CONFIG_TASKS_RCU
rcutorture: Add trivial RCU implementation
I have been showing off a trivial RCU implementation for non-preemptive
environments for some time now:
#define rcu_read_lock()
#define rcu_read_unlock()
#define rcu_dereference(p) READ_ONCE(p)
#define rcu_assign_pointer(p, v) smp_store_release(&(p), (v))
void synchronize_rcu(void)
{
int cpu;
for_each_online_cpu(cpu)
sched_setaffinity(current->pid, cpumask_of(cpu));
}
Trivial or not, as the old saying goes, "if it ain't tested, it don't
work!". This commit therefore adds a "trivial" flavor to rcutorture
and a corresponding TRIVIAL test scenario. This variant does not handle
CPU hotplug, which is unconditionally enabled on x86 for post-v5.1-rc3
kernels, which is why the TRIVIAL.boot says "rcutorture.onoff_interval=0".
This commit actually does handle CONFIG_PREEMPT=y kernels, but only
because it turns back the Linux-kernel clock in order to provide these
alternative definitions (or the moral equivalent thereof):
#define rcu_read_lock() preempt_disable()
#define rcu_read_unlock() preempt_enable()
In CONFIG_PREEMPT=n kernels without debugging, these are equivalent to
empty macros give or take a compiler barrier. However, the have been
successfully tested with actual empty macros as well.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
[ paulmck: Fix symbol issue reported by kbuild test robot <lkp@intel.com>. ]
[ paulmck: Work around sched_setaffinity() issue noted by Andrea Parri. ]
[ paulmck: Add rcutorture.shuffle_interval=0 to TRIVIAL.boot to fix
interaction with shuffler task noted by Peter Zijlstra. ]
Tested-by: Andrea Parri <andrea.parri@amarulasolutions.com>
2019-04-19 22:38:27 +08:00
2022-03-18 06:18:27 +08:00
# define TASKS_OPS
rcutorture: Add trivial RCU implementation
I have been showing off a trivial RCU implementation for non-preemptive
environments for some time now:
#define rcu_read_lock()
#define rcu_read_unlock()
#define rcu_dereference(p) READ_ONCE(p)
#define rcu_assign_pointer(p, v) smp_store_release(&(p), (v))
void synchronize_rcu(void)
{
int cpu;
for_each_online_cpu(cpu)
sched_setaffinity(current->pid, cpumask_of(cpu));
}
Trivial or not, as the old saying goes, "if it ain't tested, it don't
work!". This commit therefore adds a "trivial" flavor to rcutorture
and a corresponding TRIVIAL test scenario. This variant does not handle
CPU hotplug, which is unconditionally enabled on x86 for post-v5.1-rc3
kernels, which is why the TRIVIAL.boot says "rcutorture.onoff_interval=0".
This commit actually does handle CONFIG_PREEMPT=y kernels, but only
because it turns back the Linux-kernel clock in order to provide these
alternative definitions (or the moral equivalent thereof):
#define rcu_read_lock() preempt_disable()
#define rcu_read_unlock() preempt_enable()
In CONFIG_PREEMPT=n kernels without debugging, these are equivalent to
empty macros give or take a compiler barrier. However, the have been
successfully tested with actual empty macros as well.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
[ paulmck: Fix symbol issue reported by kbuild test robot <lkp@intel.com>. ]
[ paulmck: Work around sched_setaffinity() issue noted by Andrea Parri. ]
[ paulmck: Add rcutorture.shuffle_interval=0 to TRIVIAL.boot to fix
interaction with shuffler task noted by Peter Zijlstra. ]
Tested-by: Andrea Parri <andrea.parri@amarulasolutions.com>
2019-04-19 22:38:27 +08:00
2022-03-18 06:18:27 +08:00
# endif // #else #ifdef CONFIG_TASKS_RCU
rcutorture: Add trivial RCU implementation
I have been showing off a trivial RCU implementation for non-preemptive
environments for some time now:
#define rcu_read_lock()
#define rcu_read_unlock()
#define rcu_dereference(p) READ_ONCE(p)
#define rcu_assign_pointer(p, v) smp_store_release(&(p), (v))
void synchronize_rcu(void)
{
int cpu;
for_each_online_cpu(cpu)
sched_setaffinity(current->pid, cpumask_of(cpu));
}
Trivial or not, as the old saying goes, "if it ain't tested, it don't
work!". This commit therefore adds a "trivial" flavor to rcutorture
and a corresponding TRIVIAL test scenario. This variant does not handle
CPU hotplug, which is unconditionally enabled on x86 for post-v5.1-rc3
kernels, which is why the TRIVIAL.boot says "rcutorture.onoff_interval=0".
This commit actually does handle CONFIG_PREEMPT=y kernels, but only
because it turns back the Linux-kernel clock in order to provide these
alternative definitions (or the moral equivalent thereof):
#define rcu_read_lock() preempt_disable()
#define rcu_read_unlock() preempt_enable()
In CONFIG_PREEMPT=n kernels without debugging, these are equivalent to
empty macros give or take a compiler barrier. However, the have been
successfully tested with actual empty macros as well.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
[ paulmck: Fix symbol issue reported by kbuild test robot <lkp@intel.com>. ]
[ paulmck: Work around sched_setaffinity() issue noted by Andrea Parri. ]
[ paulmck: Add rcutorture.shuffle_interval=0 to TRIVIAL.boot to fix
interaction with shuffler task noted by Peter Zijlstra. ]
Tested-by: Andrea Parri <andrea.parri@amarulasolutions.com>
2019-04-19 22:38:27 +08:00
2022-03-18 07:16:45 +08:00
# ifdef CONFIG_TASKS_RUDE_RCU
rcutorture: Add trivial RCU implementation
I have been showing off a trivial RCU implementation for non-preemptive
environments for some time now:
#define rcu_read_lock()
#define rcu_read_unlock()
#define rcu_dereference(p) READ_ONCE(p)
#define rcu_assign_pointer(p, v) smp_store_release(&(p), (v))
void synchronize_rcu(void)
{
int cpu;
for_each_online_cpu(cpu)
sched_setaffinity(current->pid, cpumask_of(cpu));
}
Trivial or not, as the old saying goes, "if it ain't tested, it don't
work!". This commit therefore adds a "trivial" flavor to rcutorture
and a corresponding TRIVIAL test scenario. This variant does not handle
CPU hotplug, which is unconditionally enabled on x86 for post-v5.1-rc3
kernels, which is why the TRIVIAL.boot says "rcutorture.onoff_interval=0".
This commit actually does handle CONFIG_PREEMPT=y kernels, but only
because it turns back the Linux-kernel clock in order to provide these
alternative definitions (or the moral equivalent thereof):
#define rcu_read_lock() preempt_disable()
#define rcu_read_unlock() preempt_enable()
In CONFIG_PREEMPT=n kernels without debugging, these are equivalent to
empty macros give or take a compiler barrier. However, the have been
successfully tested with actual empty macros as well.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
[ paulmck: Fix symbol issue reported by kbuild test robot <lkp@intel.com>. ]
[ paulmck: Work around sched_setaffinity() issue noted by Andrea Parri. ]
[ paulmck: Add rcutorture.shuffle_interval=0 to TRIVIAL.boot to fix
interaction with shuffler task noted by Peter Zijlstra. ]
Tested-by: Andrea Parri <andrea.parri@amarulasolutions.com>
2019-04-19 22:38:27 +08:00
2020-03-04 07:02:50 +08:00
/*
* Definitions for rude RCU - tasks torture testing .
*/
static void rcu_tasks_rude_torture_deferred_free ( struct rcu_torture * p )
{
call_rcu_tasks_rude ( & p - > rtort_rcu , rcu_torture_cb ) ;
}
static struct rcu_torture_ops tasks_rude_ops = {
. ttype = RCU_TASKS_RUDE_FLAVOR ,
. init = rcu_sync_torture_init ,
. readlock = rcu_torture_read_lock_trivial ,
. read_delay = rcu_read_delay , /* just reuse rcu's version. */
. readunlock = rcu_torture_read_unlock_trivial ,
. get_gp_seq = rcu_no_completed ,
. deferred_free = rcu_tasks_rude_torture_deferred_free ,
. sync = synchronize_rcu_tasks_rude ,
. exp_sync = synchronize_rcu_tasks_rude ,
. call = call_rcu_tasks_rude ,
. cb_barrier = rcu_barrier_tasks_rude ,
2020-09-16 08:08:03 +08:00
. gp_kthread_dbg = show_rcu_tasks_rude_gp_kthread ,
2021-11-24 03:53:52 +08:00
. cbflood_max = 50000 ,
2020-03-04 07:02:50 +08:00
. fqs = NULL ,
. stats = NULL ,
. irq_capable = 1 ,
. name = " tasks-rude "
} ;
2022-03-18 07:16:45 +08:00
# define TASKS_RUDE_OPS &tasks_rude_ops,
# else // #ifdef CONFIG_TASKS_RUDE_RCU
# define TASKS_RUDE_OPS
# endif // #else #ifdef CONFIG_TASKS_RUDE_RCU
2022-03-18 04:29:59 +08:00
# ifdef CONFIG_TASKS_TRACE_RCU
2020-03-11 01:32:30 +08:00
/*
* Definitions for tracing RCU - tasks torture testing .
*/
static int tasks_tracing_torture_read_lock ( void )
{
rcu_read_lock_trace ( ) ;
return 0 ;
}
static void tasks_tracing_torture_read_unlock ( int idx )
{
rcu_read_unlock_trace ( ) ;
}
static void rcu_tasks_tracing_torture_deferred_free ( struct rcu_torture * p )
{
call_rcu_tasks_trace ( & p - > rtort_rcu , rcu_torture_cb ) ;
}
static struct rcu_torture_ops tasks_tracing_ops = {
. ttype = RCU_TASKS_TRACING_FLAVOR ,
. init = rcu_sync_torture_init ,
. readlock = tasks_tracing_torture_read_lock ,
. read_delay = srcu_read_delay , /* just reuse srcu's version. */
. readunlock = tasks_tracing_torture_read_unlock ,
2021-03-14 12:05:31 +08:00
. readlock_held = rcu_read_lock_trace_held ,
2020-03-11 01:32:30 +08:00
. get_gp_seq = rcu_no_completed ,
. deferred_free = rcu_tasks_tracing_torture_deferred_free ,
. sync = synchronize_rcu_tasks_trace ,
. exp_sync = synchronize_rcu_tasks_trace ,
. call = call_rcu_tasks_trace ,
. cb_barrier = rcu_barrier_tasks_trace ,
2020-09-16 08:08:03 +08:00
. gp_kthread_dbg = show_rcu_tasks_trace_gp_kthread ,
2021-11-24 03:53:52 +08:00
. cbflood_max = 50000 ,
2020-03-11 01:32:30 +08:00
. fqs = NULL ,
. stats = NULL ,
. irq_capable = 1 ,
. slow_gps = 1 ,
. name = " tasks-tracing "
} ;
2022-03-18 04:29:59 +08:00
# define TASKS_TRACING_OPS &tasks_tracing_ops,
# else // #ifdef CONFIG_TASKS_TRACE_RCU
# define TASKS_TRACING_OPS
# endif // #else #ifdef CONFIG_TASKS_TRACE_RCU
2018-05-16 06:24:41 +08:00
static unsigned long rcutorture_seq_diff ( unsigned long new , unsigned long old )
{
if ( ! cur_ops - > gp_diff )
return new - old ;
return cur_ops - > gp_diff ( new , old ) ;
}
2010-09-03 07:16:14 +08:00
/*
* RCU torture priority - boost testing . Runs one real - time thread per
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
* CPU for moderate bursts , repeatedly starting grace periods and waiting
* for them to complete . If a given grace period takes too long , we assume
* that priority inversion has occurred .
2010-09-03 07:16:14 +08:00
*/
2018-06-11 07:45:43 +08:00
static int old_rt_runtime = - 1 ;
static void rcu_torture_disable_rt_throttle ( void )
{
/*
* Disable RT throttling so that rcutorture ' s boost threads don ' t get
* throttled . Only possible if rcutorture is built - in otherwise the
* user should manually do this by setting the sched_rt_period_us and
* sched_rt_runtime sysctls .
*/
if ( ! IS_BUILTIN ( CONFIG_RCU_TORTURE_TEST ) | | old_rt_runtime ! = - 1 )
return ;
old_rt_runtime = sysctl_sched_rt_runtime ;
sysctl_sched_rt_runtime = - 1 ;
}
static void rcu_torture_enable_rt_throttle ( void )
{
if ( ! IS_BUILTIN ( CONFIG_RCU_TORTURE_TEST ) | | old_rt_runtime = = - 1 )
return ;
sysctl_sched_rt_runtime = old_rt_runtime ;
old_rt_runtime = - 1 ;
}
2021-04-15 04:00:10 +08:00
static bool rcu_torture_boost_failed ( unsigned long gp_state , unsigned long * start )
2018-06-11 07:45:44 +08:00
{
2021-04-09 04:01:14 +08:00
int cpu ;
2021-01-16 05:30:38 +08:00
static int dbg_done ;
2021-04-15 04:00:10 +08:00
unsigned long end = jiffies ;
2021-04-09 01:46:55 +08:00
bool gp_done ;
2021-04-09 04:01:14 +08:00
unsigned long j ;
static unsigned long last_persist ;
unsigned long lp ;
unsigned long mininterval = test_boost_duration * HZ - HZ / 2 ;
2021-01-16 05:30:38 +08:00
2021-04-15 04:00:10 +08:00
if ( end - * start > mininterval ) {
2021-04-08 08:09:37 +08:00
// Recheck after checking time to avoid false positives.
smp_mb ( ) ; // Time check before grace-period check.
if ( cur_ops - > poll_gp_state ( gp_state ) )
return false ; // passed, though perhaps just barely
2021-04-09 04:01:14 +08:00
if ( cur_ops - > check_boost_failed & & ! cur_ops - > check_boost_failed ( gp_state , & cpu ) ) {
// At most one persisted message per boost test.
j = jiffies ;
lp = READ_ONCE ( last_persist ) ;
if ( time_after ( j , lp + mininterval ) & & cmpxchg ( & last_persist , lp , j ) = = lp )
pr_info ( " Boost inversion persisted: No QS from CPU %d \n " , cpu ) ;
return false ; // passed on a technicality
}
2018-06-11 07:45:44 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_boost boosting failed " ) ;
n_rcu_torture_boost_failure + + ;
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
if ( ! xchg ( & dbg_done , 1 ) & & cur_ops - > gp_kthread_dbg ) {
pr_info ( " Boost inversion thread ->rt_priority %u gp_state %lu jiffies %lu \n " ,
2021-04-15 04:00:10 +08:00
current - > rt_priority , gp_state , end - * start ) ;
2021-01-16 05:30:38 +08:00
cur_ops - > gp_kthread_dbg ( ) ;
2021-04-09 01:46:55 +08:00
// Recheck after print to flag grace period ending during splat.
gp_done = cur_ops - > poll_gp_state ( gp_state ) ;
pr_info ( " Boost inversion: GP %lu %s. \n " , gp_state ,
gp_done ? " ended already " : " still pending " ) ;
2018-06-11 07:45:44 +08:00
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
}
2018-06-11 07:45:44 +08:00
2021-04-08 08:09:37 +08:00
return true ; // failed
2021-04-15 04:00:10 +08:00
} else if ( cur_ops - > check_boost_failed & & ! cur_ops - > check_boost_failed ( gp_state , NULL ) ) {
* start = jiffies ;
2018-06-11 07:45:44 +08:00
}
2021-04-08 08:09:37 +08:00
return false ; // passed
2018-06-11 07:45:44 +08:00
}
2010-09-03 07:16:14 +08:00
static int rcu_torture_boost ( void * arg )
{
unsigned long endtime ;
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
unsigned long gp_state ;
unsigned long gp_state_time ;
2010-09-03 07:16:14 +08:00
unsigned long oldstarttime ;
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_boost started " ) ;
2010-09-03 07:16:14 +08:00
/* Set real-time priority. */
2020-04-22 19:10:04 +08:00
sched_set_fifo_low ( current ) ;
2010-09-03 07:16:14 +08:00
/* Each pass through the following loop does one boost-test cycle. */
do {
2021-01-16 05:30:38 +08:00
bool failed = false ; // Test failed already in this test interval
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
bool gp_initiated = false ;
2018-06-11 07:45:44 +08:00
if ( kthread_should_stop ( ) )
goto checkwait ;
2010-09-03 07:16:14 +08:00
/* Wait for the next test interval. */
2021-12-14 03:05:07 +08:00
oldstarttime = READ_ONCE ( boost_starttime ) ;
2020-04-11 06:37:12 +08:00
while ( time_before ( jiffies , oldstarttime ) ) {
2013-01-11 08:21:07 +08:00
schedule_timeout_interruptible ( oldstarttime - jiffies ) ;
2020-09-23 07:42:42 +08:00
if ( stutter_wait ( " rcu_torture_boost " ) )
sched_set_fifo_low ( current ) ;
2014-01-31 07:49:29 +08:00
if ( torture_must_stop ( ) )
2010-09-03 07:16:14 +08:00
goto checkwait ;
}
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
// Do one boost-test interval.
2010-09-03 07:16:14 +08:00
endtime = oldstarttime + test_boost_duration * HZ ;
2020-04-11 06:37:12 +08:00
while ( time_before ( jiffies , endtime ) ) {
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
// Has current GP gone too long?
if ( gp_initiated & & ! failed & & ! cur_ops - > poll_gp_state ( gp_state ) )
2021-04-15 04:00:10 +08:00
failed = rcu_torture_boost_failed ( gp_state , & gp_state_time ) ;
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
// If we don't have a grace period in flight, start one.
if ( ! gp_initiated | | cur_ops - > poll_gp_state ( gp_state ) ) {
gp_state = cur_ops - > start_gp_poll ( ) ;
gp_initiated = true ;
gp_state_time = jiffies ;
2010-09-03 07:16:14 +08:00
}
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
if ( stutter_wait ( " rcu_torture_boost " ) ) {
2020-09-23 07:42:42 +08:00
sched_set_fifo_low ( current ) ;
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
// If the grace period already ended,
// we don't know when that happened, so
// start over.
if ( cur_ops - > poll_gp_state ( gp_state ) )
gp_initiated = false ;
}
2014-01-31 07:49:29 +08:00
if ( torture_must_stop ( ) )
2010-09-03 07:16:14 +08:00
goto checkwait ;
}
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
// In case the grace period extended beyond the end of the loop.
if ( gp_initiated & & ! failed & & ! cur_ops - > poll_gp_state ( gp_state ) )
2021-04-15 04:00:10 +08:00
rcu_torture_boost_failed ( gp_state , & gp_state_time ) ;
2018-06-11 07:45:44 +08:00
2010-09-03 07:16:14 +08:00
/*
* Set the start time of the next test interval .
* Yes , this is vulnerable to long delays , but such
* delays simply cause a false negative for the next
* interval . Besides , we are running at RT priority ,
* so delays should be relatively rare .
*/
2021-12-14 03:05:07 +08:00
while ( oldstarttime = = READ_ONCE ( boost_starttime ) & & ! kthread_should_stop ( ) ) {
2010-09-03 07:16:14 +08:00
if ( mutex_trylock ( & boost_mutex ) ) {
2021-04-08 11:00:00 +08:00
if ( oldstarttime = = boost_starttime ) {
2021-12-14 03:05:07 +08:00
WRITE_ONCE ( boost_starttime ,
jiffies + test_boost_interval * HZ ) ;
2021-04-08 11:00:00 +08:00
n_rcu_torture_boosts + + ;
}
2010-09-03 07:16:14 +08:00
mutex_unlock ( & boost_mutex ) ;
break ;
}
schedule_timeout_uninterruptible ( 1 ) ;
}
/* Go do the stutter. */
2020-09-23 07:42:42 +08:00
checkwait : if ( stutter_wait ( " rcu_torture_boost " ) )
sched_set_fifo_low ( current ) ;
2014-01-31 07:49:29 +08:00
} while ( ! torture_must_stop ( ) ) ;
2010-09-03 07:16:14 +08:00
/* Clean up and exit. */
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
while ( ! kthread_should_stop ( ) ) {
2014-02-01 09:37:28 +08:00
torture_shutdown_absorb ( " rcu_torture_boost " ) ;
2010-09-03 07:16:14 +08:00
schedule_timeout_uninterruptible ( 1 ) ;
2014-02-01 09:37:28 +08:00
}
torture_kthread_stopping ( " rcu_torture_boost " ) ;
2010-09-03 07:16:14 +08:00
return 0 ;
}
2010-01-05 07:09:10 +08:00
/*
* RCU torture force - quiescent - state kthread . Repeatedly induces
* bursts of calls to force_quiescent_state ( ) , increasing the probability
* of occurrence of some important types of race conditions .
*/
static int
rcu_torture_fqs ( void * arg )
{
unsigned long fqs_resume_time ;
int fqs_burst_remaining ;
2020-09-23 07:42:42 +08:00
int oldnice = task_nice ( current ) ;
2010-01-05 07:09:10 +08:00
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_fqs task started " ) ;
2010-01-05 07:09:10 +08:00
do {
fqs_resume_time = jiffies + fqs_stutter * HZ ;
2020-04-11 06:37:12 +08:00
while ( time_before ( jiffies , fqs_resume_time ) & &
2011-08-18 03:39:34 +08:00
! kthread_should_stop ( ) ) {
2010-01-05 07:09:10 +08:00
schedule_timeout_interruptible ( 1 ) ;
}
fqs_burst_remaining = fqs_duration ;
2011-08-18 03:39:34 +08:00
while ( fqs_burst_remaining > 0 & &
! kthread_should_stop ( ) ) {
2010-01-05 07:09:10 +08:00
cur_ops - > fqs ( ) ;
udelay ( fqs_holdoff ) ;
fqs_burst_remaining - = fqs_holdoff ;
}
2020-09-23 07:42:42 +08:00
if ( stutter_wait ( " rcu_torture_fqs " ) )
sched_set_normal ( current , oldnice ) ;
2014-01-31 07:49:29 +08:00
} while ( ! torture_must_stop ( ) ) ;
2014-02-01 09:37:28 +08:00
torture_kthread_stopping ( " rcu_torture_fqs " ) ;
2010-01-05 07:09:10 +08:00
return 0 ;
}
2022-02-01 23:01:20 +08:00
// Used by writers to randomly choose from the available grace-period primitives.
static int synctype [ ARRAY_SIZE ( rcu_torture_writer_state_names ) ] = { } ;
2020-11-17 08:46:06 +08:00
static int nsynctypes ;
2005-10-31 07:03:12 +08:00
/*
2020-11-17 08:46:06 +08:00
* Determine which grace - period primitives are available .
2005-10-31 07:03:12 +08:00
*/
2020-11-17 08:46:06 +08:00
static void rcu_torture_write_types ( void )
2005-10-31 07:03:12 +08:00
{
2022-08-05 04:46:05 +08:00
bool gp_cond1 = gp_cond , gp_cond_exp1 = gp_cond_exp , gp_cond_full1 = gp_cond_full ;
2022-08-05 06:23:26 +08:00
bool gp_cond_exp_full1 = gp_cond_exp_full , gp_exp1 = gp_exp , gp_poll_exp1 = gp_poll_exp ;
bool gp_poll_exp_full1 = gp_poll_exp_full , gp_normal1 = gp_normal , gp_poll1 = gp_poll ;
bool gp_poll_full1 = gp_poll_full , gp_sync1 = gp_sync ;
2005-11-14 08:07:22 +08:00
2014-03-19 06:57:41 +08:00
/* Initialize synctype[] array. If none set, take default. */
2022-08-24 03:11:12 +08:00
if ( ! gp_cond1 & &
! gp_cond_exp1 & &
! gp_cond_full1 & &
! gp_cond_exp_full1 & &
! gp_exp1 & &
! gp_poll_exp1 & &
! gp_poll_exp_full1 & &
! gp_normal1 & &
! gp_poll1 & &
! gp_poll_full1 & &
! gp_sync1 ) {
gp_cond1 = true ;
gp_cond_exp1 = true ;
gp_cond_full1 = true ;
gp_cond_exp_full1 = true ;
gp_exp1 = true ;
gp_poll_exp1 = true ;
gp_poll_exp_full1 = true ;
gp_normal1 = true ;
gp_poll1 = true ;
gp_poll_full1 = true ;
gp_sync1 = true ;
}
2020-11-14 12:14:27 +08:00
if ( gp_cond1 & & cur_ops - > get_gp_state & & cur_ops - > cond_sync ) {
2014-03-19 06:57:41 +08:00
synctype [ nsynctypes + + ] = RTWS_COND_GET ;
2017-12-09 04:23:10 +08:00
pr_info ( " %s: Testing conditional GPs. \n " , __func__ ) ;
2020-11-14 12:14:27 +08:00
} else if ( gp_cond & & ( ! cur_ops - > get_gp_state | | ! cur_ops - > cond_sync ) ) {
2017-12-02 07:22:38 +08:00
pr_alert ( " %s: gp_cond without primitives. \n " , __func__ ) ;
2017-12-09 04:23:10 +08:00
}
2022-02-01 23:01:20 +08:00
if ( gp_cond_exp1 & & cur_ops - > get_gp_state_exp & & cur_ops - > cond_sync_exp ) {
synctype [ nsynctypes + + ] = RTWS_COND_GET_EXP ;
pr_info ( " %s: Testing conditional expedited GPs. \n " , __func__ ) ;
} else if ( gp_cond_exp & & ( ! cur_ops - > get_gp_state_exp | | ! cur_ops - > cond_sync_exp ) ) {
pr_alert ( " %s: gp_cond_exp without primitives. \n " , __func__ ) ;
}
2022-08-05 04:46:05 +08:00
if ( gp_cond_full1 & & cur_ops - > get_gp_state & & cur_ops - > cond_sync_full ) {
synctype [ nsynctypes + + ] = RTWS_COND_GET_FULL ;
pr_info ( " %s: Testing conditional full-state GPs. \n " , __func__ ) ;
} else if ( gp_cond_full & & ( ! cur_ops - > get_gp_state | | ! cur_ops - > cond_sync_full ) ) {
pr_alert ( " %s: gp_cond_full without primitives. \n " , __func__ ) ;
}
2022-08-05 06:23:26 +08:00
if ( gp_cond_exp_full1 & & cur_ops - > get_gp_state_exp & & cur_ops - > cond_sync_exp_full ) {
synctype [ nsynctypes + + ] = RTWS_COND_GET_EXP_FULL ;
pr_info ( " %s: Testing conditional full-state expedited GPs. \n " , __func__ ) ;
} else if ( gp_cond_exp_full & &
( ! cur_ops - > get_gp_state_exp | | ! cur_ops - > cond_sync_exp_full ) ) {
pr_alert ( " %s: gp_cond_exp_full without primitives. \n " , __func__ ) ;
}
2017-12-09 04:23:10 +08:00
if ( gp_exp1 & & cur_ops - > exp_sync ) {
2014-03-19 06:57:41 +08:00
synctype [ nsynctypes + + ] = RTWS_EXP_SYNC ;
2017-12-09 04:23:10 +08:00
pr_info ( " %s: Testing expedited GPs. \n " , __func__ ) ;
} else if ( gp_exp & & ! cur_ops - > exp_sync ) {
2017-12-02 07:22:38 +08:00
pr_alert ( " %s: gp_exp without primitives. \n " , __func__ ) ;
2017-12-09 04:23:10 +08:00
}
if ( gp_normal1 & & cur_ops - > deferred_free ) {
2014-03-19 06:57:41 +08:00
synctype [ nsynctypes + + ] = RTWS_DEF_FREE ;
2017-12-09 04:23:10 +08:00
pr_info ( " %s: Testing asynchronous GPs. \n " , __func__ ) ;
} else if ( gp_normal & & ! cur_ops - > deferred_free ) {
2017-12-02 07:22:38 +08:00
pr_alert ( " %s: gp_normal without primitives. \n " , __func__ ) ;
2017-12-09 04:23:10 +08:00
}
2022-08-26 06:47:09 +08:00
if ( gp_poll1 & & cur_ops - > get_comp_state & & cur_ops - > same_gp_state & &
cur_ops - > start_gp_poll & & cur_ops - > poll_gp_state ) {
2020-11-14 12:43:59 +08:00
synctype [ nsynctypes + + ] = RTWS_POLL_GET ;
pr_info ( " %s: Testing polling GPs. \n " , __func__ ) ;
} else if ( gp_poll & & ( ! cur_ops - > start_gp_poll | | ! cur_ops - > poll_gp_state ) ) {
pr_alert ( " %s: gp_poll without primitives. \n " , __func__ ) ;
}
2022-08-26 04:37:59 +08:00
if ( gp_poll_full1 & & cur_ops - > get_comp_state_full & & cur_ops - > same_gp_state_full
& & cur_ops - > start_gp_poll_full & & cur_ops - > poll_gp_state_full ) {
2022-08-03 08:04:54 +08:00
synctype [ nsynctypes + + ] = RTWS_POLL_GET_FULL ;
pr_info ( " %s: Testing polling full-state GPs. \n " , __func__ ) ;
} else if ( gp_poll_full & & ( ! cur_ops - > start_gp_poll_full | | ! cur_ops - > poll_gp_state_full ) ) {
pr_alert ( " %s: gp_poll_full without primitives. \n " , __func__ ) ;
}
2022-02-01 23:01:20 +08:00
if ( gp_poll_exp1 & & cur_ops - > start_gp_poll_exp & & cur_ops - > poll_gp_state_exp ) {
synctype [ nsynctypes + + ] = RTWS_POLL_GET_EXP ;
pr_info ( " %s: Testing polling expedited GPs. \n " , __func__ ) ;
} else if ( gp_poll_exp & & ( ! cur_ops - > start_gp_poll_exp | | ! cur_ops - > poll_gp_state_exp ) ) {
pr_alert ( " %s: gp_poll_exp without primitives. \n " , __func__ ) ;
}
2022-08-04 03:38:51 +08:00
if ( gp_poll_exp_full1 & & cur_ops - > start_gp_poll_exp_full & & cur_ops - > poll_gp_state_full ) {
synctype [ nsynctypes + + ] = RTWS_POLL_GET_EXP_FULL ;
pr_info ( " %s: Testing polling full-state expedited GPs. \n " , __func__ ) ;
} else if ( gp_poll_exp_full & &
( ! cur_ops - > start_gp_poll_exp_full | | ! cur_ops - > poll_gp_state_full ) ) {
pr_alert ( " %s: gp_poll_exp_full without primitives. \n " , __func__ ) ;
}
2017-12-09 04:23:10 +08:00
if ( gp_sync1 & & cur_ops - > sync ) {
2014-03-22 07:17:56 +08:00
synctype [ nsynctypes + + ] = RTWS_SYNC ;
2017-12-09 04:23:10 +08:00
pr_info ( " %s: Testing normal GPs. \n " , __func__ ) ;
} else if ( gp_sync & & ! cur_ops - > sync ) {
2017-12-02 07:22:38 +08:00
pr_alert ( " %s: gp_sync without primitives. \n " , __func__ ) ;
2017-12-09 04:23:10 +08:00
}
2020-11-17 08:46:06 +08:00
}
2022-07-30 13:05:17 +08:00
/*
* Do the specified rcu_torture_writer ( ) synchronous grace period ,
* while also testing out the polled APIs . Note well that the single - CPU
* grace - period optimizations must be accounted for .
*/
static void do_rtws_sync ( struct torture_random_state * trsp , void ( * sync ) ( void ) )
{
unsigned long cookie ;
struct rcu_gp_oldstate cookie_full ;
bool dopoll ;
bool dopoll_full ;
unsigned long r = torture_random ( trsp ) ;
dopoll = cur_ops - > get_gp_state & & cur_ops - > poll_gp_state & & ! ( r & 0x300 ) ;
dopoll_full = cur_ops - > get_gp_state_full & & cur_ops - > poll_gp_state_full & & ! ( r & 0xc00 ) ;
if ( dopoll | | dopoll_full )
cpus_read_lock ( ) ;
if ( dopoll )
cookie = cur_ops - > get_gp_state ( ) ;
if ( dopoll_full )
cur_ops - > get_gp_state_full ( & cookie_full ) ;
2022-08-02 07:57:17 +08:00
if ( cur_ops - > poll_need_2gp & & cur_ops - > poll_need_2gp ( dopoll , dopoll_full ) )
2022-07-30 13:05:17 +08:00
sync ( ) ;
sync ( ) ;
WARN_ONCE ( dopoll & & ! cur_ops - > poll_gp_state ( cookie ) ,
" %s: Cookie check 3 failed %pS() online %*pbl. " ,
__func__ , sync , cpumask_pr_args ( cpu_online_mask ) ) ;
WARN_ONCE ( dopoll_full & & ! cur_ops - > poll_gp_state_full ( & cookie_full ) ,
" %s: Cookie check 4 failed %pS() online %*pbl " ,
__func__ , sync , cpumask_pr_args ( cpu_online_mask ) ) ;
if ( dopoll | | dopoll_full )
cpus_read_unlock ( ) ;
}
2020-11-17 08:46:06 +08:00
/*
* RCU torture writer kthread . Repeatedly substitutes a new structure
* for that pointed to by rcu_torture_current , freeing the old structure
* after a series of grace periods ( the " pipeline " ) .
*/
static int
rcu_torture_writer ( void * arg )
{
bool boot_ended ;
bool can_expedite = ! rcu_gp_is_expedited ( ) & & ! rcu_gp_is_normal ( ) ;
unsigned long cookie ;
2022-07-29 06:37:05 +08:00
struct rcu_gp_oldstate cookie_full ;
2020-11-17 08:46:06 +08:00
int expediting = 0 ;
unsigned long gp_snap ;
2022-08-26 06:47:09 +08:00
unsigned long gp_snap1 ;
2022-08-03 08:04:54 +08:00
struct rcu_gp_oldstate gp_snap_full ;
2022-08-26 04:37:59 +08:00
struct rcu_gp_oldstate gp_snap1_full ;
2020-11-17 08:46:06 +08:00
int i ;
int idx ;
int oldnice = task_nice ( current ) ;
2022-08-26 04:37:59 +08:00
struct rcu_gp_oldstate rgo [ NUM_ACTIVE_RCU_POLL_FULL_OLDSTATE ] ;
2020-11-17 08:46:06 +08:00
struct rcu_torture * rp ;
struct rcu_torture * old_rp ;
static DEFINE_TORTURE_RANDOM ( rand ) ;
bool stutter_waited ;
2022-08-26 06:47:09 +08:00
unsigned long ulo [ NUM_ACTIVE_RCU_POLL_OLDSTATE ] ;
2020-11-17 08:46:06 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_writer task started " ) ;
if ( ! can_expedite )
pr_alert ( " %s " TORTURE_FLAG
" GP expediting controlled from boot/sysfs for %s. \n " ,
torture_type , cur_ops - > name ) ;
2014-03-19 06:57:41 +08:00
if ( WARN_ONCE ( nsynctypes = = 0 ,
2022-03-08 06:46:57 +08:00
" %s: No update-side primitives. \n " , __func__ ) ) {
2014-03-22 07:17:56 +08:00
/*
* No updates primitives , so don ' t try updating .
* The resulting test won ' t be testing much , hence the
* above WARN_ONCE ( ) .
*/
2014-03-19 06:57:41 +08:00
rcu_torture_writer_state = RTWS_STOPPING ;
torture_kthread_stopping ( " rcu_torture_writer " ) ;
2022-03-08 06:46:57 +08:00
return 0 ;
2014-03-19 06:57:41 +08:00
}
2005-10-31 07:03:12 +08:00
do {
2014-02-20 02:51:42 +08:00
rcu_torture_writer_state = RTWS_FIXED_DELAY ;
2020-11-18 06:12:24 +08:00
torture_hrtimeout_us ( 500 , 1000 , & rand ) ;
2009-09-19 01:28:19 +08:00
rp = rcu_torture_alloc ( ) ;
if ( rp = = NULL )
2005-10-31 07:03:12 +08:00
continue ;
rp - > rtort_pipe_count = 0 ;
2014-02-20 02:51:42 +08:00
rcu_torture_writer_state = RTWS_DELAY ;
2014-01-28 03:49:39 +08:00
udelay ( torture_random ( & rand ) & 0x3ff ) ;
2014-02-20 02:51:42 +08:00
rcu_torture_writer_state = RTWS_REPLACE ;
2010-09-20 12:06:14 +08:00
old_rp = rcu_dereference_check ( rcu_torture_current ,
current = = writer_task ) ;
2005-11-18 17:10:50 +08:00
rp - > rtort_mbtest = 1 ;
2005-10-31 07:03:12 +08:00
rcu_assign_pointer ( rcu_torture_current , rp ) ;
2009-09-24 00:50:43 +08:00
smp_wmb ( ) ; /* Mods to old_rp must follow rcu_assign_pointer() */
2007-05-08 15:33:20 +08:00
if ( old_rp ) {
2005-10-31 07:03:12 +08:00
i = old_rp - > rtort_pipe_count ;
if ( i > RCU_TORTURE_PIPE_LEN )
i = RCU_TORTURE_PIPE_LEN ;
atomic_inc ( & rcu_torture_wcount [ i ] ) ;
2019-12-22 02:41:48 +08:00
WRITE_ONCE ( old_rp - > rtort_pipe_count ,
old_rp - > rtort_pipe_count + 1 ) ;
2022-08-02 08:33:24 +08:00
// Make sure readers block polled grace periods.
2020-11-14 12:43:59 +08:00
if ( cur_ops - > get_gp_state & & cur_ops - > poll_gp_state ) {
idx = cur_ops - > readlock ( ) ;
cookie = cur_ops - > get_gp_state ( ) ;
2022-08-03 01:22:12 +08:00
WARN_ONCE ( cur_ops - > poll_gp_state ( cookie ) ,
2020-11-14 12:43:59 +08:00
" %s: Cookie check 1 failed %s(%d) %lu->%lu \n " ,
__func__ ,
rcu_torture_writer_state_getname ( ) ,
rcu_torture_writer_state ,
cookie , cur_ops - > get_gp_state ( ) ) ;
2022-04-14 07:14:02 +08:00
if ( cur_ops - > get_gp_completed ) {
cookie = cur_ops - > get_gp_completed ( ) ;
WARN_ON_ONCE ( ! cur_ops - > poll_gp_state ( cookie ) ) ;
}
2020-11-14 12:43:59 +08:00
cur_ops - > readunlock ( idx ) ;
}
2022-08-02 08:33:24 +08:00
if ( cur_ops - > get_gp_state_full & & cur_ops - > poll_gp_state_full ) {
idx = cur_ops - > readlock ( ) ;
cur_ops - > get_gp_state_full ( & cookie_full ) ;
WARN_ONCE ( cur_ops - > poll_gp_state_full ( & cookie_full ) ,
" %s: Cookie check 5 failed %s(%d) online %*pbl \n " ,
__func__ ,
rcu_torture_writer_state_getname ( ) ,
rcu_torture_writer_state ,
cpumask_pr_args ( cpu_online_mask ) ) ;
if ( cur_ops - > get_gp_completed_full ) {
cur_ops - > get_gp_completed_full ( & cookie_full ) ;
WARN_ON_ONCE ( ! cur_ops - > poll_gp_state_full ( & cookie_full ) ) ;
}
cur_ops - > readunlock ( idx ) ;
2022-07-29 06:37:05 +08:00
}
2014-03-19 06:57:41 +08:00
switch ( synctype [ torture_random ( & rand ) % nsynctypes ] ) {
case RTWS_DEF_FREE :
2014-02-20 02:51:42 +08:00
rcu_torture_writer_state = RTWS_DEF_FREE ;
2013-06-13 06:12:21 +08:00
cur_ops - > deferred_free ( old_rp ) ;
2014-03-19 06:57:41 +08:00
break ;
case RTWS_EXP_SYNC :
2014-02-20 02:51:42 +08:00
rcu_torture_writer_state = RTWS_EXP_SYNC ;
2022-07-30 13:05:17 +08:00
do_rtws_sync ( & rand , cur_ops - > exp_sync ) ;
2014-03-19 06:57:41 +08:00
rcu_torture_pipe_update ( old_rp ) ;
break ;
case RTWS_COND_GET :
rcu_torture_writer_state = RTWS_COND_GET ;
2020-11-14 12:14:27 +08:00
gp_snap = cur_ops - > get_gp_state ( ) ;
2020-11-18 03:32:54 +08:00
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 , & rand ) ;
2014-03-19 06:57:41 +08:00
rcu_torture_writer_state = RTWS_COND_SYNC ;
cur_ops - > cond_sync ( gp_snap ) ;
rcu_torture_pipe_update ( old_rp ) ;
break ;
2022-02-01 23:01:20 +08:00
case RTWS_COND_GET_EXP :
rcu_torture_writer_state = RTWS_COND_GET_EXP ;
gp_snap = cur_ops - > get_gp_state_exp ( ) ;
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 , & rand ) ;
rcu_torture_writer_state = RTWS_COND_SYNC_EXP ;
cur_ops - > cond_sync_exp ( gp_snap ) ;
rcu_torture_pipe_update ( old_rp ) ;
break ;
2022-08-05 04:46:05 +08:00
case RTWS_COND_GET_FULL :
rcu_torture_writer_state = RTWS_COND_GET_FULL ;
cur_ops - > get_gp_state_full ( & gp_snap_full ) ;
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 , & rand ) ;
rcu_torture_writer_state = RTWS_COND_SYNC_FULL ;
cur_ops - > cond_sync_full ( & gp_snap_full ) ;
rcu_torture_pipe_update ( old_rp ) ;
break ;
2022-08-05 06:23:26 +08:00
case RTWS_COND_GET_EXP_FULL :
rcu_torture_writer_state = RTWS_COND_GET_EXP_FULL ;
cur_ops - > get_gp_state_full ( & gp_snap_full ) ;
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 , & rand ) ;
rcu_torture_writer_state = RTWS_COND_SYNC_EXP_FULL ;
cur_ops - > cond_sync_exp_full ( & gp_snap_full ) ;
rcu_torture_pipe_update ( old_rp ) ;
break ;
2020-11-14 12:43:59 +08:00
case RTWS_POLL_GET :
rcu_torture_writer_state = RTWS_POLL_GET ;
2022-08-26 06:47:09 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( ulo ) ; i + + )
ulo [ i ] = cur_ops - > get_comp_state ( ) ;
2020-11-14 12:43:59 +08:00
gp_snap = cur_ops - > start_gp_poll ( ) ;
rcu_torture_writer_state = RTWS_POLL_WAIT ;
2022-08-26 06:47:09 +08:00
while ( ! cur_ops - > poll_gp_state ( gp_snap ) ) {
gp_snap1 = cur_ops - > get_gp_state ( ) ;
for ( i = 0 ; i < ARRAY_SIZE ( ulo ) ; i + + )
if ( cur_ops - > poll_gp_state ( ulo [ i ] ) | |
cur_ops - > same_gp_state ( ulo [ i ] , gp_snap1 ) ) {
ulo [ i ] = gp_snap1 ;
break ;
}
WARN_ON_ONCE ( i > = ARRAY_SIZE ( ulo ) ) ;
2020-11-18 03:32:54 +08:00
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 ,
& rand ) ;
2022-08-26 06:47:09 +08:00
}
2020-11-14 12:43:59 +08:00
rcu_torture_pipe_update ( old_rp ) ;
break ;
2022-08-03 08:04:54 +08:00
case RTWS_POLL_GET_FULL :
rcu_torture_writer_state = RTWS_POLL_GET_FULL ;
2022-08-26 04:37:59 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( rgo ) ; i + + )
cur_ops - > get_comp_state_full ( & rgo [ i ] ) ;
2022-08-03 08:04:54 +08:00
cur_ops - > start_gp_poll_full ( & gp_snap_full ) ;
rcu_torture_writer_state = RTWS_POLL_WAIT_FULL ;
2022-08-26 04:37:59 +08:00
while ( ! cur_ops - > poll_gp_state_full ( & gp_snap_full ) ) {
cur_ops - > get_gp_state_full ( & gp_snap1_full ) ;
for ( i = 0 ; i < ARRAY_SIZE ( rgo ) ; i + + )
if ( cur_ops - > poll_gp_state_full ( & rgo [ i ] ) | |
cur_ops - > same_gp_state_full ( & rgo [ i ] ,
& gp_snap1_full ) ) {
rgo [ i ] = gp_snap1_full ;
break ;
}
WARN_ON_ONCE ( i > = ARRAY_SIZE ( rgo ) ) ;
2022-08-03 08:04:54 +08:00
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 ,
& rand ) ;
2022-08-26 04:37:59 +08:00
}
2022-08-03 08:04:54 +08:00
rcu_torture_pipe_update ( old_rp ) ;
break ;
2022-02-01 23:01:20 +08:00
case RTWS_POLL_GET_EXP :
rcu_torture_writer_state = RTWS_POLL_GET_EXP ;
gp_snap = cur_ops - > start_gp_poll_exp ( ) ;
rcu_torture_writer_state = RTWS_POLL_WAIT_EXP ;
while ( ! cur_ops - > poll_gp_state_exp ( gp_snap ) )
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 ,
& rand ) ;
rcu_torture_pipe_update ( old_rp ) ;
break ;
2022-08-04 03:38:51 +08:00
case RTWS_POLL_GET_EXP_FULL :
rcu_torture_writer_state = RTWS_POLL_GET_EXP_FULL ;
cur_ops - > start_gp_poll_exp_full ( & gp_snap_full ) ;
rcu_torture_writer_state = RTWS_POLL_WAIT_EXP_FULL ;
while ( ! cur_ops - > poll_gp_state_full ( & gp_snap_full ) )
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 ,
& rand ) ;
rcu_torture_pipe_update ( old_rp ) ;
break ;
2014-03-22 07:17:56 +08:00
case RTWS_SYNC :
rcu_torture_writer_state = RTWS_SYNC ;
2022-07-30 13:05:17 +08:00
do_rtws_sync ( & rand , cur_ops - > sync ) ;
2014-03-22 07:17:56 +08:00
rcu_torture_pipe_update ( old_rp ) ;
break ;
2014-03-19 06:57:41 +08:00
default :
WARN_ON_ONCE ( 1 ) ;
break ;
2013-06-13 06:12:21 +08:00
}
2005-10-31 07:03:12 +08:00
}
2018-07-19 05:32:31 +08:00
WRITE_ONCE ( rcu_torture_current_version ,
rcu_torture_current_version + 1 ) ;
2015-02-19 08:31:29 +08:00
/* Cycle through nesting levels of rcu_expedite_gp() calls. */
if ( can_expedite & &
! ( torture_random ( & rand ) & 0xff & ( ! ! expediting - 1 ) ) ) {
WARN_ON_ONCE ( expediting = = 0 & & rcu_gp_is_expedited ( ) ) ;
if ( expediting > = 0 )
rcu_expedite_gp ( ) ;
else
rcu_unexpedite_gp ( ) ;
if ( + + expediting > 3 )
expediting = - expediting ;
2017-12-09 03:37:24 +08:00
} else if ( ! can_expedite ) { /* Disabled during boot, recheck. */
can_expedite = ! rcu_gp_is_expedited ( ) & &
! rcu_gp_is_normal ( ) ;
2015-02-19 08:31:29 +08:00
}
2014-02-20 02:51:42 +08:00
rcu_torture_writer_state = RTWS_STUTTER ;
2020-11-17 08:01:50 +08:00
boot_ended = rcu_inkernel_boot_has_ended ( ) ;
2020-09-23 07:42:42 +08:00
stutter_waited = stutter_wait ( " rcu_torture_writer " ) ;
if ( stutter_waited & &
2021-12-18 04:33:53 +08:00
! atomic_read ( & rcu_fwd_cb_nodelay ) & &
2019-04-16 05:50:05 +08:00
! cur_ops - > slow_gps & &
2019-11-29 10:54:06 +08:00
! torture_must_stop ( ) & &
2020-11-17 08:01:50 +08:00
boot_ended )
2018-08-08 05:34:44 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( rcu_tortures ) ; i + + )
2019-04-10 02:06:32 +08:00
if ( list_empty ( & rcu_tortures [ i ] . rtort_free ) & &
rcu_access_pointer ( rcu_torture_current ) ! =
2019-05-17 07:15:16 +08:00
& rcu_tortures [ i ] ) {
2022-04-11 23:19:03 +08:00
tracing_off ( ) ;
2023-05-16 00:18:20 +08:00
show_rcu_gp_kthreads ( ) ;
2019-04-10 02:06:32 +08:00
WARN ( 1 , " %s: rtort_pipe_count: %d \n " , __func__ , rcu_tortures [ i ] . rtort_pipe_count ) ;
2022-04-11 23:19:03 +08:00
rcu_ftrace_dump ( DUMP_ALL ) ;
2019-05-17 07:15:16 +08:00
}
2020-09-23 07:42:42 +08:00
if ( stutter_waited )
sched_set_normal ( current , oldnice ) ;
2014-01-31 07:49:29 +08:00
} while ( ! torture_must_stop ( ) ) ;
2020-04-27 10:20:37 +08:00
rcu_torture_current = NULL ; // Let stats task know that we are done.
2015-02-19 08:31:29 +08:00
/* Reset expediting back to unexpedited. */
if ( expediting > 0 )
expediting = - expediting ;
while ( can_expedite & & expediting + + < 0 )
rcu_unexpedite_gp ( ) ;
WARN_ON_ONCE ( can_expedite & & rcu_gp_is_expedited ( ) ) ;
2017-12-09 03:37:24 +08:00
if ( ! can_expedite )
pr_alert ( " %s " TORTURE_FLAG
" Dynamic grace-period expediting was disabled. \n " ,
torture_type ) ;
2014-02-20 02:51:42 +08:00
rcu_torture_writer_state = RTWS_STOPPING ;
2014-02-01 09:37:28 +08:00
torture_kthread_stopping ( " rcu_torture_writer " ) ;
2005-10-31 07:03:12 +08:00
return 0 ;
}
2006-10-04 17:17:13 +08:00
/*
* RCU torture fake writer kthread . Repeatedly calls sync , with a random
* delay between calls .
*/
static int
rcu_torture_fakewriter ( void * arg )
{
2020-11-17 09:10:39 +08:00
unsigned long gp_snap ;
2022-08-03 08:04:54 +08:00
struct rcu_gp_oldstate gp_snap_full ;
2014-01-28 03:49:39 +08:00
DEFINE_TORTURE_RANDOM ( rand ) ;
2006-10-04 17:17:13 +08:00
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_fakewriter task started " ) ;
2014-02-11 15:34:49 +08:00
set_user_nice ( current , MAX_NICE ) ;
2006-10-04 17:17:13 +08:00
2022-03-08 06:46:55 +08:00
if ( WARN_ONCE ( nsynctypes = = 0 ,
" %s: No update-side primitives. \n " , __func__ ) ) {
/*
* No updates primitives , so don ' t try updating .
* The resulting test won ' t be testing much , hence the
* above WARN_ONCE ( ) .
*/
torture_kthread_stopping ( " rcu_torture_fakewriter " ) ;
return 0 ;
}
2006-10-04 17:17:13 +08:00
do {
2020-11-18 06:12:24 +08:00
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 10 , & rand ) ;
2012-05-30 08:50:51 +08:00
if ( cur_ops - > cb_barrier ! = NULL & &
2014-01-28 03:49:39 +08:00
torture_random ( & rand ) % ( nfakewriters * 8 ) = = 0 ) {
2012-05-30 08:50:51 +08:00
cur_ops - > cb_barrier ( ) ;
2020-11-17 09:10:39 +08:00
} else {
switch ( synctype [ torture_random ( & rand ) % nsynctypes ] ) {
case RTWS_DEF_FREE :
break ;
case RTWS_EXP_SYNC :
2013-06-13 06:12:21 +08:00
cur_ops - > exp_sync ( ) ;
2020-11-17 09:10:39 +08:00
break ;
case RTWS_COND_GET :
gp_snap = cur_ops - > get_gp_state ( ) ;
2020-11-18 03:32:54 +08:00
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 , & rand ) ;
2020-11-17 09:10:39 +08:00
cur_ops - > cond_sync ( gp_snap ) ;
break ;
2022-02-01 23:01:20 +08:00
case RTWS_COND_GET_EXP :
gp_snap = cur_ops - > get_gp_state_exp ( ) ;
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 , & rand ) ;
cur_ops - > cond_sync_exp ( gp_snap ) ;
break ;
2022-08-05 04:46:05 +08:00
case RTWS_COND_GET_FULL :
cur_ops - > get_gp_state_full ( & gp_snap_full ) ;
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 , & rand ) ;
cur_ops - > cond_sync_full ( & gp_snap_full ) ;
break ;
2022-08-05 06:23:26 +08:00
case RTWS_COND_GET_EXP_FULL :
cur_ops - > get_gp_state_full ( & gp_snap_full ) ;
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 , & rand ) ;
cur_ops - > cond_sync_exp_full ( & gp_snap_full ) ;
break ;
2020-11-17 09:10:39 +08:00
case RTWS_POLL_GET :
gp_snap = cur_ops - > start_gp_poll ( ) ;
while ( ! cur_ops - > poll_gp_state ( gp_snap ) ) {
2020-11-18 03:32:54 +08:00
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 ,
& rand ) ;
2020-11-17 09:10:39 +08:00
}
break ;
2022-08-03 08:04:54 +08:00
case RTWS_POLL_GET_FULL :
cur_ops - > start_gp_poll_full ( & gp_snap_full ) ;
while ( ! cur_ops - > poll_gp_state_full ( & gp_snap_full ) ) {
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 ,
& rand ) ;
}
break ;
2022-02-01 23:01:20 +08:00
case RTWS_POLL_GET_EXP :
gp_snap = cur_ops - > start_gp_poll_exp ( ) ;
while ( ! cur_ops - > poll_gp_state_exp ( gp_snap ) ) {
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 ,
& rand ) ;
}
break ;
2022-08-04 03:38:51 +08:00
case RTWS_POLL_GET_EXP_FULL :
cur_ops - > start_gp_poll_exp_full ( & gp_snap_full ) ;
while ( ! cur_ops - > poll_gp_state_full ( & gp_snap_full ) ) {
torture_hrtimeout_jiffies ( torture_random ( & rand ) % 16 ,
& rand ) ;
}
break ;
2020-11-17 09:10:39 +08:00
case RTWS_SYNC :
cur_ops - > sync ( ) ;
break ;
default :
WARN_ON_ONCE ( 1 ) ;
break ;
}
2013-06-13 06:12:21 +08:00
}
2014-02-01 03:57:43 +08:00
stutter_wait ( " rcu_torture_fakewriter " ) ;
2014-01-31 07:49:29 +08:00
} while ( ! torture_must_stop ( ) ) ;
2006-10-04 17:17:13 +08:00
2014-02-01 09:37:28 +08:00
torture_kthread_stopping ( " rcu_torture_fakewriter " ) ;
2006-10-04 17:17:13 +08:00
return 0 ;
}
2017-07-21 06:27:32 +08:00
static void rcu_torture_timer_cb ( struct rcu_head * rhp )
{
kfree ( rhp ) ;
}
2020-10-30 06:08:57 +08:00
// Set up and carry out testing of RCU's global memory ordering
static void rcu_torture_reader_do_mbchk ( long myid , struct rcu_torture * rtp ,
struct torture_random_state * trsp )
{
unsigned long loops ;
2020-12-19 23:34:35 +08:00
int noc = torture_num_online_cpus ( ) ;
2020-10-30 06:08:57 +08:00
int rdrchked ;
int rdrchker ;
struct rcu_torture_reader_check * rtrcp ; // Me.
struct rcu_torture_reader_check * rtrcp_assigner ; // Assigned us to do checking.
struct rcu_torture_reader_check * rtrcp_chked ; // Reader being checked.
struct rcu_torture_reader_check * rtrcp_chker ; // Reader doing checking when not me.
if ( myid < 0 )
return ; // Don't try this from timer handlers.
// Increment my counter.
rtrcp = & rcu_torture_reader_mbchk [ myid ] ;
WRITE_ONCE ( rtrcp - > rtc_myloops , rtrcp - > rtc_myloops + 1 ) ;
// Attempt to assign someone else some checking work.
rdrchked = torture_random ( trsp ) % nrealreaders ;
rtrcp_chked = & rcu_torture_reader_mbchk [ rdrchked ] ;
rdrchker = torture_random ( trsp ) % nrealreaders ;
rtrcp_chker = & rcu_torture_reader_mbchk [ rdrchker ] ;
if ( rdrchked ! = myid & & rdrchked ! = rdrchker & & noc > = rdrchked & & noc > = rdrchker & &
smp_load_acquire ( & rtrcp - > rtc_chkrdr ) < 0 & & // Pairs with smp_store_release below.
! READ_ONCE ( rtp - > rtort_chkp ) & &
! smp_load_acquire ( & rtrcp_chker - > rtc_assigner ) ) { // Pairs with smp_store_release below.
rtrcp - > rtc_chkloops = READ_ONCE ( rtrcp_chked - > rtc_myloops ) ;
WARN_ON_ONCE ( rtrcp - > rtc_chkrdr > = 0 ) ;
rtrcp - > rtc_chkrdr = rdrchked ;
WARN_ON_ONCE ( rtrcp - > rtc_ready ) ; // This gets set after the grace period ends.
if ( cmpxchg_relaxed ( & rtrcp_chker - > rtc_assigner , NULL , rtrcp ) | |
cmpxchg_relaxed ( & rtp - > rtort_chkp , NULL , rtrcp ) )
( void ) cmpxchg_relaxed ( & rtrcp_chker - > rtc_assigner , rtrcp , NULL ) ; // Back out.
}
// If assigned some completed work, do it!
rtrcp_assigner = READ_ONCE ( rtrcp - > rtc_assigner ) ;
if ( ! rtrcp_assigner | | ! smp_load_acquire ( & rtrcp_assigner - > rtc_ready ) )
return ; // No work or work not yet ready.
rdrchked = rtrcp_assigner - > rtc_chkrdr ;
if ( WARN_ON_ONCE ( rdrchked < 0 ) )
return ;
rtrcp_chked = & rcu_torture_reader_mbchk [ rdrchked ] ;
loops = READ_ONCE ( rtrcp_chked - > rtc_myloops ) ;
atomic_inc ( & n_rcu_torture_mbchk_tries ) ;
if ( ULONG_CMP_LT ( loops , rtrcp_assigner - > rtc_chkloops ) )
atomic_inc ( & n_rcu_torture_mbchk_fail ) ;
rtrcp_assigner - > rtc_chkloops = loops + ULONG_MAX / 2 ;
rtrcp_assigner - > rtc_ready = 0 ;
smp_store_release ( & rtrcp - > rtc_assigner , NULL ) ; // Someone else can assign us work.
smp_store_release ( & rtrcp_assigner - > rtc_chkrdr , - 1 ) ; // Assigner can again assign.
}
2008-06-26 03:24:52 +08:00
/*
2018-05-25 22:29:25 +08:00
* Do one extension of an RCU read - side critical section using the
* current reader state in readstate ( set to zero for initial entry
* to extended critical section ) , set the new state as specified by
* newstate ( set to zero for final exit from extended critical section ) ,
* and random - number - generator state in trsp . If this is neither the
* beginning or end of the critical section and if there was actually a
* change , do a - > read_delay ( ) .
2008-06-26 03:24:52 +08:00
*/
2018-05-25 22:29:25 +08:00
static void rcutorture_one_extend ( int * readstate , int newstate ,
2018-07-14 03:09:14 +08:00
struct torture_random_state * trsp ,
struct rt_read_seg * rtrsp )
2018-05-25 22:29:25 +08:00
{
2020-03-29 09:53:25 +08:00
unsigned long flags ;
2021-09-23 11:49:12 +08:00
int idxnew1 = - 1 ;
int idxnew2 = - 1 ;
int idxold1 = * readstate ;
int idxold2 = idxold1 ;
2018-05-25 22:29:25 +08:00
int statesnew = ~ * readstate & newstate ;
int statesold = * readstate & ~ newstate ;
2021-09-23 11:49:12 +08:00
WARN_ON_ONCE ( idxold2 < 0 ) ;
WARN_ON_ONCE ( ( idxold2 > > RCUTORTURE_RDR_SHIFT_2 ) > 1 ) ;
2018-07-14 03:09:14 +08:00
rtrsp - > rt_readstate = newstate ;
2018-05-25 22:29:25 +08:00
/* First, put new protection in place to avoid critical-section gap. */
if ( statesnew & RCUTORTURE_RDR_BH )
local_bh_disable ( ) ;
2021-08-20 15:42:36 +08:00
if ( statesnew & RCUTORTURE_RDR_RBH )
rcu_read_lock_bh ( ) ;
2018-05-25 22:29:25 +08:00
if ( statesnew & RCUTORTURE_RDR_IRQ )
local_irq_disable ( ) ;
if ( statesnew & RCUTORTURE_RDR_PREEMPT )
preempt_disable ( ) ;
2018-07-07 06:16:12 +08:00
if ( statesnew & RCUTORTURE_RDR_SCHED )
rcu_read_lock_sched ( ) ;
2021-09-23 11:49:12 +08:00
if ( statesnew & RCUTORTURE_RDR_RCU_1 )
idxnew1 = ( cur_ops - > readlock ( ) & 0x1 ) < < RCUTORTURE_RDR_SHIFT_1 ;
if ( statesnew & RCUTORTURE_RDR_RCU_2 )
idxnew2 = ( cur_ops - > readlock ( ) & 0x1 ) < < RCUTORTURE_RDR_SHIFT_2 ;
2018-05-25 22:29:25 +08:00
2021-08-20 15:42:36 +08:00
/*
* Next , remove old protection , in decreasing order of strength
* to avoid unlock paths that aren ' t safe in the stronger
* context . Namely : BH can not be enabled with disabled interrupts .
* Additionally PREEMPT_RT requires that BH is enabled in preemptible
* context .
*/
2018-05-25 22:29:25 +08:00
if ( statesold & RCUTORTURE_RDR_IRQ )
local_irq_enable ( ) ;
if ( statesold & RCUTORTURE_RDR_PREEMPT )
preempt_enable ( ) ;
2018-07-07 06:16:12 +08:00
if ( statesold & RCUTORTURE_RDR_SCHED )
rcu_read_unlock_sched ( ) ;
2021-08-20 15:42:36 +08:00
if ( statesold & RCUTORTURE_RDR_BH )
local_bh_enable ( ) ;
if ( statesold & RCUTORTURE_RDR_RBH )
rcu_read_unlock_bh ( ) ;
2021-09-23 11:49:12 +08:00
if ( statesold & RCUTORTURE_RDR_RCU_2 ) {
cur_ops - > readunlock ( ( idxold2 > > RCUTORTURE_RDR_SHIFT_2 ) & 0x1 ) ;
WARN_ON_ONCE ( idxnew2 ! = - 1 ) ;
idxold2 = 0 ;
}
if ( statesold & RCUTORTURE_RDR_RCU_1 ) {
2021-09-25 12:30:26 +08:00
bool lockit ;
2020-03-29 09:53:25 +08:00
2021-09-25 12:30:26 +08:00
lockit = ! cur_ops - > no_pi_lock & & ! statesnew & & ! ( torture_random ( trsp ) & 0xffff ) ;
2020-03-29 09:53:25 +08:00
if ( lockit )
raw_spin_lock_irqsave ( & current - > pi_lock , flags ) ;
2021-09-23 11:49:12 +08:00
cur_ops - > readunlock ( ( idxold1 > > RCUTORTURE_RDR_SHIFT_1 ) & 0x1 ) ;
WARN_ON_ONCE ( idxnew1 ! = - 1 ) ;
idxold1 = 0 ;
2020-03-29 09:53:25 +08:00
if ( lockit )
raw_spin_unlock_irqrestore ( & current - > pi_lock , flags ) ;
}
2018-05-25 22:29:25 +08:00
/* Delay if neither beginning nor end and there was a change. */
if ( ( statesnew | | statesold ) & & * readstate & & newstate )
2018-07-14 03:09:14 +08:00
cur_ops - > read_delay ( trsp , rtrsp ) ;
2018-05-25 22:29:25 +08:00
/* Update the reader state. */
2021-09-23 11:49:12 +08:00
if ( idxnew1 = = - 1 )
idxnew1 = idxold1 & RCUTORTURE_RDR_MASK_1 ;
WARN_ON_ONCE ( idxnew1 < 0 ) ;
if ( WARN_ON_ONCE ( ( idxnew1 > > RCUTORTURE_RDR_SHIFT_1 ) > 1 ) )
pr_info ( " Unexpected idxnew1 value of %#x \n " , idxnew1 ) ;
if ( idxnew2 = = - 1 )
idxnew2 = idxold2 & RCUTORTURE_RDR_MASK_2 ;
WARN_ON_ONCE ( idxnew2 < 0 ) ;
WARN_ON_ONCE ( ( idxnew2 > > RCUTORTURE_RDR_SHIFT_2 ) > 1 ) ;
* readstate = idxnew1 | idxnew2 | newstate ;
WARN_ON_ONCE ( * readstate < 0 ) ;
if ( WARN_ON_ONCE ( ( * readstate > > RCUTORTURE_RDR_SHIFT_2 ) > 1 ) )
pr_info ( " Unexpected idxnew2 value of %#x \n " , idxnew2 ) ;
2018-05-25 22:29:25 +08:00
}
/* Return the biggest extendables mask given current RCU and boot parameters. */
static int rcutorture_extend_mask_max ( void )
{
int mask ;
WARN_ON_ONCE ( extendables & ~ RCUTORTURE_MAX_EXTEND ) ;
mask = extendables & RCUTORTURE_MAX_EXTEND & cur_ops - > extendables ;
2021-09-23 11:49:12 +08:00
mask = mask | RCUTORTURE_RDR_RCU_1 | RCUTORTURE_RDR_RCU_2 ;
2018-05-25 22:29:25 +08:00
return mask ;
}
/* Return a random protection state mask, but with at least one bit set. */
static int
rcutorture_extend_mask ( int oldmask , struct torture_random_state * trsp )
{
int mask = rcutorture_extend_mask_max ( ) ;
2023-07-13 07:16:37 +08:00
unsigned long randmask1 = torture_random ( trsp ) ;
2018-07-14 03:09:14 +08:00
unsigned long randmask2 = randmask1 > > 3 ;
2021-08-20 15:42:36 +08:00
unsigned long preempts = RCUTORTURE_RDR_PREEMPT | RCUTORTURE_RDR_SCHED ;
unsigned long preempts_irq = preempts | RCUTORTURE_RDR_IRQ ;
unsigned long bhs = RCUTORTURE_RDR_BH | RCUTORTURE_RDR_RBH ;
2018-05-25 22:29:25 +08:00
2021-09-23 11:49:12 +08:00
WARN_ON_ONCE ( mask > > RCUTORTURE_RDR_SHIFT_1 ) ;
2019-03-01 07:06:13 +08:00
/* Mostly only one bit (need preemption!), sometimes lots of bits. */
2018-07-14 03:09:14 +08:00
if ( ! ( randmask1 & 0x7 ) )
2018-06-10 23:50:09 +08:00
mask = mask & randmask2 ;
else
mask = mask & ( 1 < < ( randmask2 % RCUTORTURE_RDR_NBITS ) ) ;
2021-08-20 15:42:36 +08:00
2021-09-23 11:49:12 +08:00
// Can't have nested RCU reader without outer RCU reader.
if ( ! ( mask & RCUTORTURE_RDR_RCU_1 ) & & ( mask & RCUTORTURE_RDR_RCU_2 ) ) {
if ( oldmask & RCUTORTURE_RDR_RCU_1 )
mask & = ~ RCUTORTURE_RDR_RCU_2 ;
else
mask | = RCUTORTURE_RDR_RCU_1 ;
}
2021-08-20 15:42:36 +08:00
/*
* Can ' t enable bh w / irq disabled .
*/
if ( mask & RCUTORTURE_RDR_IRQ )
mask | = oldmask & bhs ;
/*
* Ideally these sequences would be detected in debug builds
* ( regardless of RT ) , but until then don ' t stop testing
* them on non - RT .
*/
if ( IS_ENABLED ( CONFIG_PREEMPT_RT ) ) {
/* Can't modify BH in atomic context */
if ( oldmask & preempts_irq )
mask & = ~ bhs ;
if ( ( oldmask | mask ) & preempts_irq )
mask | = oldmask & bhs ;
}
2021-09-23 11:49:12 +08:00
return mask ? : RCUTORTURE_RDR_RCU_1 ;
2018-05-25 22:29:25 +08:00
}
/*
* Do a randomly selected number of extensions of an existing RCU read - side
* critical section .
*/
2018-07-14 03:09:14 +08:00
static struct rt_read_seg *
rcutorture_loop_extend ( int * readstate , struct torture_random_state * trsp ,
struct rt_read_seg * rtrsp )
2018-05-25 22:29:25 +08:00
{
int i ;
2018-07-14 03:09:14 +08:00
int j ;
2018-05-25 22:29:25 +08:00
int mask = rcutorture_extend_mask_max ( ) ;
WARN_ON_ONCE ( ! * readstate ) ; /* -Existing- RCU read-side critsect! */
if ( ! ( ( mask - 1 ) & mask ) )
2018-07-14 03:09:14 +08:00
return rtrsp ; /* Current RCU reader not extendable. */
/* Bias towards larger numbers of loops. */
2023-07-13 07:16:37 +08:00
i = torture_random ( trsp ) ;
2018-07-14 03:09:14 +08:00
i = ( ( i | ( i > > 3 ) ) & RCUTORTURE_RDR_MAX_LOOPS ) + 1 ;
for ( j = 0 ; j < i ; j + + ) {
2018-05-25 22:29:25 +08:00
mask = rcutorture_extend_mask ( * readstate , trsp ) ;
2018-07-14 03:09:14 +08:00
rcutorture_one_extend ( readstate , mask , trsp , & rtrsp [ j ] ) ;
2018-05-25 22:29:25 +08:00
}
2018-07-14 03:09:14 +08:00
return & rtrsp [ j ] ;
2018-05-25 22:29:25 +08:00
}
2018-05-23 01:56:05 +08:00
/*
* Do one read - side critical section , returning false if there was
* no data to read . Can be invoked both from process context and
* from a timer handler .
*/
2020-10-30 06:08:57 +08:00
static bool rcu_torture_one_read ( struct torture_random_state * trsp , long myid )
2008-06-26 03:24:52 +08:00
{
2022-08-25 09:57:45 +08:00
bool checkpolling = ! ( torture_random ( trsp ) & 0xfff ) ;
2020-11-16 04:45:57 +08:00
unsigned long cookie ;
2022-08-04 07:40:48 +08:00
struct rcu_gp_oldstate cookie_full ;
2018-07-14 03:09:14 +08:00
int i ;
2014-11-22 09:10:16 +08:00
unsigned long started ;
2014-11-22 06:19:26 +08:00
unsigned long completed ;
2018-05-25 22:29:25 +08:00
int newstate ;
2008-06-26 03:24:52 +08:00
struct rcu_torture * p ;
int pipe_count ;
2018-05-25 22:29:25 +08:00
int readstate = 0 ;
2018-07-14 03:09:14 +08:00
struct rt_read_seg rtseg [ RCUTORTURE_RDR_MAX_SEGS ] = { { 0 } } ;
struct rt_read_seg * rtrsp = & rtseg [ 0 ] ;
struct rt_read_seg * rtrsp1 ;
2012-11-15 08:26:40 +08:00
unsigned long long ts ;
2008-06-26 03:24:52 +08:00
2020-06-12 07:43:14 +08:00
WARN_ON_ONCE ( ! rcu_is_watching ( ) ) ;
2018-05-25 22:29:25 +08:00
newstate = rcutorture_extend_mask ( readstate , trsp ) ;
2018-07-14 03:09:14 +08:00
rcutorture_one_extend ( & readstate , newstate , trsp , rtrsp + + ) ;
2022-08-25 09:57:45 +08:00
if ( checkpolling ) {
if ( cur_ops - > get_gp_state & & cur_ops - > poll_gp_state )
cookie = cur_ops - > get_gp_state ( ) ;
if ( cur_ops - > get_gp_state_full & & cur_ops - > poll_gp_state_full )
cur_ops - > get_gp_state_full ( & cookie_full ) ;
}
2018-04-28 02:39:34 +08:00
started = cur_ops - > get_gp_seq ( ) ;
2013-02-05 02:36:13 +08:00
ts = rcu_trace_clock_local ( ) ;
rcu: Introduce lockdep-based checking to RCU read-side primitives
Inspection is proving insufficient to catch all RCU misuses,
which is understandable given that rcu_dereference() might be
protected by any of four different flavors of RCU (RCU, RCU-bh,
RCU-sched, and SRCU), and might also/instead be protected by any
of a number of locking primitives. It is therefore time to
enlist the aid of lockdep.
This set of patches is inspired by earlier work by Peter
Zijlstra and Thomas Gleixner, and takes the following approach:
o Set up separate lockdep classes for RCU, RCU-bh, and RCU-sched.
o Set up separate lockdep classes for each instance of SRCU.
o Create primitives that check for being in an RCU read-side
critical section. These return exact answers if lockdep is
fully enabled, but if unsure, report being in an RCU read-side
critical section. (We want to avoid false positives!)
The primitives are:
For RCU: rcu_read_lock_held(void)
For RCU-bh: rcu_read_lock_bh_held(void)
For RCU-sched: rcu_read_lock_sched_held(void)
For SRCU: srcu_read_lock_held(struct srcu_struct *sp)
o Add rcu_dereference_check(), which takes a second argument
in which one places a boolean expression based on the above
primitives and/or lockdep_is_held().
o A new kernel configuration parameter, CONFIG_PROVE_RCU, enables
rcu_dereference_check(). This depends on CONFIG_PROVE_LOCKING,
and should be quite helpful during the transition period while
CONFIG_PROVE_RCU-unaware patches are in flight.
The existing rcu_dereference() primitive does no checking, but
upcoming patches will change that.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: laijs@cn.fujitsu.com
Cc: dipankar@in.ibm.com
Cc: mathieu.desnoyers@polymtl.ca
Cc: josh@joshtriplett.org
Cc: dvhltc@us.ibm.com
Cc: niv@us.ibm.com
Cc: peterz@infradead.org
Cc: rostedt@goodmis.org
Cc: Valdis.Kletnieks@vt.edu
Cc: dhowells@redhat.com
LKML-Reference: <1266887105-1528-1-git-send-email-paulmck@linux.vnet.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-23 09:04:45 +08:00
p = rcu_dereference_check ( rcu_torture_current ,
2021-03-14 12:05:31 +08:00
! cur_ops - > readlock_held | | cur_ops - > readlock_held ( ) ) ;
2008-06-26 03:24:52 +08:00
if ( p = = NULL ) {
2018-05-23 01:56:05 +08:00
/* Wait for rcu_torture_writer to get underway */
2018-07-14 03:09:14 +08:00
rcutorture_one_extend ( & readstate , 0 , trsp , rtrsp ) ;
2018-05-23 01:56:05 +08:00
return false ;
2008-06-26 03:24:52 +08:00
}
if ( p - > rtort_mbtest = = 0 )
atomic_inc ( & n_rcu_torture_mberror ) ;
2020-10-30 06:08:57 +08:00
rcu_torture_reader_do_mbchk ( myid , p , trsp ) ;
2018-07-14 03:09:14 +08:00
rtrsp = rcutorture_loop_extend ( & readstate , trsp , rtrsp ) ;
2008-06-26 03:24:52 +08:00
preempt_disable ( ) ;
2019-12-22 02:41:48 +08:00
pipe_count = READ_ONCE ( p - > rtort_pipe_count ) ;
2008-06-26 03:24:52 +08:00
if ( pipe_count > RCU_TORTURE_PIPE_LEN ) {
/* Should not happen, but... */
pipe_count = RCU_TORTURE_PIPE_LEN ;
}
2018-04-28 02:39:34 +08:00
completed = cur_ops - > get_gp_seq ( ) ;
2012-11-15 08:26:40 +08:00
if ( pipe_count > 1 ) {
2018-05-23 01:56:05 +08:00
do_trace_rcu_torture_read ( cur_ops - > name , & p - > rtort_rcu ,
ts , started , completed ) ;
2016-03-22 10:46:04 +08:00
rcu_ftrace_dump ( DUMP_ALL ) ;
2012-11-15 08:26:40 +08:00
}
2009-10-29 21:34:15 +08:00
__this_cpu_inc ( rcu_torture_count [ pipe_count ] ) ;
2018-05-16 06:24:41 +08:00
completed = rcutorture_seq_diff ( completed , started ) ;
2008-06-26 03:24:52 +08:00
if ( completed > RCU_TORTURE_PIPE_LEN ) {
/* Should not happen, but... */
completed = RCU_TORTURE_PIPE_LEN ;
}
2009-10-29 21:34:15 +08:00
__this_cpu_inc ( rcu_torture_batch [ completed ] ) ;
2008-06-26 03:24:52 +08:00
preempt_enable ( ) ;
2022-08-25 09:57:45 +08:00
if ( checkpolling ) {
if ( cur_ops - > get_gp_state & & cur_ops - > poll_gp_state )
WARN_ONCE ( cur_ops - > poll_gp_state ( cookie ) ,
" %s: Cookie check 2 failed %s(%d) %lu->%lu \n " ,
__func__ ,
rcu_torture_writer_state_getname ( ) ,
rcu_torture_writer_state ,
cookie , cur_ops - > get_gp_state ( ) ) ;
if ( cur_ops - > get_gp_state_full & & cur_ops - > poll_gp_state_full )
WARN_ONCE ( cur_ops - > poll_gp_state_full ( & cookie_full ) ,
" %s: Cookie check 6 failed %s(%d) online %*pbl \n " ,
__func__ ,
rcu_torture_writer_state_getname ( ) ,
rcu_torture_writer_state ,
cpumask_pr_args ( cpu_online_mask ) ) ;
}
2018-07-14 03:09:14 +08:00
rcutorture_one_extend ( & readstate , 0 , trsp , rtrsp ) ;
2021-09-23 11:31:44 +08:00
WARN_ON_ONCE ( readstate ) ;
2020-08-12 01:33:39 +08:00
// This next splat is expected behavior if leakpointer, especially
// for CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels.
WARN_ON_ONCE ( leakpointer & & READ_ONCE ( p - > rtort_pipe_count ) > 1 ) ;
2018-07-14 03:09:14 +08:00
/* If error or close call, record the sequence of reader protections. */
if ( ( pipe_count > 1 | | completed > 1 ) & & ! xchg ( & err_segs_recorded , 1 ) ) {
i = 0 ;
for ( rtrsp1 = & rtseg [ 0 ] ; rtrsp1 < rtrsp ; rtrsp1 + + )
err_segs [ i + + ] = * rtrsp1 ;
rt_read_nsegs = i ;
}
2018-05-23 01:56:05 +08:00
return true ;
}
2018-05-23 02:38:47 +08:00
static DEFINE_TORTURE_RANDOM_PERCPU ( rcu_torture_timer_rand ) ;
2008-06-26 03:24:52 +08:00
/*
* RCU torture reader from timer handler . Dereferences rcu_torture_current ,
* incrementing the corresponding element of the pipeline array . The
* counter in the element should never be greater than 1 , otherwise , the
* RCU implementation is broken .
*/
2017-10-23 08:58:54 +08:00
static void rcu_torture_timer ( struct timer_list * unused )
2008-06-26 03:24:52 +08:00
{
2018-05-23 02:17:51 +08:00
atomic_long_inc ( & n_rcu_torture_timers ) ;
2020-10-30 06:08:57 +08:00
( void ) rcu_torture_one_read ( this_cpu_ptr ( & rcu_torture_timer_rand ) , - 1 ) ;
2017-07-21 06:27:32 +08:00
/* Test call_rcu() invocation from interrupt handler. */
if ( cur_ops - > call ) {
struct rcu_head * rhp = kmalloc ( sizeof ( * rhp ) , GFP_NOWAIT ) ;
if ( rhp )
cur_ops - > call ( rhp , rcu_torture_timer_cb ) ;
}
2008-06-26 03:24:52 +08:00
}
2005-10-31 07:03:12 +08:00
/*
* RCU torture reader kthread . Repeatedly dereferences rcu_torture_current ,
* incrementing the corresponding element of the pipeline array . The
* counter in the element should never be greater than 1 , otherwise , the
* RCU implementation is broken .
*/
static int
rcu_torture_reader ( void * arg )
{
2018-07-05 05:14:42 +08:00
unsigned long lastsleep = jiffies ;
2018-07-24 05:16:47 +08:00
long myid = ( long ) arg ;
int mynumonline = myid ;
2014-01-28 03:49:39 +08:00
DEFINE_TORTURE_RANDOM ( rand ) ;
2008-06-26 03:24:52 +08:00
struct timer_list t ;
2005-10-31 07:03:12 +08:00
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_reader task started " ) ;
2014-02-11 15:34:49 +08:00
set_user_nice ( current , MAX_NICE ) ;
2009-06-26 00:08:17 +08:00
if ( irqreader & & cur_ops - > irq_capable )
2017-10-23 08:58:54 +08:00
timer_setup_on_stack ( & t , rcu_torture_timer , 0 ) ;
2019-07-29 03:00:48 +08:00
tick_dep_set_task ( current , TICK_DEP_BIT_RCU ) ;
2005-10-31 07:03:12 +08:00
do {
2009-06-26 00:08:17 +08:00
if ( irqreader & & cur_ops - > irq_capable ) {
2008-06-26 03:24:52 +08:00
if ( ! timer_pending ( & t ) )
2010-02-23 09:05:04 +08:00
mod_timer ( & t , jiffies + 1 ) ;
2008-06-26 03:24:52 +08:00
}
2020-10-30 06:08:57 +08:00
if ( ! rcu_torture_one_read ( & rand , myid ) & & ! torture_must_stop ( ) )
2005-10-31 07:03:12 +08:00
schedule_timeout_interruptible ( HZ ) ;
2019-07-29 03:00:48 +08:00
if ( time_after ( jiffies , lastsleep ) & & ! torture_must_stop ( ) ) {
2020-11-18 06:12:24 +08:00
torture_hrtimeout_us ( 500 , 1000 , & rand ) ;
2018-07-05 05:14:42 +08:00
lastsleep = jiffies + 10 ;
}
2020-12-19 23:34:35 +08:00
while ( torture_num_online_cpus ( ) < mynumonline & & ! torture_must_stop ( ) )
2018-07-24 05:16:47 +08:00
schedule_timeout_interruptible ( HZ / 5 ) ;
2014-02-01 03:57:43 +08:00
stutter_wait ( " rcu_torture_reader " ) ;
2014-01-31 07:49:29 +08:00
} while ( ! torture_must_stop ( ) ) ;
2014-03-23 23:58:27 +08:00
if ( irqreader & & cur_ops - > irq_capable ) {
2008-06-26 03:24:52 +08:00
del_timer_sync ( & t ) ;
2014-03-23 23:58:27 +08:00
destroy_timer_on_stack ( & t ) ;
}
2019-07-29 03:00:48 +08:00
tick_dep_clear_task ( current , TICK_DEP_BIT_RCU ) ;
2014-02-01 09:37:28 +08:00
torture_kthread_stopping ( " rcu_torture_reader " ) ;
2005-10-31 07:03:12 +08:00
return 0 ;
}
2020-09-24 08:39:46 +08:00
/*
* Randomly Toggle CPUs ' callback - offload state . This uses hrtimers to
* increase race probabilities and fuzzes the interval between toggling .
*/
static int rcu_nocb_toggle ( void * arg )
{
int cpu ;
int maxcpu = - 1 ;
int oldnice = task_nice ( current ) ;
long r ;
DEFINE_TORTURE_RANDOM ( rand ) ;
ktime_t toggle_delay ;
unsigned long toggle_fuzz ;
ktime_t toggle_interval = ms_to_ktime ( nocbs_toggle ) ;
VERBOSE_TOROUT_STRING ( " rcu_nocb_toggle task started " ) ;
while ( ! rcu_inkernel_boot_has_ended ( ) )
schedule_timeout_interruptible ( HZ / 10 ) ;
for_each_online_cpu ( cpu )
maxcpu = cpu ;
WARN_ON ( maxcpu < 0 ) ;
if ( toggle_interval > ULONG_MAX )
toggle_fuzz = ULONG_MAX > > 3 ;
else
toggle_fuzz = toggle_interval > > 3 ;
if ( toggle_fuzz < = 0 )
toggle_fuzz = NSEC_PER_USEC ;
do {
r = torture_random ( & rand ) ;
2023-07-13 07:16:37 +08:00
cpu = ( r > > 1 ) % ( maxcpu + 1 ) ;
2020-09-24 08:39:46 +08:00
if ( r & 0x1 ) {
rcu_nocb_cpu_offload ( cpu ) ;
atomic_long_inc ( & n_nocb_offload ) ;
} else {
rcu_nocb_cpu_deoffload ( cpu ) ;
atomic_long_inc ( & n_nocb_deoffload ) ;
}
toggle_delay = torture_random ( & rand ) % toggle_fuzz + toggle_interval ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
schedule_hrtimeout ( & toggle_delay , HRTIMER_MODE_REL ) ;
if ( stutter_wait ( " rcu_nocb_toggle " ) )
sched_set_normal ( current , oldnice ) ;
} while ( ! torture_must_stop ( ) ) ;
torture_kthread_stopping ( " rcu_nocb_toggle " ) ;
return 0 ;
}
2005-10-31 07:03:12 +08:00
/*
2014-07-14 21:16:15 +08:00
* Print torture statistics . Caller must ensure that there is only
* one call to this function at a given time ! ! ! This is normally
* accomplished by relying on the module system to only have one copy
* of the module loaded , and then by giving the rcu_torture_stats
* kthread full control ( or the init / cleanup functions when rcu_torture_stats
* thread is not running ) .
2005-10-31 07:03:12 +08:00
*/
rcu/torture: Dynamically allocate SRCU output buffer to avoid overflow
If the rcutorture SRCU output exceeds 4096 bytes, for example, if you
have more than about 75 CPUs, it will overflow the current statically
allocated buffer. This commit therefore replaces this static buffer
with a dynamically buffer whose size is based on the number of CPUs.
Benefits:
- Avoids both buffer overflow and output truncation.
- Handles an arbitrarily large number of CPUs.
- Straightforward implementation.
Shortcomings:
- Some memory is wasted:
1 cpu now comsumes 50 - 60 bytes, and this patch provides 200 bytes.
Therefore, for 1K CPUs, roughly 100KB of memory will be wasted.
However, the memory is freed immediately after printing, so this
wastage should not be a problem in practice.
Testing (Fedora16 2 CPUs, 2GB RAM x86_64):
- as module, with/without "torture_type=srcu".
- build-in not boot runnable, with/without "torture_type=srcu".
- build-in let boot runnable, with/without "torture_type=srcu".
Signed-off-by: Chen Gang <gang.chen@asianux.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
2013-11-07 10:30:25 +08:00
static void
2014-07-14 21:16:15 +08:00
rcu_torture_stats_print ( void )
2005-10-31 07:03:12 +08:00
{
int cpu ;
int i ;
long pipesummary [ RCU_TORTURE_PIPE_LEN + 1 ] = { 0 } ;
long batchsummary [ RCU_TORTURE_PIPE_LEN + 1 ] = { 0 } ;
2020-01-09 11:58:13 +08:00
struct rcu_torture * rtcp ;
2014-02-20 02:51:42 +08:00
static unsigned long rtcv_snap = ULONG_MAX ;
2017-08-31 01:40:17 +08:00
static bool splatted ;
2016-07-01 02:56:38 +08:00
struct task_struct * wtp ;
2005-10-31 07:03:12 +08:00
2006-03-28 17:56:37 +08:00
for_each_possible_cpu ( cpu ) {
2005-10-31 07:03:12 +08:00
for ( i = 0 ; i < RCU_TORTURE_PIPE_LEN + 1 ; i + + ) {
2020-01-04 08:27:00 +08:00
pipesummary [ i ] + = READ_ONCE ( per_cpu ( rcu_torture_count , cpu ) [ i ] ) ;
batchsummary [ i ] + = READ_ONCE ( per_cpu ( rcu_torture_batch , cpu ) [ i ] ) ;
2005-10-31 07:03:12 +08:00
}
}
2022-05-21 04:18:16 +08:00
for ( i = RCU_TORTURE_PIPE_LEN ; i > = 0 ; i - - ) {
2005-10-31 07:03:12 +08:00
if ( pipesummary [ i ] ! = 0 )
break ;
}
2014-07-14 21:16:15 +08:00
pr_alert ( " %s%s " , torture_type , TORTURE_FLAG ) ;
2020-01-09 11:58:13 +08:00
rtcp = rcu_access_pointer ( rcu_torture_current ) ;
2019-05-26 03:36:53 +08:00
pr_cont ( " rtc: %p %s: %lu tfle: %d rta: %d rtaf: %d rtf: %d " ,
2020-01-09 11:58:13 +08:00
rtcp ,
rtcp & & ! rcu_stall_is_suppressed_at_boot ( ) ? " ver " : " VER " ,
2014-07-14 21:16:15 +08:00
rcu_torture_current_version ,
list_empty ( & rcu_torture_freelist ) ,
atomic_read ( & n_rcu_torture_alloc ) ,
atomic_read ( & n_rcu_torture_alloc_fail ) ,
atomic_read ( & n_rcu_torture_free ) ) ;
2023-01-17 13:53:10 +08:00
pr_cont ( " rtmbe: %d rtmbkf: %d/%d rtbe: %ld rtbke: %ld " ,
2014-07-14 21:16:15 +08:00
atomic_read ( & n_rcu_torture_mberror ) ,
2020-10-30 06:08:57 +08:00
atomic_read ( & n_rcu_torture_mbchk_fail ) , atomic_read ( & n_rcu_torture_mbchk_tries ) ,
2016-08-13 14:54:35 +08:00
n_rcu_torture_barrier_error ,
2023-01-17 13:53:10 +08:00
n_rcu_torture_boost_ktrerror ) ;
2014-07-14 21:16:15 +08:00
pr_cont ( " rtbf: %ld rtb: %ld nt: %ld " ,
n_rcu_torture_boost_failure ,
n_rcu_torture_boosts ,
2018-05-23 02:17:51 +08:00
atomic_long_read ( & n_rcu_torture_timers ) ) ;
2014-07-14 21:16:15 +08:00
torture_onoff_stats ( ) ;
2020-04-25 02:21:40 +08:00
pr_cont ( " barrier: %ld/%ld:%ld " ,
2020-02-19 05:41:02 +08:00
data_race ( n_barrier_successes ) ,
data_race ( n_barrier_attempts ) ,
data_race ( n_rcu_torture_barrier_error ) ) ;
2020-12-22 03:17:16 +08:00
pr_cont ( " read-exits: %ld " , data_race ( n_read_exits ) ) ; // Statistic.
2020-09-24 08:39:46 +08:00
pr_cont ( " nocb-toggles: %ld:%ld \n " ,
atomic_long_read ( & n_nocb_offload ) , atomic_long_read ( & n_nocb_deoffload ) ) ;
2014-07-14 21:16:15 +08:00
pr_alert ( " %s%s " , torture_type , TORTURE_FLAG ) ;
2019-08-15 03:02:40 +08:00
if ( atomic_read ( & n_rcu_torture_mberror ) | |
2020-10-30 06:08:57 +08:00
atomic_read ( & n_rcu_torture_mbchk_fail ) | |
2019-08-15 03:02:40 +08:00
n_rcu_torture_barrier_error | | n_rcu_torture_boost_ktrerror | |
2023-01-17 13:53:10 +08:00
n_rcu_torture_boost_failure | | i > 1 ) {
2014-07-14 21:16:15 +08:00
pr_cont ( " %s " , " !!! " ) ;
2005-11-18 17:10:50 +08:00
atomic_inc ( & n_rcu_torture_error ) ;
2019-08-15 03:02:40 +08:00
WARN_ON_ONCE ( atomic_read ( & n_rcu_torture_mberror ) ) ;
2020-10-30 06:08:57 +08:00
WARN_ON_ONCE ( atomic_read ( & n_rcu_torture_mbchk_fail ) ) ;
2019-08-15 03:02:40 +08:00
WARN_ON_ONCE ( n_rcu_torture_barrier_error ) ; // rcu_barrier()
WARN_ON_ONCE ( n_rcu_torture_boost_ktrerror ) ; // no boost kthread
2021-01-16 05:30:38 +08:00
WARN_ON_ONCE ( n_rcu_torture_boost_failure ) ; // boost failed (TIMER_SOFTIRQ RT prio?)
2019-08-15 03:02:40 +08:00
WARN_ON_ONCE ( i > 1 ) ; // Too-short grace period
2005-11-18 17:10:50 +08:00
}
2014-07-14 21:16:15 +08:00
pr_cont ( " Reader Pipe: " ) ;
2005-10-31 07:03:12 +08:00
for ( i = 0 ; i < RCU_TORTURE_PIPE_LEN + 1 ; i + + )
2014-07-14 21:16:15 +08:00
pr_cont ( " %ld " , pipesummary [ i ] ) ;
pr_cont ( " \n " ) ;
pr_alert ( " %s%s " , torture_type , TORTURE_FLAG ) ;
pr_cont ( " Reader Batch: " ) ;
2006-06-27 17:54:03 +08:00
for ( i = 0 ; i < RCU_TORTURE_PIPE_LEN + 1 ; i + + )
2014-07-14 21:16:15 +08:00
pr_cont ( " %ld " , batchsummary [ i ] ) ;
pr_cont ( " \n " ) ;
pr_alert ( " %s%s " , torture_type , TORTURE_FLAG ) ;
pr_cont ( " Free-Block Circulation: " ) ;
2005-10-31 07:03:12 +08:00
for ( i = 0 ; i < RCU_TORTURE_PIPE_LEN + 1 ; i + + ) {
2014-07-14 21:16:15 +08:00
pr_cont ( " %d " , atomic_read ( & rcu_torture_wcount [ i ] ) ) ;
2005-10-31 07:03:12 +08:00
}
2014-07-14 21:16:15 +08:00
pr_cont ( " \n " ) ;
2007-05-08 15:33:20 +08:00
if ( cur_ops - > stats )
2014-07-14 21:16:15 +08:00
cur_ops - > stats ( ) ;
2014-02-20 02:51:42 +08:00
if ( rtcv_snap = = rcu_torture_current_version & &
2020-01-09 11:58:13 +08:00
rcu_access_pointer ( rcu_torture_current ) & &
! rcu_stall_is_suppressed ( ) ) {
2017-04-19 08:17:35 +08:00
int __maybe_unused flags = 0 ;
2018-05-01 21:42:51 +08:00
unsigned long __maybe_unused gp_seq = 0 ;
2014-02-20 02:51:42 +08:00
rcutorture_get_gp_data ( cur_ops - > ttype ,
2018-05-01 21:42:51 +08:00
& flags , & gp_seq ) ;
2017-04-19 08:17:35 +08:00
srcutorture_get_gp_data ( cur_ops - > ttype , srcu_ctlp ,
2018-05-01 21:42:51 +08:00
& flags , & gp_seq ) ;
2016-07-01 02:56:38 +08:00
wtp = READ_ONCE ( writer_task ) ;
2021-06-11 16:28:17 +08:00
pr_alert ( " ??? Writer stall state %s(%d) g%lu f%#x ->state %#x cpu %d \n " ,
2015-11-18 05:35:28 +08:00
rcu_torture_writer_state_getname ( ) ,
2018-05-01 21:42:51 +08:00
rcu_torture_writer_state , gp_seq , flags ,
2021-06-11 16:28:17 +08:00
wtp = = NULL ? ~ 0U : wtp - > __state ,
2017-06-20 01:03:22 +08:00
wtp = = NULL ? - 1 : ( int ) task_cpu ( wtp ) ) ;
2017-08-31 01:40:17 +08:00
if ( ! splatted & & wtp ) {
sched_show_task ( wtp ) ;
splatted = true ;
}
2020-09-16 08:08:03 +08:00
if ( cur_ops - > gp_kthread_dbg )
cur_ops - > gp_kthread_dbg ( ) ;
2016-03-22 10:46:04 +08:00
rcu_ftrace_dump ( DUMP_ALL ) ;
2014-02-20 02:51:42 +08:00
}
rtcv_snap = rcu_torture_current_version ;
2005-10-31 07:03:12 +08:00
}
/*
* Periodically prints torture statistics , if periodic statistics printing
* was specified via the stat_interval module parameter .
*/
static int
rcu_torture_stats ( void * arg )
{
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_stats task started " ) ;
2005-10-31 07:03:12 +08:00
do {
schedule_timeout_interruptible ( stat_interval * HZ ) ;
rcu_torture_stats_print ( ) ;
2014-01-29 23:40:27 +08:00
torture_shutdown_absorb ( " rcu_torture_stats " ) ;
2014-01-31 07:49:29 +08:00
} while ( ! torture_must_stop ( ) ) ;
2014-02-01 09:37:28 +08:00
torture_kthread_stopping ( " rcu_torture_stats " ) ;
2008-06-18 20:21:44 +08:00
return 0 ;
}
2021-05-03 10:56:05 +08:00
/* Test mem_dump_obj() and friends. */
static void rcu_torture_mem_dump_obj ( void )
{
struct rcu_head * rhp ;
struct kmem_cache * kcp ;
static int z ;
kcp = kmem_cache_create ( " rcuscale " , 136 , 8 , SLAB_STORE_USER , NULL ) ;
2022-06-12 14:48:25 +08:00
if ( WARN_ON_ONCE ( ! kcp ) )
return ;
2021-05-03 10:56:05 +08:00
rhp = kmem_cache_alloc ( kcp , GFP_KERNEL ) ;
2022-06-12 14:48:25 +08:00
if ( WARN_ON_ONCE ( ! rhp ) ) {
kmem_cache_destroy ( kcp ) ;
return ;
}
2021-05-03 10:56:05 +08:00
pr_alert ( " mem_dump_obj() slab test: rcu_torture_stats = %px, &rhp = %px, rhp = %px, &z = %px \n " , stats_task , & rhp , rhp , & z ) ;
pr_alert ( " mem_dump_obj(ZERO_SIZE_PTR): " ) ;
mem_dump_obj ( ZERO_SIZE_PTR ) ;
pr_alert ( " mem_dump_obj(NULL): " ) ;
mem_dump_obj ( NULL ) ;
pr_alert ( " mem_dump_obj(%px): " , & rhp ) ;
mem_dump_obj ( & rhp ) ;
pr_alert ( " mem_dump_obj(%px): " , rhp ) ;
mem_dump_obj ( rhp ) ;
pr_alert ( " mem_dump_obj(%px): " , & rhp - > func ) ;
mem_dump_obj ( & rhp - > func ) ;
pr_alert ( " mem_dump_obj(%px): " , & z ) ;
mem_dump_obj ( & z ) ;
kmem_cache_free ( kcp , rhp ) ;
kmem_cache_destroy ( kcp ) ;
rhp = kmalloc ( sizeof ( * rhp ) , GFP_KERNEL ) ;
2022-06-12 14:48:25 +08:00
if ( WARN_ON_ONCE ( ! rhp ) )
return ;
2021-05-03 10:56:05 +08:00
pr_alert ( " mem_dump_obj() kmalloc test: rcu_torture_stats = %px, &rhp = %px, rhp = %px \n " , stats_task , & rhp , rhp ) ;
pr_alert ( " mem_dump_obj(kmalloc %px): " , rhp ) ;
mem_dump_obj ( rhp ) ;
pr_alert ( " mem_dump_obj(kmalloc %px): " , & rhp - > func ) ;
mem_dump_obj ( & rhp - > func ) ;
kfree ( rhp ) ;
rhp = vmalloc ( 4096 ) ;
2022-06-12 14:48:25 +08:00
if ( WARN_ON_ONCE ( ! rhp ) )
return ;
2021-05-03 10:56:05 +08:00
pr_alert ( " mem_dump_obj() vmalloc test: rcu_torture_stats = %px, &rhp = %px, rhp = %px \n " , stats_task , & rhp , rhp ) ;
pr_alert ( " mem_dump_obj(vmalloc %px): " , rhp ) ;
mem_dump_obj ( rhp ) ;
pr_alert ( " mem_dump_obj(vmalloc %px): " , & rhp - > func ) ;
mem_dump_obj ( & rhp - > func ) ;
vfree ( rhp ) ;
}
2018-05-18 02:33:17 +08:00
static void
2013-07-13 04:50:28 +08:00
rcu_torture_print_module_parms ( struct rcu_torture_ops * cur_ops , const char * tag )
2006-03-24 19:15:58 +08:00
{
2012-08-10 07:30:45 +08:00
pr_alert ( " %s " TORTURE_FLAG
" --- %s: nreaders=%d nfakewriters=%d "
" stat_interval=%d verbose=%d test_no_idle_hz=%d "
" shuffle_interval=%d stutter=%d irqreader=%d "
" fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
" test_boost=%d/%d test_boost_interval=%d "
" test_boost_duration=%d shutdown_secs=%d "
2017-08-19 07:11:37 +08:00
" stall_cpu=%d stall_cpu_holdoff=%d stall_cpu_irqsoff=%d "
2020-03-12 08:39:12 +08:00
" stall_cpu_block=%d "
2012-10-21 03:56:06 +08:00
" n_barrier_cbs=%d "
2020-04-25 02:21:40 +08:00
" onoff_interval=%d onoff_holdoff=%d "
2020-09-24 08:39:46 +08:00
" read_exit_delay=%d read_exit_burst=%d "
2022-12-20 03:21:09 +08:00
" nocbs_nthreads=%d nocbs_toggle=%d "
" test_nmis=%d \n " ,
2012-08-10 07:30:45 +08:00
torture_type , tag , nrealreaders , nfakewriters ,
stat_interval , verbose , test_no_idle_hz , shuffle_interval ,
stutter , irqreader , fqs_duration , fqs_holdoff , fqs_stutter ,
test_boost , cur_ops - > can_boost ,
test_boost_interval , test_boost_duration , shutdown_secs ,
2017-08-19 07:11:37 +08:00
stall_cpu , stall_cpu_holdoff , stall_cpu_irqsoff ,
2020-03-12 08:39:12 +08:00
stall_cpu_block ,
2012-10-21 03:56:06 +08:00
n_barrier_cbs ,
2020-04-25 02:21:40 +08:00
onoff_interval , onoff_holdoff ,
2020-09-24 08:39:46 +08:00
read_exit_delay , read_exit_burst ,
2022-12-20 03:21:09 +08:00
nocbs_nthreads , nocbs_toggle ,
test_nmis ) ;
2006-03-24 19:15:58 +08:00
}
2016-08-18 20:57:22 +08:00
static int rcutorture_booster_cleanup ( unsigned int cpu )
2010-09-03 07:16:14 +08:00
{
struct task_struct * t ;
if ( boost_tasks [ cpu ] = = NULL )
2016-08-18 20:57:22 +08:00
return 0 ;
2010-09-03 07:16:14 +08:00
mutex_lock ( & boost_mutex ) ;
t = boost_tasks [ cpu ] ;
boost_tasks [ cpu ] = NULL ;
2018-06-11 07:45:43 +08:00
rcu_torture_enable_rt_throttle ( ) ;
2010-09-03 07:16:14 +08:00
mutex_unlock ( & boost_mutex ) ;
/* This must be outside of the mutex, otherwise deadlock! */
2014-02-05 03:47:08 +08:00
torture_stop_kthread ( rcu_torture_boost , t ) ;
2016-08-18 20:57:22 +08:00
return 0 ;
2010-09-03 07:16:14 +08:00
}
2016-08-18 20:57:22 +08:00
static int rcutorture_booster_init ( unsigned int cpu )
2010-09-03 07:16:14 +08:00
{
int retval ;
if ( boost_tasks [ cpu ] ! = NULL )
return 0 ; /* Already created, nothing more to do. */
2022-06-10 21:03:57 +08:00
// Testing RCU priority boosting requires rcutorture do
// some serious abuse. Counter this by running ksoftirqd
// at higher priority.
if ( IS_BUILTIN ( CONFIG_RCU_TORTURE_TEST ) ) {
struct sched_param sp ;
struct task_struct * t ;
t = per_cpu ( ksoftirqd , cpu ) ;
WARN_ON_ONCE ( ! t ) ;
sp . sched_priority = 2 ;
sched_setscheduler_nocheck ( t , SCHED_FIFO , & sp ) ;
}
2010-09-03 07:16:14 +08:00
/* Don't allow time recalculation while creating a new task. */
mutex_lock ( & boost_mutex ) ;
2018-06-11 07:45:43 +08:00
rcu_torture_disable_rt_throttle ( ) ;
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " Creating rcu_torture_boost task " ) ;
2022-01-15 06:03:02 +08:00
boost_tasks [ cpu ] = kthread_run_on_cpu ( rcu_torture_boost , NULL ,
cpu , " rcu_torture_boost_%u " ) ;
2010-09-03 07:16:14 +08:00
if ( IS_ERR ( boost_tasks [ cpu ] ) ) {
retval = PTR_ERR ( boost_tasks [ cpu ] ) ;
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_boost task create failed " ) ;
2010-09-03 07:16:14 +08:00
n_rcu_torture_boost_ktrerror + + ;
boost_tasks [ cpu ] = NULL ;
mutex_unlock ( & boost_mutex ) ;
return retval ;
}
mutex_unlock ( & boost_mutex ) ;
return 0 ;
}
2012-01-21 07:36:33 +08:00
/*
* CPU - stall kthread . It waits as specified by stall_cpu_holdoff , then
* induces a CPU stall for the time specified by stall_cpu .
*/
2013-06-20 02:52:21 +08:00
static int rcu_torture_stall ( void * args )
2012-01-21 07:36:33 +08:00
{
2020-03-12 08:39:12 +08:00
int idx ;
2012-01-21 07:36:33 +08:00
unsigned long stop_at ;
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_stall task started " ) ;
2012-01-21 07:36:33 +08:00
if ( stall_cpu_holdoff > 0 ) {
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_stall begin holdoff " ) ;
2012-01-21 07:36:33 +08:00
schedule_timeout_interruptible ( stall_cpu_holdoff * HZ ) ;
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_stall end holdoff " ) ;
2012-01-21 07:36:33 +08:00
}
2020-04-02 10:57:52 +08:00
if ( ! kthread_should_stop ( ) & & stall_gp_kthread > 0 ) {
VERBOSE_TOROUT_STRING ( " rcu_torture_stall begin GP stall " ) ;
rcu_gp_set_torture_wait ( stall_gp_kthread * HZ ) ;
for ( idx = 0 ; idx < stall_gp_kthread + 2 ; idx + + ) {
if ( kthread_should_stop ( ) )
break ;
schedule_timeout_uninterruptible ( HZ ) ;
}
}
if ( ! kthread_should_stop ( ) & & stall_cpu > 0 ) {
VERBOSE_TOROUT_STRING ( " rcu_torture_stall begin CPU stall " ) ;
2018-06-18 22:47:34 +08:00
stop_at = ktime_get_seconds ( ) + stall_cpu ;
2012-01-21 07:36:33 +08:00
/* RCU CPU stall is expected behavior in following code. */
2020-03-12 08:39:12 +08:00
idx = cur_ops - > readlock ( ) ;
2017-08-19 07:11:37 +08:00
if ( stall_cpu_irqsoff )
local_irq_disable ( ) ;
2020-03-12 08:39:12 +08:00
else if ( ! stall_cpu_block )
2017-08-19 07:11:37 +08:00
preempt_disable ( ) ;
2021-01-23 17:54:17 +08:00
pr_alert ( " %s start on CPU %d. \n " ,
__func__ , raw_smp_processor_id ( ) ) ;
2018-06-18 22:47:34 +08:00
while ( ULONG_CMP_LT ( ( unsigned long ) ktime_get_seconds ( ) ,
stop_at ) )
2021-05-17 12:17:27 +08:00
if ( stall_cpu_block ) {
# ifdef CONFIG_PREEMPTION
preempt_schedule ( ) ;
# else
2020-03-12 08:39:12 +08:00
schedule_timeout_uninterruptible ( HZ ) ;
2021-05-17 12:17:27 +08:00
# endif
2021-11-10 22:37:45 +08:00
} else if ( stall_no_softlockup ) {
touch_softlockup_watchdog ( ) ;
2021-05-17 12:17:27 +08:00
}
2017-08-19 07:11:37 +08:00
if ( stall_cpu_irqsoff )
local_irq_enable ( ) ;
2020-03-12 08:39:12 +08:00
else if ( ! stall_cpu_block )
2017-08-19 07:11:37 +08:00
preempt_enable ( ) ;
2020-03-12 08:39:12 +08:00
cur_ops - > readunlock ( idx ) ;
2012-01-21 07:36:33 +08:00
}
2021-01-23 17:54:17 +08:00
pr_alert ( " %s end. \n " , __func__ ) ;
2014-01-29 23:40:27 +08:00
torture_shutdown_absorb ( " rcu_torture_stall " ) ;
2012-01-21 07:36:33 +08:00
while ( ! kthread_should_stop ( ) )
schedule_timeout_interruptible ( 10 * HZ ) ;
return 0 ;
}
/* Spawn CPU-stall kthread, if stall_cpu specified. */
static int __init rcu_torture_stall_init ( void )
{
2020-04-02 10:57:52 +08:00
if ( stall_cpu < = 0 & & stall_gp_kthread < = 0 )
2012-01-21 07:36:33 +08:00
return 0 ;
2014-02-04 03:52:27 +08:00
return torture_create_kthread ( rcu_torture_stall , NULL , stall_task ) ;
2012-01-21 07:36:33 +08:00
}
2018-07-20 04:36:00 +08:00
/* State structure for forward-progress self-propagating RCU callback. */
struct fwd_cb_state {
struct rcu_head rh ;
int stop ;
} ;
/*
* Forward - progress self - propagating RCU callback function . Because
* callbacks run from softirq , this function is an implicit RCU read - side
* critical section .
*/
static void rcu_torture_fwd_prog_cb ( struct rcu_head * rhp )
{
struct fwd_cb_state * fcsp = container_of ( rhp , struct fwd_cb_state , rh ) ;
if ( READ_ONCE ( fcsp - > stop ) ) {
WRITE_ONCE ( fcsp - > stop , 2 ) ;
return ;
}
cur_ops - > call ( & fcsp - > rh , rcu_torture_fwd_prog_cb ) ;
}
2018-08-16 06:32:51 +08:00
/* State for continuous-flood RCU callbacks. */
struct rcu_fwd_cb {
struct rcu_head rh ;
struct rcu_fwd_cb * rfc_next ;
2019-11-06 01:08:58 +08:00
struct rcu_fwd * rfc_rfp ;
2018-08-16 06:32:51 +08:00
int rfc_gps ;
} ;
2019-11-06 00:31:56 +08:00
2018-08-16 06:32:51 +08:00
# define MAX_FWD_CB_JIFFIES (8 * HZ) /* Maximum CB test duration. */
# define MIN_FWD_CB_LAUNDERS 3 /* This many CB invocations to count. */
# define MIN_FWD_CBS_LAUNDERED 100 /* Number of counted CBs. */
2018-10-06 07:43:09 +08:00
# define FWD_CBS_HIST_DIV 10 /* Histogram buckets/second. */
2019-11-06 00:31:56 +08:00
# define N_LAUNDERS_HIST (2 * MAX_FWD_CB_JIFFIES / (HZ / FWD_CBS_HIST_DIV))
2019-01-09 05:41:26 +08:00
struct rcu_launder_hist {
long n_launders ;
unsigned long launder_gp_seq ;
} ;
2018-08-16 06:32:51 +08:00
2019-11-06 00:31:56 +08:00
struct rcu_fwd {
spinlock_t rcu_fwd_lock ;
struct rcu_fwd_cb * rcu_fwd_cb_head ;
struct rcu_fwd_cb * * rcu_fwd_cb_tail ;
long n_launders_cb ;
unsigned long rcu_fwd_startat ;
struct rcu_launder_hist n_launders_hist [ N_LAUNDERS_HIST ] ;
unsigned long rcu_launder_gp_seq_start ;
2021-11-23 12:55:18 +08:00
int rcu_fwd_id ;
2019-11-06 00:31:56 +08:00
} ;
2020-07-20 23:34:07 +08:00
static DEFINE_MUTEX ( rcu_fwd_mutex ) ;
2020-04-09 19:42:38 +08:00
static struct rcu_fwd * rcu_fwds ;
2021-11-23 12:55:18 +08:00
static unsigned long rcu_fwd_seq ;
2021-11-24 05:51:11 +08:00
static atomic_long_t rcu_fwd_max_cbs ;
2020-04-09 19:42:38 +08:00
static bool rcu_fwd_emergency_stop ;
2018-08-16 06:32:51 +08:00
2019-11-06 01:08:58 +08:00
static void rcu_torture_fwd_cb_hist ( struct rcu_fwd * rfp )
2018-10-04 03:33:41 +08:00
{
2019-01-09 05:41:26 +08:00
unsigned long gps ;
unsigned long gps_old ;
2018-10-04 03:33:41 +08:00
int i ;
int j ;
2019-11-06 01:08:58 +08:00
for ( i = ARRAY_SIZE ( rfp - > n_launders_hist ) - 1 ; i > 0 ; i - - )
if ( rfp - > n_launders_hist [ i ] . n_launders > 0 )
2018-10-04 03:33:41 +08:00
break ;
2021-11-23 12:55:18 +08:00
pr_alert ( " %s: Callback-invocation histogram %d (duration %lu jiffies): " ,
__func__ , rfp - > rcu_fwd_id , jiffies - rfp - > rcu_fwd_startat ) ;
2019-11-06 01:08:58 +08:00
gps_old = rfp - > rcu_launder_gp_seq_start ;
2019-01-09 05:41:26 +08:00
for ( j = 0 ; j < = i ; j + + ) {
2019-11-06 01:08:58 +08:00
gps = rfp - > n_launders_hist [ j ] . launder_gp_seq ;
2019-01-09 05:41:26 +08:00
pr_cont ( " %ds/%d: %ld:%ld " ,
2019-11-06 00:31:56 +08:00
j + 1 , FWD_CBS_HIST_DIV ,
2019-11-06 01:08:58 +08:00
rfp - > n_launders_hist [ j ] . n_launders ,
2019-01-09 05:41:26 +08:00
rcutorture_seq_diff ( gps , gps_old ) ) ;
gps_old = gps ;
}
2018-10-04 03:33:41 +08:00
pr_cont ( " \n " ) ;
}
2018-08-16 06:32:51 +08:00
/* Callback function for continuous-flood RCU callbacks. */
static void rcu_torture_fwd_cb_cr ( struct rcu_head * rhp )
{
2018-10-06 00:09:49 +08:00
unsigned long flags ;
2018-08-16 06:32:51 +08:00
int i ;
struct rcu_fwd_cb * rfcp = container_of ( rhp , struct rcu_fwd_cb , rh ) ;
struct rcu_fwd_cb * * rfcpp ;
2019-11-06 01:08:58 +08:00
struct rcu_fwd * rfp = rfcp - > rfc_rfp ;
2018-08-16 06:32:51 +08:00
rfcp - > rfc_next = NULL ;
rfcp - > rfc_gps + + ;
2019-11-06 01:08:58 +08:00
spin_lock_irqsave ( & rfp - > rcu_fwd_lock , flags ) ;
rfcpp = rfp - > rcu_fwd_cb_tail ;
rfp - > rcu_fwd_cb_tail = & rfcp - > rfc_next ;
2018-08-16 06:32:51 +08:00
WRITE_ONCE ( * rfcpp , rfcp ) ;
2019-11-06 01:08:58 +08:00
WRITE_ONCE ( rfp - > n_launders_cb , rfp - > n_launders_cb + 1 ) ;
i = ( ( jiffies - rfp - > rcu_fwd_startat ) / ( HZ / FWD_CBS_HIST_DIV ) ) ;
if ( i > = ARRAY_SIZE ( rfp - > n_launders_hist ) )
i = ARRAY_SIZE ( rfp - > n_launders_hist ) - 1 ;
rfp - > n_launders_hist [ i ] . n_launders + + ;
rfp - > n_launders_hist [ i ] . launder_gp_seq = cur_ops - > get_gp_seq ( ) ;
spin_unlock_irqrestore ( & rfp - > rcu_fwd_lock , flags ) ;
2018-10-06 00:09:49 +08:00
}
2019-04-15 09:30:22 +08:00
// Give the scheduler a chance, even on nohz_full CPUs.
2019-06-23 05:35:59 +08:00
static void rcu_torture_fwd_prog_cond_resched ( unsigned long iter )
2019-04-15 09:30:22 +08:00
{
2019-10-16 03:18:14 +08:00
if ( IS_ENABLED ( CONFIG_PREEMPTION ) & & IS_ENABLED ( CONFIG_NO_HZ_FULL ) ) {
2019-06-23 05:35:59 +08:00
// Real call_rcu() floods hit userspace, so emulate that.
if ( need_resched ( ) | | ( iter & 0xfff ) )
2019-04-15 09:30:22 +08:00
schedule ( ) ;
2019-07-29 03:00:48 +08:00
return ;
2019-04-15 09:30:22 +08:00
}
2019-07-29 03:00:48 +08:00
// No userspace emulation: CB invocation throttles call_rcu()
cond_resched ( ) ;
2019-04-15 09:30:22 +08:00
}
2018-10-06 00:09:49 +08:00
/*
* Free all callbacks on the rcu_fwd_cb_head list , either because the
* test is over or because we hit an OOM event .
*/
2019-11-07 00:20:20 +08:00
static unsigned long rcu_torture_fwd_prog_cbfree ( struct rcu_fwd * rfp )
2018-10-06 00:09:49 +08:00
{
unsigned long flags ;
unsigned long freed = 0 ;
struct rcu_fwd_cb * rfcp ;
for ( ; ; ) {
2019-11-07 00:20:20 +08:00
spin_lock_irqsave ( & rfp - > rcu_fwd_lock , flags ) ;
rfcp = rfp - > rcu_fwd_cb_head ;
2019-04-10 01:08:18 +08:00
if ( ! rfcp ) {
2019-11-07 00:20:20 +08:00
spin_unlock_irqrestore ( & rfp - > rcu_fwd_lock , flags ) ;
2018-10-06 00:09:49 +08:00
break ;
2019-04-10 01:08:18 +08:00
}
2019-11-07 00:20:20 +08:00
rfp - > rcu_fwd_cb_head = rfcp - > rfc_next ;
if ( ! rfp - > rcu_fwd_cb_head )
rfp - > rcu_fwd_cb_tail = & rfp - > rcu_fwd_cb_head ;
spin_unlock_irqrestore ( & rfp - > rcu_fwd_lock , flags ) ;
2018-10-06 00:09:49 +08:00
kfree ( rfcp ) ;
freed + + ;
2019-06-23 05:35:59 +08:00
rcu_torture_fwd_prog_cond_resched ( freed ) ;
2019-08-05 04:17:35 +08:00
if ( tick_nohz_full_enabled ( ) ) {
local_irq_save ( flags ) ;
rcu_momentary_dyntick_idle ( ) ;
local_irq_restore ( flags ) ;
}
2018-10-06 00:09:49 +08:00
}
return freed ;
2018-08-16 06:32:51 +08:00
}
2018-08-29 05:38:43 +08:00
/* Carry out need_resched()/cond_resched() forward-progress testing. */
2019-11-06 01:08:58 +08:00
static void rcu_torture_fwd_prog_nr ( struct rcu_fwd * rfp ,
int * tested , int * tested_tries )
2018-07-19 05:32:31 +08:00
{
rcutorture: Also use GP sequence to judge forward progress
Currently, rcutorture relies solely on the progress of
rcu_torture_writer() to judge grace-period forward progress. In theory,
this is the gold standard of forward progress, but in practice rcutorture
separately detects and reports rcu_torture_writer() stalls. This commit
therefore adds the grace-period sequence number (when provided) to the
judgment of grace-period forward progress, which makes it easier to
distinguish between failure of actual grace periods to progress on the
one hand and downstream forward-progress failures on the other.
For example, given this change, if rcu_torture_writer() stalls,
but rcu_torture_fwd_prog() does not complain, then the grace-period
computation is working, which is a hint that the failure lies in callback
processing, wakeup of the rcu_torture_writer() kthread, or similar.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
2018-07-19 06:39:37 +08:00
unsigned long cver ;
2018-07-25 11:50:40 +08:00
unsigned long dur ;
2018-08-08 07:42:42 +08:00
struct fwd_cb_state fcs ;
rcutorture: Also use GP sequence to judge forward progress
Currently, rcutorture relies solely on the progress of
rcu_torture_writer() to judge grace-period forward progress. In theory,
this is the gold standard of forward progress, but in practice rcutorture
separately detects and reports rcu_torture_writer() stalls. This commit
therefore adds the grace-period sequence number (when provided) to the
judgment of grace-period forward progress, which makes it easier to
distinguish between failure of actual grace periods to progress on the
one hand and downstream forward-progress failures on the other.
For example, given this change, if rcu_torture_writer() stalls,
but rcu_torture_fwd_prog() does not complain, then the grace-period
computation is working, which is a hint that the failure lies in callback
processing, wakeup of the rcu_torture_writer() kthread, or similar.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
2018-07-19 06:39:37 +08:00
unsigned long gps ;
2018-07-19 05:32:31 +08:00
int idx ;
2018-08-29 05:38:43 +08:00
int sd ;
int sd4 ;
bool selfpropcb = false ;
unsigned long stopat ;
static DEFINE_TORTURE_RANDOM ( trs ) ;
2021-12-17 07:36:02 +08:00
pr_alert ( " %s: Starting forward-progress test %d \n " , __func__ , rfp - > rcu_fwd_id ) ;
2020-10-10 10:51:55 +08:00
if ( ! cur_ops - > sync )
return ; // Cannot do need_resched() forward progress testing without ->sync.
if ( cur_ops - > call & & cur_ops - > cb_barrier ) {
2018-08-29 05:38:43 +08:00
init_rcu_head_on_stack ( & fcs . rh ) ;
selfpropcb = true ;
}
/* Tight loop containing cond_resched(). */
2021-12-18 04:33:53 +08:00
atomic_inc ( & rcu_fwd_cb_nodelay ) ;
2019-04-10 02:06:32 +08:00
cur_ops - > sync ( ) ; /* Later readers see above write. */
2018-08-29 05:38:43 +08:00
if ( selfpropcb ) {
WRITE_ONCE ( fcs . stop , 0 ) ;
cur_ops - > call ( & fcs . rh , rcu_torture_fwd_prog_cb ) ;
}
cver = READ_ONCE ( rcu_torture_current_version ) ;
gps = cur_ops - > get_gp_seq ( ) ;
sd = cur_ops - > stall_dur ( ) + 1 ;
sd4 = ( sd + fwd_progress_div - 1 ) / fwd_progress_div ;
dur = sd4 + torture_random ( & trs ) % ( sd - sd4 ) ;
2019-11-06 01:08:58 +08:00
WRITE_ONCE ( rfp - > rcu_fwd_startat , jiffies ) ;
stopat = rfp - > rcu_fwd_startat + dur ;
2018-10-02 08:40:54 +08:00
while ( time_before ( jiffies , stopat ) & &
2019-07-10 23:30:00 +08:00
! shutdown_time_arrived ( ) & &
2018-10-02 08:40:54 +08:00
! READ_ONCE ( rcu_fwd_emergency_stop ) & & ! torture_must_stop ( ) ) {
2018-08-29 05:38:43 +08:00
idx = cur_ops - > readlock ( ) ;
udelay ( 10 ) ;
cur_ops - > readunlock ( idx ) ;
if ( ! fwd_progress_need_resched | | need_resched ( ) )
2019-08-16 02:43:53 +08:00
cond_resched ( ) ;
2018-08-29 05:38:43 +08:00
}
( * tested_tries ) + + ;
2018-10-02 08:40:54 +08:00
if ( ! time_before ( jiffies , stopat ) & &
2019-07-10 23:30:00 +08:00
! shutdown_time_arrived ( ) & &
2018-10-02 08:40:54 +08:00
! READ_ONCE ( rcu_fwd_emergency_stop ) & & ! torture_must_stop ( ) ) {
2018-08-29 05:38:43 +08:00
( * tested ) + + ;
cver = READ_ONCE ( rcu_torture_current_version ) - cver ;
gps = rcutorture_seq_diff ( cur_ops - > get_gp_seq ( ) , gps ) ;
WARN_ON ( ! cver & & gps < 2 ) ;
2021-11-23 12:55:18 +08:00
pr_alert ( " %s: %d Duration %ld cver %ld gps %ld \n " , __func__ ,
rfp - > rcu_fwd_id , dur , cver , gps ) ;
2018-08-29 05:38:43 +08:00
}
if ( selfpropcb ) {
WRITE_ONCE ( fcs . stop , 1 ) ;
cur_ops - > sync ( ) ; /* Wait for running CB to complete. */
2021-12-17 07:36:02 +08:00
pr_alert ( " %s: Waiting for CBs: %pS() %d \n " , __func__ , cur_ops - > cb_barrier , rfp - > rcu_fwd_id ) ;
2018-08-29 05:38:43 +08:00
cur_ops - > cb_barrier ( ) ; /* Wait for queued callbacks. */
}
if ( selfpropcb ) {
WARN_ON ( READ_ONCE ( fcs . stop ) ! = 2 ) ;
destroy_rcu_head_on_stack ( & fcs . rh ) ;
}
2019-04-10 02:06:32 +08:00
schedule_timeout_uninterruptible ( HZ / 10 ) ; /* Let kthreads recover. */
2021-12-18 04:33:53 +08:00
atomic_dec ( & rcu_fwd_cb_nodelay ) ;
2018-08-29 05:38:43 +08:00
}
/* Carry out call_rcu() forward-progress testing. */
2019-11-06 01:08:58 +08:00
static void rcu_torture_fwd_prog_cr ( struct rcu_fwd * rfp )
2018-08-29 05:38:43 +08:00
{
unsigned long cver ;
2019-08-05 04:17:35 +08:00
unsigned long flags ;
2018-08-29 05:38:43 +08:00
unsigned long gps ;
int i ;
2018-08-16 06:32:51 +08:00
long n_launders ;
long n_launders_cb_snap ;
long n_launders_sa ;
long n_max_cbs ;
long n_max_gps ;
struct rcu_fwd_cb * rfcp ;
struct rcu_fwd_cb * rfcpn ;
2018-07-19 05:32:31 +08:00
unsigned long stopat ;
2018-08-16 06:32:51 +08:00
unsigned long stoppedat ;
2018-08-29 05:38:43 +08:00
2021-12-17 07:36:02 +08:00
pr_alert ( " %s: Starting forward-progress test %d \n " , __func__ , rfp - > rcu_fwd_id ) ;
2018-10-06 00:09:49 +08:00
if ( READ_ONCE ( rcu_fwd_emergency_stop ) )
return ; /* Get out of the way quickly, no GP wait! */
rcutorture: Add trivial RCU implementation
I have been showing off a trivial RCU implementation for non-preemptive
environments for some time now:
#define rcu_read_lock()
#define rcu_read_unlock()
#define rcu_dereference(p) READ_ONCE(p)
#define rcu_assign_pointer(p, v) smp_store_release(&(p), (v))
void synchronize_rcu(void)
{
int cpu;
for_each_online_cpu(cpu)
sched_setaffinity(current->pid, cpumask_of(cpu));
}
Trivial or not, as the old saying goes, "if it ain't tested, it don't
work!". This commit therefore adds a "trivial" flavor to rcutorture
and a corresponding TRIVIAL test scenario. This variant does not handle
CPU hotplug, which is unconditionally enabled on x86 for post-v5.1-rc3
kernels, which is why the TRIVIAL.boot says "rcutorture.onoff_interval=0".
This commit actually does handle CONFIG_PREEMPT=y kernels, but only
because it turns back the Linux-kernel clock in order to provide these
alternative definitions (or the moral equivalent thereof):
#define rcu_read_lock() preempt_disable()
#define rcu_read_unlock() preempt_enable()
In CONFIG_PREEMPT=n kernels without debugging, these are equivalent to
empty macros give or take a compiler barrier. However, the have been
successfully tested with actual empty macros as well.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
[ paulmck: Fix symbol issue reported by kbuild test robot <lkp@intel.com>. ]
[ paulmck: Work around sched_setaffinity() issue noted by Andrea Parri. ]
[ paulmck: Add rcutorture.shuffle_interval=0 to TRIVIAL.boot to fix
interaction with shuffler task noted by Peter Zijlstra. ]
Tested-by: Andrea Parri <andrea.parri@amarulasolutions.com>
2019-04-19 22:38:27 +08:00
if ( ! cur_ops - > call )
return ; /* Can't do call_rcu() fwd prog without ->call. */
2018-10-06 00:09:49 +08:00
2018-08-29 05:38:43 +08:00
/* Loop continuously posting RCU callbacks. */
2021-12-18 04:33:53 +08:00
atomic_inc ( & rcu_fwd_cb_nodelay ) ;
2018-08-29 05:38:43 +08:00
cur_ops - > sync ( ) ; /* Later readers see above write. */
2019-11-06 01:08:58 +08:00
WRITE_ONCE ( rfp - > rcu_fwd_startat , jiffies ) ;
stopat = rfp - > rcu_fwd_startat + MAX_FWD_CB_JIFFIES ;
2018-08-29 05:38:43 +08:00
n_launders = 0 ;
2019-11-06 01:08:58 +08:00
rfp - > n_launders_cb = 0 ; // Hoist initialization for multi-kthread
2018-08-29 05:38:43 +08:00
n_launders_sa = 0 ;
n_max_cbs = 0 ;
n_max_gps = 0 ;
2019-11-06 01:08:58 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( rfp - > n_launders_hist ) ; i + + )
rfp - > n_launders_hist [ i ] . n_launders = 0 ;
2018-08-29 05:38:43 +08:00
cver = READ_ONCE ( rcu_torture_current_version ) ;
gps = cur_ops - > get_gp_seq ( ) ;
2019-11-06 01:08:58 +08:00
rfp - > rcu_launder_gp_seq_start = gps ;
2019-07-29 03:00:48 +08:00
tick_dep_set_task ( current , TICK_DEP_BIT_RCU ) ;
2018-10-02 08:40:54 +08:00
while ( time_before ( jiffies , stopat ) & &
2019-07-10 23:30:00 +08:00
! shutdown_time_arrived ( ) & &
2018-10-02 08:40:54 +08:00
! READ_ONCE ( rcu_fwd_emergency_stop ) & & ! torture_must_stop ( ) ) {
2019-11-06 01:08:58 +08:00
rfcp = READ_ONCE ( rfp - > rcu_fwd_cb_head ) ;
2018-08-29 05:38:43 +08:00
rfcpn = NULL ;
if ( rfcp )
rfcpn = READ_ONCE ( rfcp - > rfc_next ) ;
if ( rfcpn ) {
if ( rfcp - > rfc_gps > = MIN_FWD_CB_LAUNDERS & &
+ + n_max_gps > = MIN_FWD_CBS_LAUNDERED )
break ;
2019-11-06 01:08:58 +08:00
rfp - > rcu_fwd_cb_head = rfcpn ;
2018-08-29 05:38:43 +08:00
n_launders + + ;
n_launders_sa + + ;
2021-11-24 03:53:52 +08:00
} else if ( ! cur_ops - > cbflood_max | | cur_ops - > cbflood_max > n_max_cbs ) {
2018-08-29 05:38:43 +08:00
rfcp = kmalloc ( sizeof ( * rfcp ) , GFP_KERNEL ) ;
if ( WARN_ON_ONCE ( ! rfcp ) ) {
schedule_timeout_interruptible ( 1 ) ;
continue ;
}
n_max_cbs + + ;
n_launders_sa = 0 ;
rfcp - > rfc_gps = 0 ;
2019-11-06 01:08:58 +08:00
rfcp - > rfc_rfp = rfp ;
2021-11-24 03:53:52 +08:00
} else {
rfcp = NULL ;
2018-08-29 05:38:43 +08:00
}
2021-11-24 03:53:52 +08:00
if ( rfcp )
cur_ops - > call ( & rfcp - > rh , rcu_torture_fwd_cb_cr ) ;
2019-06-23 05:35:59 +08:00
rcu_torture_fwd_prog_cond_resched ( n_launders + n_max_cbs ) ;
2019-08-05 04:17:35 +08:00
if ( tick_nohz_full_enabled ( ) ) {
local_irq_save ( flags ) ;
rcu_momentary_dyntick_idle ( ) ;
local_irq_restore ( flags ) ;
}
2018-08-29 05:38:43 +08:00
}
stoppedat = jiffies ;
2019-11-06 01:08:58 +08:00
n_launders_cb_snap = READ_ONCE ( rfp - > n_launders_cb ) ;
2018-08-29 05:38:43 +08:00
cver = READ_ONCE ( rcu_torture_current_version ) - cver ;
gps = rcutorture_seq_diff ( cur_ops - > get_gp_seq ( ) , gps ) ;
2021-12-17 07:36:02 +08:00
pr_alert ( " %s: Waiting for CBs: %pS() %d \n " , __func__ , cur_ops - > cb_barrier , rfp - > rcu_fwd_id ) ;
2018-08-29 05:38:43 +08:00
cur_ops - > cb_barrier ( ) ; /* Wait for callbacks to be invoked. */
2019-11-07 00:20:20 +08:00
( void ) rcu_torture_fwd_prog_cbfree ( rfp ) ;
2018-10-06 00:09:49 +08:00
2019-07-10 23:30:00 +08:00
if ( ! torture_must_stop ( ) & & ! READ_ONCE ( rcu_fwd_emergency_stop ) & &
! shutdown_time_arrived ( ) ) {
2018-08-29 05:38:43 +08:00
WARN_ON ( n_max_gps < MIN_FWD_CBS_LAUNDERED ) ;
pr_alert ( " %s Duration %lu barrier: %lu pending %ld n_launders: %ld n_launders_sa: %ld n_max_gps: %ld n_max_cbs: %ld cver %ld gps %ld \n " ,
__func__ ,
2019-11-06 01:08:58 +08:00
stoppedat - rfp - > rcu_fwd_startat , jiffies - stoppedat ,
2018-08-29 05:38:43 +08:00
n_launders + n_max_cbs - n_launders_cb_snap ,
n_launders , n_launders_sa ,
n_max_gps , n_max_cbs , cver , gps ) ;
2021-11-24 05:51:11 +08:00
atomic_long_add ( n_max_cbs , & rcu_fwd_max_cbs ) ;
2021-12-29 07:59:38 +08:00
mutex_lock ( & rcu_fwd_mutex ) ; // Serialize histograms.
2019-11-06 01:08:58 +08:00
rcu_torture_fwd_cb_hist ( rfp ) ;
2021-12-29 07:59:38 +08:00
mutex_unlock ( & rcu_fwd_mutex ) ;
2018-08-29 05:38:43 +08:00
}
2019-04-10 02:06:32 +08:00
schedule_timeout_uninterruptible ( HZ ) ; /* Let CBs drain. */
2019-07-29 03:00:48 +08:00
tick_dep_clear_task ( current , TICK_DEP_BIT_RCU ) ;
2021-12-18 04:33:53 +08:00
atomic_dec ( & rcu_fwd_cb_nodelay ) ;
2018-08-29 05:38:43 +08:00
}
2018-10-02 08:40:54 +08:00
/*
* OOM notifier , but this only prints diagnostic information for the
* current forward - progress test .
*/
static int rcutorture_oom_notify ( struct notifier_block * self ,
unsigned long notused , void * nfreed )
{
2021-11-23 12:55:18 +08:00
int i ;
long ncbs ;
2020-07-20 23:34:07 +08:00
struct rcu_fwd * rfp ;
2019-11-07 00:20:20 +08:00
2020-07-20 23:34:07 +08:00
mutex_lock ( & rcu_fwd_mutex ) ;
rfp = rcu_fwds ;
if ( ! rfp ) {
mutex_unlock ( & rcu_fwd_mutex ) ;
return NOTIFY_OK ;
}
2018-10-06 00:09:49 +08:00
WARN ( 1 , " %s invoked upon OOM during forward-progress testing. \n " ,
__func__ ) ;
2021-11-23 12:55:18 +08:00
for ( i = 0 ; i < fwd_progress ; i + + ) {
rcu_torture_fwd_cb_hist ( & rfp [ i ] ) ;
rcu_fwd_progress_check ( 1 + ( jiffies - READ_ONCE ( rfp [ i ] . rcu_fwd_startat ) ) / 2 ) ;
}
2018-10-02 08:40:54 +08:00
WRITE_ONCE ( rcu_fwd_emergency_stop , true ) ;
2018-10-06 00:09:49 +08:00
smp_mb ( ) ; /* Emergency stop before free and wait to avoid hangs. */
2021-11-23 12:55:18 +08:00
ncbs = 0 ;
for ( i = 0 ; i < fwd_progress ; i + + )
ncbs + = rcu_torture_fwd_prog_cbfree ( & rfp [ i ] ) ;
pr_info ( " %s: Freed %lu RCU callbacks. \n " , __func__ , ncbs ) ;
2022-07-31 18:53:56 +08:00
cur_ops - > cb_barrier ( ) ;
2021-11-23 12:55:18 +08:00
ncbs = 0 ;
for ( i = 0 ; i < fwd_progress ; i + + )
ncbs + = rcu_torture_fwd_prog_cbfree ( & rfp [ i ] ) ;
pr_info ( " %s: Freed %lu RCU callbacks. \n " , __func__ , ncbs ) ;
2022-07-31 18:53:56 +08:00
cur_ops - > cb_barrier ( ) ;
2021-11-23 12:55:18 +08:00
ncbs = 0 ;
for ( i = 0 ; i < fwd_progress ; i + + )
ncbs + = rcu_torture_fwd_prog_cbfree ( & rfp [ i ] ) ;
pr_info ( " %s: Freed %lu RCU callbacks. \n " , __func__ , ncbs ) ;
2018-10-06 00:09:49 +08:00
smp_mb ( ) ; /* Frees before return to avoid redoing OOM. */
( * ( unsigned long * ) nfreed ) + + ; /* Forward progress CBs freed! */
pr_info ( " %s returning after OOM processing. \n " , __func__ ) ;
2020-07-20 23:34:07 +08:00
mutex_unlock ( & rcu_fwd_mutex ) ;
2018-10-02 08:40:54 +08:00
return NOTIFY_OK ;
}
static struct notifier_block rcutorture_oom_nb = {
. notifier_call = rcutorture_oom_notify
} ;
2018-08-29 05:38:43 +08:00
/* Carry out grace-period forward-progress testing. */
static int rcu_torture_fwd_prog ( void * args )
{
2021-11-24 05:51:11 +08:00
bool firsttime = true ;
long max_cbs ;
2020-09-23 07:42:42 +08:00
int oldnice = task_nice ( current ) ;
2021-11-23 12:55:18 +08:00
unsigned long oldseq = READ_ONCE ( rcu_fwd_seq ) ;
2019-11-06 01:08:58 +08:00
struct rcu_fwd * rfp = args ;
2018-07-25 11:50:40 +08:00
int tested = 0 ;
2018-07-20 01:57:58 +08:00
int tested_tries = 0 ;
2018-07-19 05:32:31 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_fwd_progress task started " ) ;
2018-09-22 09:08:09 +08:00
rcu_bind_current_to_nocb ( ) ;
2018-07-21 03:18:11 +08:00
if ( ! IS_ENABLED ( CONFIG_SMP ) | | ! IS_ENABLED ( CONFIG_RCU_BOOST ) )
set_user_nice ( current , MAX_NICE ) ;
2018-07-19 05:32:31 +08:00
do {
2021-11-23 12:55:18 +08:00
if ( ! rfp - > rcu_fwd_id ) {
schedule_timeout_interruptible ( fwd_progress_holdoff * HZ ) ;
WRITE_ONCE ( rcu_fwd_emergency_stop , false ) ;
2021-11-24 05:51:11 +08:00
if ( ! firsttime ) {
max_cbs = atomic_long_xchg ( & rcu_fwd_max_cbs , 0 ) ;
pr_alert ( " %s n_max_cbs: %ld \n " , __func__ , max_cbs ) ;
}
firsttime = false ;
2021-11-23 12:55:18 +08:00
WRITE_ONCE ( rcu_fwd_seq , rcu_fwd_seq + 1 ) ;
} else {
2021-12-18 07:05:05 +08:00
while ( READ_ONCE ( rcu_fwd_seq ) = = oldseq & & ! torture_must_stop ( ) )
2021-11-23 12:55:18 +08:00
schedule_timeout_interruptible ( 1 ) ;
oldseq = READ_ONCE ( rcu_fwd_seq ) ;
}
pr_alert ( " %s: Starting forward-progress test %d \n " , __func__ , rfp - > rcu_fwd_id ) ;
if ( rcu_inkernel_boot_has_ended ( ) & & torture_num_online_cpus ( ) > rfp - > rcu_fwd_id )
rcu_torture_fwd_prog_cr ( rfp ) ;
2021-11-24 03:53:52 +08:00
if ( ( cur_ops - > stall_dur & & cur_ops - > stall_dur ( ) > 0 ) & &
( ! IS_ENABLED ( CONFIG_TINY_RCU ) | |
( rcu_inkernel_boot_has_ended ( ) & &
torture_num_online_cpus ( ) > rfp - > rcu_fwd_id ) ) )
2019-12-05 07:58:41 +08:00
rcu_torture_fwd_prog_nr ( rfp , & tested , & tested_tries ) ;
2018-08-16 06:32:51 +08:00
2018-07-19 05:32:31 +08:00
/* Avoid slow periods, better to test when busy. */
2020-09-23 07:42:42 +08:00
if ( stutter_wait ( " rcu_torture_fwd_prog " ) )
sched_set_normal ( current , oldnice ) ;
2018-07-19 05:32:31 +08:00
} while ( ! torture_must_stop ( ) ) ;
2018-07-20 01:57:58 +08:00
/* Short runs might not contain a valid forward-progress attempt. */
2021-11-23 12:55:18 +08:00
if ( ! rfp - > rcu_fwd_id ) {
WARN_ON ( ! tested & & tested_tries > = 5 ) ;
pr_alert ( " %s: tested %d tested_tries %d \n " , __func__ , tested , tested_tries ) ;
}
2018-07-19 05:32:31 +08:00
torture_kthread_stopping ( " rcu_torture_fwd_prog " ) ;
return 0 ;
}
/* If forward-progress checking is requested and feasible, spawn the thread. */
static int __init rcu_torture_fwd_prog_init ( void )
{
2021-11-23 12:55:18 +08:00
int i ;
int ret = 0 ;
2019-11-07 00:35:08 +08:00
struct rcu_fwd * rfp ;
2019-11-07 00:20:20 +08:00
2018-07-19 05:32:31 +08:00
if ( ! fwd_progress )
return 0 ; /* Not requested, so don't do it. */
2021-11-23 12:55:18 +08:00
if ( fwd_progress > = nr_cpu_ids ) {
VERBOSE_TOROUT_STRING ( " rcu_torture_fwd_prog_init: Limiting fwd_progress to # CPUs. \n " ) ;
fwd_progress = nr_cpu_ids ;
} else if ( fwd_progress < 0 ) {
fwd_progress = nr_cpu_ids ;
}
2020-10-10 10:51:55 +08:00
if ( ( ! cur_ops - > sync & & ! cur_ops - > call ) | |
2021-11-24 03:53:52 +08:00
( ! cur_ops - > cbflood_max & & ( ! cur_ops - > stall_dur | | cur_ops - > stall_dur ( ) < = 0 ) ) | |
cur_ops = = & rcu_busted_ops ) {
2018-07-19 05:32:31 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_fwd_prog_init: Disabled, unsupported by RCU flavor under test " ) ;
2021-11-23 12:55:18 +08:00
fwd_progress = 0 ;
2018-07-19 05:32:31 +08:00
return 0 ;
}
if ( stall_cpu > 0 ) {
VERBOSE_TOROUT_STRING ( " rcu_torture_fwd_prog_init: Disabled, conflicts with CPU-stall testing " ) ;
2021-11-23 12:55:18 +08:00
fwd_progress = 0 ;
2021-07-26 05:43:33 +08:00
if ( IS_MODULE ( CONFIG_RCU_TORTURE_TEST ) )
2018-07-19 05:32:31 +08:00
return - EINVAL ; /* In module, can fail back to user. */
WARN_ON ( 1 ) ; /* Make sure rcutorture notices conflict. */
return 0 ;
}
if ( fwd_progress_holdoff < = 0 )
fwd_progress_holdoff = 1 ;
if ( fwd_progress_div < = 0 )
fwd_progress_div = 4 ;
2021-11-23 12:55:18 +08:00
rfp = kcalloc ( fwd_progress , sizeof ( * rfp ) , GFP_KERNEL ) ;
fwd_prog_tasks = kcalloc ( fwd_progress , sizeof ( * fwd_prog_tasks ) , GFP_KERNEL ) ;
if ( ! rfp | | ! fwd_prog_tasks ) {
kfree ( rfp ) ;
kfree ( fwd_prog_tasks ) ;
fwd_prog_tasks = NULL ;
fwd_progress = 0 ;
2019-11-07 00:35:08 +08:00
return - ENOMEM ;
2021-11-23 12:55:18 +08:00
}
for ( i = 0 ; i < fwd_progress ; i + + ) {
spin_lock_init ( & rfp [ i ] . rcu_fwd_lock ) ;
rfp [ i ] . rcu_fwd_cb_tail = & rfp [ i ] . rcu_fwd_cb_head ;
rfp [ i ] . rcu_fwd_id = i ;
}
2020-07-20 23:34:07 +08:00
mutex_lock ( & rcu_fwd_mutex ) ;
2020-07-20 05:40:31 +08:00
rcu_fwds = rfp ;
2020-07-20 23:34:07 +08:00
mutex_unlock ( & rcu_fwd_mutex ) ;
2020-07-23 01:45:12 +08:00
register_oom_notifier ( & rcutorture_oom_nb ) ;
2021-11-23 12:55:18 +08:00
for ( i = 0 ; i < fwd_progress ; i + + ) {
ret = torture_create_kthread ( rcu_torture_fwd_prog , & rcu_fwds [ i ] , fwd_prog_tasks [ i ] ) ;
if ( ret ) {
fwd_progress = i ;
return ret ;
}
}
return 0 ;
2018-07-19 05:32:31 +08:00
}
2020-07-20 05:40:31 +08:00
static void rcu_torture_fwd_prog_cleanup ( void )
{
2021-11-23 12:55:18 +08:00
int i ;
2020-07-20 05:40:31 +08:00
struct rcu_fwd * rfp ;
2021-11-23 12:55:18 +08:00
if ( ! rcu_fwds | | ! fwd_prog_tasks )
return ;
for ( i = 0 ; i < fwd_progress ; i + + )
torture_stop_kthread ( rcu_torture_fwd_prog , fwd_prog_tasks [ i ] ) ;
unregister_oom_notifier ( & rcutorture_oom_nb ) ;
2020-07-20 23:34:07 +08:00
mutex_lock ( & rcu_fwd_mutex ) ;
2021-11-23 12:55:18 +08:00
rfp = rcu_fwds ;
2020-07-20 05:40:31 +08:00
rcu_fwds = NULL ;
2020-07-20 23:34:07 +08:00
mutex_unlock ( & rcu_fwd_mutex ) ;
2020-07-20 05:40:31 +08:00
kfree ( rfp ) ;
2021-11-23 12:55:18 +08:00
kfree ( fwd_prog_tasks ) ;
fwd_prog_tasks = NULL ;
2020-07-20 05:40:31 +08:00
}
2012-02-21 09:51:45 +08:00
/* Callback function for RCU barrier testing. */
2014-02-27 19:46:57 +08:00
static void rcu_torture_barrier_cbf ( struct rcu_head * rcu )
2012-02-21 09:51:45 +08:00
{
atomic_inc ( & barrier_cbs_invoked ) ;
}
2020-02-05 07:00:56 +08:00
/* IPI handler to get callback posted on desired CPU, if online. */
static void rcu_torture_barrier1cb ( void * rcu_void )
{
struct rcu_head * rhp = rcu_void ;
cur_ops - > call ( rhp , rcu_torture_barrier_cbf ) ;
}
2012-02-21 09:51:45 +08:00
/* kthread function to register callbacks used to test RCU barriers. */
static int rcu_torture_barrier_cbs ( void * arg )
{
long myid = ( long ) arg ;
2020-06-02 02:45:48 +08:00
bool lastphase = false ;
2013-09-25 06:04:06 +08:00
bool newphase ;
2012-02-21 09:51:45 +08:00
struct rcu_head rcu ;
init_rcu_head_on_stack ( & rcu ) ;
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_barrier_cbs task started " ) ;
2014-02-11 15:34:49 +08:00
set_user_nice ( current , MAX_NICE ) ;
2012-02-21 09:51:45 +08:00
do {
wait_event ( barrier_cbs_wq [ myid ] ,
2013-09-25 06:04:06 +08:00
( newphase =
2015-04-14 02:58:08 +08:00
smp_load_acquire ( & barrier_phase ) ) ! = lastphase | |
2014-01-31 07:49:29 +08:00
torture_must_stop ( ) ) ;
2013-09-25 06:04:06 +08:00
lastphase = newphase ;
2014-01-31 07:49:29 +08:00
if ( torture_must_stop ( ) )
2012-02-21 09:51:45 +08:00
break ;
2015-04-14 02:58:08 +08:00
/*
* The above smp_load_acquire ( ) ensures barrier_phase load
2016-05-03 03:20:51 +08:00
* is ordered before the following - > call ( ) .
2015-04-14 02:58:08 +08:00
*/
2020-02-05 07:00:56 +08:00
if ( smp_call_function_single ( myid , rcu_torture_barrier1cb ,
& rcu , 1 ) ) {
// IPI failed, so use direct call from current CPU.
cur_ops - > call ( & rcu , rcu_torture_barrier_cbf ) ;
}
2012-02-21 09:51:45 +08:00
if ( atomic_dec_and_test ( & barrier_cbs_count ) )
wake_up ( & barrier_wq ) ;
2014-01-31 07:49:29 +08:00
} while ( ! torture_must_stop ( ) ) ;
2014-07-02 02:59:36 +08:00
if ( cur_ops - > cb_barrier ! = NULL )
cur_ops - > cb_barrier ( ) ;
2012-02-21 09:51:45 +08:00
destroy_rcu_head_on_stack ( & rcu ) ;
2014-02-01 09:37:28 +08:00
torture_kthread_stopping ( " rcu_torture_barrier_cbs " ) ;
2012-02-21 09:51:45 +08:00
return 0 ;
}
/* kthread function to drive and coordinate RCU barrier testing. */
static int rcu_torture_barrier ( void * arg )
{
int i ;
2014-01-29 23:25:25 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_barrier task starting " ) ;
2012-02-21 09:51:45 +08:00
do {
atomic_set ( & barrier_cbs_invoked , 0 ) ;
atomic_set ( & barrier_cbs_count , n_barrier_cbs ) ;
2015-04-14 02:58:08 +08:00
/* Ensure barrier_phase ordered after prior assignments. */
smp_store_release ( & barrier_phase , ! barrier_phase ) ;
2012-02-21 09:51:45 +08:00
for ( i = 0 ; i < n_barrier_cbs ; i + + )
wake_up ( & barrier_cbs_wq [ i ] ) ;
wait_event ( barrier_wq ,
atomic_read ( & barrier_cbs_count ) = = 0 | |
2014-01-31 07:49:29 +08:00
torture_must_stop ( ) ) ;
if ( torture_must_stop ( ) )
2012-02-21 09:51:45 +08:00
break ;
n_barrier_attempts + + ;
2013-09-25 06:04:06 +08:00
cur_ops - > cb_barrier ( ) ; /* Implies smp_mb() for wait_event(). */
2012-02-21 09:51:45 +08:00
if ( atomic_read ( & barrier_cbs_invoked ) ! = n_barrier_cbs ) {
n_rcu_torture_barrier_error + + ;
2014-12-18 10:39:54 +08:00
pr_err ( " barrier_cbs_invoked = %d, n_barrier_cbs = %d \n " ,
atomic_read ( & barrier_cbs_invoked ) ,
n_barrier_cbs ) ;
2020-02-06 04:54:34 +08:00
WARN_ON ( 1 ) ;
// Wait manually for the remaining callbacks
i = 0 ;
do {
if ( WARN_ON ( i + + > HZ ) )
i = INT_MIN ;
schedule_timeout_interruptible ( 1 ) ;
cur_ops - > cb_barrier ( ) ;
} while ( atomic_read ( & barrier_cbs_invoked ) ! =
n_barrier_cbs & &
! torture_must_stop ( ) ) ;
smp_mb ( ) ; // Can't trust ordering if broken.
if ( ! torture_must_stop ( ) )
pr_err ( " Recovered: barrier_cbs_invoked = %d \n " ,
atomic_read ( & barrier_cbs_invoked ) ) ;
2018-06-20 06:14:19 +08:00
} else {
n_barrier_successes + + ;
2012-02-21 09:51:45 +08:00
}
schedule_timeout_interruptible ( HZ / 10 ) ;
2014-01-31 07:49:29 +08:00
} while ( ! torture_must_stop ( ) ) ;
2014-02-01 09:37:28 +08:00
torture_kthread_stopping ( " rcu_torture_barrier " ) ;
2012-02-21 09:51:45 +08:00
return 0 ;
}
/* Initialize RCU barrier testing. */
static int rcu_torture_barrier_init ( void )
{
int i ;
int ret ;
2015-05-15 06:35:43 +08:00
if ( n_barrier_cbs < = 0 )
2012-02-21 09:51:45 +08:00
return 0 ;
if ( cur_ops - > call = = NULL | | cur_ops - > cb_barrier = = NULL ) {
2012-08-10 07:30:45 +08:00
pr_alert ( " %s " TORTURE_FLAG
" Call or barrier ops missing for %s, \n " ,
torture_type , cur_ops - > name ) ;
pr_alert ( " %s " TORTURE_FLAG
" RCU barrier testing omitted from run. \n " ,
torture_type ) ;
2012-02-21 09:51:45 +08:00
return 0 ;
}
atomic_set ( & barrier_cbs_count , 0 ) ;
atomic_set ( & barrier_cbs_invoked , 0 ) ;
barrier_cbs_tasks =
2017-12-02 06:26:56 +08:00
kcalloc ( n_barrier_cbs , sizeof ( barrier_cbs_tasks [ 0 ] ) ,
2012-02-21 09:51:45 +08:00
GFP_KERNEL ) ;
barrier_cbs_wq =
2017-12-02 06:26:56 +08:00
kcalloc ( n_barrier_cbs , sizeof ( barrier_cbs_wq [ 0 ] ) , GFP_KERNEL ) ;
2012-12-21 03:11:28 +08:00
if ( barrier_cbs_tasks = = NULL | | ! barrier_cbs_wq )
2012-02-21 09:51:45 +08:00
return - ENOMEM ;
for ( i = 0 ; i < n_barrier_cbs ; i + + ) {
init_waitqueue_head ( & barrier_cbs_wq [ i ] ) ;
2014-02-04 03:52:27 +08:00
ret = torture_create_kthread ( rcu_torture_barrier_cbs ,
( void * ) ( long ) i ,
barrier_cbs_tasks [ i ] ) ;
if ( ret )
2012-02-21 09:51:45 +08:00
return ret ;
}
2014-02-04 03:52:27 +08:00
return torture_create_kthread ( rcu_torture_barrier , NULL , barrier_task ) ;
2012-02-21 09:51:45 +08:00
}
/* Clean up after RCU barrier testing. */
static void rcu_torture_barrier_cleanup ( void )
{
int i ;
2014-02-05 03:47:08 +08:00
torture_stop_kthread ( rcu_torture_barrier , barrier_task ) ;
2012-02-21 09:51:45 +08:00
if ( barrier_cbs_tasks ! = NULL ) {
2014-02-05 03:47:08 +08:00
for ( i = 0 ; i < n_barrier_cbs ; i + + )
torture_stop_kthread ( rcu_torture_barrier_cbs ,
barrier_cbs_tasks [ i ] ) ;
2012-02-21 09:51:45 +08:00
kfree ( barrier_cbs_tasks ) ;
barrier_cbs_tasks = NULL ;
}
if ( barrier_cbs_wq ! = NULL ) {
kfree ( barrier_cbs_wq ) ;
barrier_cbs_wq = NULL ;
}
}
2018-06-20 06:14:18 +08:00
static bool rcu_torture_can_boost ( void )
{
static int boost_warn_once ;
int prio ;
if ( ! ( test_boost = = 1 & & cur_ops - > can_boost ) & & test_boost ! = 2 )
return false ;
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
if ( ! cur_ops - > start_gp_poll | | ! cur_ops - > poll_gp_state )
2021-01-16 05:30:38 +08:00
return false ;
2018-06-20 06:14:18 +08:00
prio = rcu_get_gp_kthreads_prio ( ) ;
if ( ! prio )
return false ;
if ( prio < 2 ) {
rcutorture: Judge RCU priority boosting on grace periods, not callbacks
Currently, rcutorture's testing of RCU priority boosting insists not
only that grace periods complete, but also that callbacks be invoked.
Although this is in fact what the user would want, ensuring that there
is sufficient CPU bandwidth devoted to callback execution is in fact
the user's responsibility. One could argue that rcutorture can take on
that responsibility, which is true in theory. But in practice, ensuring
sufficient CPU bandwidth to ksoftirqd, any rcuc kthreads, and any rcuo
kthreads is not particularly consistent with rcutorture's main job,
that of stress-testing RCU. In addition, if the system administrator
(say) makes very poor choices when pinning rcuo kthreads and then runs
rcutorture, there really isn't much rcutorture can do.
Besides, RCU priority boosting only boosts lagging readers, not all the
machinery required to invoke callbacks in a timely fashion.
This commit therefore switches rcutorture's evaluation of RCU priority
boosting from callback execution to grace-period completion by using
the new start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
functions. When rcutorture is built in (as in when there is no innocent
workload to inconvenience), the ksoftirqd ktheads are boosted to real-time
priority 2 in order to allow timeouts to work properly in the face of
rcutorture's testing of RCU priority boosting.
Indeed, it is not as easy as it looks to create a reliable test of RCU
priority boosting without destroying the rest of the kernel!
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-03-31 07:30:32 +08:00
if ( boost_warn_once = = 1 )
2018-06-20 06:14:18 +08:00
return false ;
2018-06-20 06:14:19 +08:00
pr_alert ( " %s: WARN: RCU kthread priority too low to test boosting. Skipping RCU boost test. Try passing rcutree.kthread_prio > 1 on the kernel command line. \n " , KBUILD_MODNAME ) ;
2018-06-20 06:14:18 +08:00
boost_warn_once = 1 ;
return false ;
}
return true ;
}
2020-04-25 02:21:40 +08:00
static bool read_exit_child_stop ;
static bool read_exit_child_stopped ;
static wait_queue_head_t read_exit_wq ;
// Child kthread which just does an rcutorture reader and exits.
static int rcu_torture_read_exit_child ( void * trsp_in )
{
struct torture_random_state * trsp = trsp_in ;
set_user_nice ( current , MAX_NICE ) ;
// Minimize time between reading and exiting.
while ( ! kthread_should_stop ( ) )
schedule_timeout_uninterruptible ( 1 ) ;
2020-10-30 06:08:57 +08:00
( void ) rcu_torture_one_read ( trsp , - 1 ) ;
2020-04-25 02:21:40 +08:00
return 0 ;
}
// Parent kthread which creates and destroys read-exit child kthreads.
static int rcu_torture_read_exit ( void * unused )
{
bool errexit = false ;
int i ;
struct task_struct * tsp ;
DEFINE_TORTURE_RANDOM ( trs ) ;
// Allocate and initialize.
set_user_nice ( current , MAX_NICE ) ;
VERBOSE_TOROUT_STRING ( " rcu_torture_read_exit: Start of test " ) ;
// Each pass through this loop does one read-exit episode.
do {
2022-04-28 02:46:02 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_read_exit: Start of episode " ) ;
for ( i = 0 ; i < read_exit_burst ; i + + ) {
if ( READ_ONCE ( read_exit_child_stop ) )
break ;
stutter_wait ( " rcu_torture_read_exit " ) ;
// Spawn child.
tsp = kthread_run ( rcu_torture_read_exit_child ,
& trs , " %s " , " rcu_torture_read_exit_child " ) ;
if ( IS_ERR ( tsp ) ) {
TOROUT_ERRSTRING ( " out of memory " ) ;
errexit = true ;
break ;
2020-04-25 02:21:40 +08:00
}
2022-04-28 02:46:02 +08:00
cond_resched ( ) ;
kthread_stop ( tsp ) ;
n_read_exits + + ;
2020-04-25 02:21:40 +08:00
}
2022-04-28 02:46:02 +08:00
VERBOSE_TOROUT_STRING ( " rcu_torture_read_exit: End of episode " ) ;
rcu_barrier ( ) ; // Wait for task_struct free, avoid OOM.
i = 0 ;
for ( ; ! errexit & & ! READ_ONCE ( read_exit_child_stop ) & & i < read_exit_delay ; i + + )
schedule_timeout_uninterruptible ( HZ ) ;
2020-04-25 02:21:40 +08:00
} while ( ! errexit & & ! READ_ONCE ( read_exit_child_stop ) ) ;
// Clean up and exit.
smp_store_release ( & read_exit_child_stopped , true ) ; // After reaping.
smp_mb ( ) ; // Store before wakeup.
wake_up ( & read_exit_wq ) ;
while ( ! torture_must_stop ( ) )
schedule_timeout_uninterruptible ( 1 ) ;
torture_kthread_stopping ( " rcu_torture_read_exit " ) ;
return 0 ;
}
static int rcu_torture_read_exit_init ( void )
{
if ( read_exit_burst < = 0 )
2021-08-04 08:42:25 +08:00
return 0 ;
2020-04-25 02:21:40 +08:00
init_waitqueue_head ( & read_exit_wq ) ;
read_exit_child_stop = false ;
read_exit_child_stopped = false ;
return torture_create_kthread ( rcu_torture_read_exit , NULL ,
read_exit_task ) ;
}
static void rcu_torture_read_exit_cleanup ( void )
{
if ( ! read_exit_task )
return ;
WRITE_ONCE ( read_exit_child_stop , true ) ;
smp_mb ( ) ; // Above write before wait.
wait_event ( read_exit_wq , smp_load_acquire ( & read_exit_child_stopped ) ) ;
torture_stop_kthread ( rcutorture_read_exit , read_exit_task ) ;
}
2022-12-20 03:21:09 +08:00
static void rcutorture_test_nmis ( int n )
{
# if IS_BUILTIN(CONFIG_RCU_TORTURE_TEST)
int cpu ;
int dumpcpu ;
int i ;
for ( i = 0 ; i < n ; i + + ) {
preempt_disable ( ) ;
cpu = smp_processor_id ( ) ;
dumpcpu = cpu + 1 ;
if ( dumpcpu > = nr_cpu_ids )
dumpcpu = 0 ;
pr_alert ( " %s: CPU %d invoking dump_cpu_task(%d) \n " , __func__ , cpu , dumpcpu ) ;
dump_cpu_task ( dumpcpu ) ;
preempt_enable ( ) ;
schedule_timeout_uninterruptible ( 15 * HZ ) ;
}
# else // #if IS_BUILTIN(CONFIG_RCU_TORTURE_TEST)
WARN_ONCE ( n , " Non-zero rcutorture.test_nmis=%d permitted only when rcutorture is built in. \n " , test_nmis ) ;
# endif // #else // #if IS_BUILTIN(CONFIG_RCU_TORTURE_TEST)
}
2016-08-18 20:57:22 +08:00
static enum cpuhp_state rcutor_hp ;
2010-09-03 07:16:14 +08:00
2005-10-31 07:03:12 +08:00
static void
rcu_torture_cleanup ( void )
{
2018-07-14 03:09:14 +08:00
int firsttime ;
2018-04-19 23:43:11 +08:00
int flags = 0 ;
2018-05-01 21:42:51 +08:00
unsigned long gp_seq = 0 ;
2005-10-31 07:03:12 +08:00
int i ;
2014-09-12 11:40:21 +08:00
if ( torture_cleanup_begin ( ) ) {
2021-12-07 07:12:14 +08:00
if ( cur_ops - > cb_barrier ! = NULL ) {
pr_info ( " %s: Invoking %pS(). \n " , __func__ , cur_ops - > cb_barrier ) ;
2008-12-16 08:13:07 +08:00
cur_ops - > cb_barrier ( ) ;
2021-12-07 07:12:14 +08:00
}
2022-02-05 04:45:18 +08:00
rcu_gp_slow_unregister ( NULL ) ;
2008-12-16 08:13:07 +08:00
return ;
}
2019-03-22 00:27:28 +08:00
if ( ! cur_ops ) {
torture_cleanup_end ( ) ;
2022-02-05 04:45:18 +08:00
rcu_gp_slow_unregister ( NULL ) ;
2019-03-22 00:27:28 +08:00
return ;
}
2006-01-08 17:03:42 +08:00
2022-12-20 03:21:09 +08:00
rcutorture_test_nmis ( test_nmis ) ;
2020-09-16 08:08:03 +08:00
if ( cur_ops - > gp_kthread_dbg )
cur_ops - > gp_kthread_dbg ( ) ;
2020-04-25 02:21:40 +08:00
rcu_torture_read_exit_cleanup ( ) ;
2012-02-21 09:51:45 +08:00
rcu_torture_barrier_cleanup ( ) ;
2020-07-20 05:40:31 +08:00
rcu_torture_fwd_prog_cleanup ( ) ;
2014-02-05 03:47:08 +08:00
torture_stop_kthread ( rcu_torture_stall , stall_task ) ;
torture_stop_kthread ( rcu_torture_writer , writer_task ) ;
2005-10-31 07:03:12 +08:00
2020-09-24 08:39:46 +08:00
if ( nocb_tasks ) {
for ( i = 0 ; i < nrealnocbers ; i + + )
torture_stop_kthread ( rcu_nocb_toggle , nocb_tasks [ i ] ) ;
kfree ( nocb_tasks ) ;
nocb_tasks = NULL ;
}
2007-05-08 15:33:20 +08:00
if ( reader_tasks ) {
2014-02-05 03:47:08 +08:00
for ( i = 0 ; i < nrealreaders ; i + + )
torture_stop_kthread ( rcu_torture_reader ,
reader_tasks [ i ] ) ;
2005-10-31 07:03:12 +08:00
kfree ( reader_tasks ) ;
2020-09-24 07:46:36 +08:00
reader_tasks = NULL ;
2005-10-31 07:03:12 +08:00
}
2020-10-30 06:08:57 +08:00
kfree ( rcu_torture_reader_mbchk ) ;
rcu_torture_reader_mbchk = NULL ;
2005-10-31 07:03:12 +08:00
2007-05-08 15:33:20 +08:00
if ( fakewriter_tasks ) {
2020-09-24 07:46:36 +08:00
for ( i = 0 ; i < nfakewriters ; i + + )
2014-02-05 03:47:08 +08:00
torture_stop_kthread ( rcu_torture_fakewriter ,
fakewriter_tasks [ i ] ) ;
2006-10-04 17:17:13 +08:00
kfree ( fakewriter_tasks ) ;
fakewriter_tasks = NULL ;
}
2018-05-01 21:42:51 +08:00
rcutorture_get_gp_data ( cur_ops - > ttype , & flags , & gp_seq ) ;
srcutorture_get_gp_data ( cur_ops - > ttype , srcu_ctlp , & flags , & gp_seq ) ;
2020-06-19 04:29:55 +08:00
pr_alert ( " %s: End-test grace-period state: g%ld f%#x total-gps=%ld \n " ,
cur_ops - > name , ( long ) gp_seq , flags ,
rcutorture_seq_diff ( gp_seq , start_gp_seq ) ) ;
2014-02-05 03:47:08 +08:00
torture_stop_kthread ( rcu_torture_stats , stats_task ) ;
torture_stop_kthread ( rcu_torture_fqs , fqs_task ) ;
2021-08-06 23:57:26 +08:00
if ( rcu_torture_can_boost ( ) & & rcutor_hp > = 0 )
2016-08-18 20:57:22 +08:00
cpuhp_remove_state ( rcutor_hp ) ;
2010-01-05 07:09:10 +08:00
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
/*
2018-07-08 09:12:26 +08:00
* Wait for all RCU callbacks to fire , then do torture - type - specific
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
* cleanup operations .
*/
2021-12-07 07:12:14 +08:00
if ( cur_ops - > cb_barrier ! = NULL ) {
pr_info ( " %s: Invoking %pS(). \n " , __func__ , cur_ops - > cb_barrier ) ;
2008-05-13 03:21:05 +08:00
cur_ops - > cb_barrier ( ) ;
2021-12-07 07:12:14 +08:00
}
rcutorture: Test SRCU cleanup code path
The current rcutorture testing does not do any cleanup operations.
This works because the srcu_struct is statically allocated, but it
does represent a memory leak of the associated dynamically allocated
->per_cpu_ref per-CPU variables. However, rcutorture currently uses
a statically allocated srcu_struct, which cannot legally be passed to
cleanup_srcu_struct(). Therefore, this commit adds a second form
of srcu (called srcud) that dynamically allocates and frees the
associated per-CPU variables. This commit also adds a ->cleanup()
member to rcu_torture_ops that is invoked at the end of the test,
after ->cb_barriers(). This ->cleanup() pointer is NULL for all
existing tests, and thus only used for scrud. Finally, the SRCU-P
torture-test configuration selects scrud instead of srcu, with SRCU-N
continuing to use srcu, thereby testing both static and dynamic
srcu_struct structures.
Reported-by: "Ahmed, Iftekhar" <ahmedi@onid.oregonstate.edu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
2015-04-15 03:28:22 +08:00
if ( cur_ops - > cleanup ! = NULL )
cur_ops - > cleanup ( ) ;
2005-10-31 07:03:12 +08:00
2021-05-03 10:56:05 +08:00
rcu_torture_mem_dump_obj ( ) ;
2005-10-31 07:03:12 +08:00
rcu_torture_stats_print ( ) ; /* -After- the stats thread is stopped! */
2006-06-27 17:54:03 +08:00
2018-07-14 03:09:14 +08:00
if ( err_segs_recorded ) {
pr_alert ( " Failure/close-call rcutorture reader segments: \n " ) ;
if ( rt_read_nsegs = = 0 )
pr_alert ( " \t : No segments recorded!!! \n " ) ;
firsttime = 1 ;
for ( i = 0 ; i < rt_read_nsegs ; i + + ) {
pr_alert ( " \t %d: %#x " , i , err_segs [ i ] . rt_readstate ) ;
if ( err_segs [ i ] . rt_delay_jiffies ! = 0 ) {
pr_cont ( " %s%ldjiffies " , firsttime ? " " : " + " ,
err_segs [ i ] . rt_delay_jiffies ) ;
firsttime = 0 ;
}
if ( err_segs [ i ] . rt_delay_ms ! = 0 ) {
pr_cont ( " %s%ldms " , firsttime ? " " : " + " ,
err_segs [ i ] . rt_delay_ms ) ;
firsttime = 0 ;
}
if ( err_segs [ i ] . rt_delay_us ! = 0 ) {
pr_cont ( " %s%ldus " , firsttime ? " " : " + " ,
err_segs [ i ] . rt_delay_us ) ;
firsttime = 0 ;
}
pr_cont ( " %s \n " ,
err_segs [ i ] . rt_preempted ? " preempted " : " " ) ;
}
}
2012-02-21 09:51:45 +08:00
if ( atomic_read ( & n_rcu_torture_error ) | | n_rcu_torture_barrier_error )
2010-09-03 07:16:14 +08:00
rcu_torture_print_module_parms ( cur_ops , " End of test: FAILURE " ) ;
2014-01-29 07:58:22 +08:00
else if ( torture_onoff_failures ( ) )
2012-01-11 04:51:14 +08:00
rcu_torture_print_module_parms ( cur_ops ,
" End of test: RCU_HOTPLUG " ) ;
2006-03-24 19:15:58 +08:00
else
2010-09-03 07:16:14 +08:00
rcu_torture_print_module_parms ( cur_ops , " End of test: SUCCESS " ) ;
2014-09-12 11:40:21 +08:00
torture_cleanup_end ( ) ;
2022-02-05 04:45:18 +08:00
rcu_gp_slow_unregister ( & rcu_fwd_cb_nodelay ) ;
2005-10-31 07:03:12 +08:00
}
2013-04-24 08:05:42 +08:00
# ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
static void rcu_torture_leak_cb ( struct rcu_head * rhp )
{
}
static void rcu_torture_err_cb ( struct rcu_head * rhp )
{
/*
* This - might - happen due to race conditions , but is unlikely .
* The scenario that leads to this happening is that the
* first of the pair of duplicate callbacks is queued ,
* someone else starts a grace period that includes that
* callback , then the second of the pair must wait for the
* next grace period . Unlikely , but can happen . If it
* does happen , the debug - objects subsystem won ' t have splatted .
*/
2017-12-02 07:22:38 +08:00
pr_alert ( " %s: duplicated callback was invoked. \n " , KBUILD_MODNAME ) ;
2013-04-24 08:05:42 +08:00
}
# endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
/*
* Verify that double - free causes debug - objects to complain , but only
* if CONFIG_DEBUG_OBJECTS_RCU_HEAD = y . Otherwise , say that the test
* cannot be carried out .
*/
static void rcu_test_debug_objects ( void )
{
# ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
struct rcu_head rh1 ;
struct rcu_head rh2 ;
2020-12-03 09:52:07 +08:00
struct rcu_head * rhp = kmalloc ( sizeof ( * rhp ) , GFP_KERNEL ) ;
2013-04-24 08:05:42 +08:00
init_rcu_head_on_stack ( & rh1 ) ;
init_rcu_head_on_stack ( & rh2 ) ;
2017-12-02 07:22:38 +08:00
pr_alert ( " %s: WARN: Duplicate call_rcu() test starting. \n " , KBUILD_MODNAME ) ;
2013-04-24 08:05:42 +08:00
/* Try to queue the rh2 pair of callbacks for the same grace period. */
preempt_disable ( ) ; /* Prevent preemption from interrupting test. */
rcu_read_lock ( ) ; /* Make it impossible to finish a grace period. */
2022-10-17 00:23:01 +08:00
call_rcu_hurry ( & rh1 , rcu_torture_leak_cb ) ; /* Start grace period. */
2013-04-24 08:05:42 +08:00
local_irq_disable ( ) ; /* Make it harder to start a new grace period. */
2022-10-17 00:23:01 +08:00
call_rcu_hurry ( & rh2 , rcu_torture_leak_cb ) ;
call_rcu_hurry ( & rh2 , rcu_torture_err_cb ) ; /* Duplicate callback. */
2020-12-03 09:52:07 +08:00
if ( rhp ) {
2022-10-17 00:23:01 +08:00
call_rcu_hurry ( rhp , rcu_torture_leak_cb ) ;
call_rcu_hurry ( rhp , rcu_torture_err_cb ) ; /* Another duplicate callback. */
2020-12-03 09:52:07 +08:00
}
2013-04-24 08:05:42 +08:00
local_irq_enable ( ) ;
rcu_read_unlock ( ) ;
preempt_enable ( ) ;
/* Wait for them all to get done so we can safely return. */
rcu_barrier ( ) ;
2017-12-02 07:22:38 +08:00
pr_alert ( " %s: WARN: Duplicate call_rcu() test complete. \n " , KBUILD_MODNAME ) ;
2013-04-24 08:05:42 +08:00
destroy_rcu_head_on_stack ( & rh1 ) ;
destroy_rcu_head_on_stack ( & rh2 ) ;
2022-04-27 15:15:20 +08:00
kfree ( rhp ) ;
2013-04-24 08:05:42 +08:00
# else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
2017-12-02 07:22:38 +08:00
pr_alert ( " %s: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu() \n " , KBUILD_MODNAME ) ;
2013-04-24 08:05:42 +08:00
# endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
}
2018-12-11 01:44:52 +08:00
static void rcutorture_sync ( void )
{
static unsigned long n ;
if ( cur_ops - > sync & & ! ( + + n & 0xfff ) )
cur_ops - > sync ( ) ;
}
2023-01-14 13:34:27 +08:00
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 ( srcu0 ) ;
DEFINE_STATIC_SRCU ( srcu1 ) ;
DEFINE_STATIC_SRCU ( srcu2 ) ;
DEFINE_STATIC_SRCU ( srcu3 ) ;
DEFINE_STATIC_SRCU ( srcu4 ) ;
DEFINE_STATIC_SRCU ( srcu5 ) ;
DEFINE_STATIC_SRCU ( srcu6 ) ;
DEFINE_STATIC_SRCU ( srcu7 ) ;
DEFINE_STATIC_SRCU ( srcu8 ) ;
DEFINE_STATIC_SRCU ( srcu9 ) ;
static int srcu_lockdep_next ( const char * f , const char * fl , const char * fs , const char * fu , int i ,
int cyclelen , int deadlock )
{
int j = i + 1 ;
if ( j > = cyclelen )
j = deadlock ? 0 : - 1 ;
if ( j > = 0 )
pr_info ( " %s: %s(%d), %s(%d), %s(%d) \n " , f , fl , i , fs , j , fu , i ) ;
else
pr_info ( " %s: %s(%d), %s(%d) \n " , f , fl , i , fu , i ) ;
return j ;
}
// Test lockdep on SRCU-based deadlock scenarios.
static void rcu_torture_init_srcu_lockdep ( void )
{
int cyclelen ;
int deadlock ;
bool err = false ;
int i ;
int j ;
int idx ;
struct mutex * muts [ ] = { & mut0 , & mut1 , & mut2 , & mut3 , & mut4 ,
& mut5 , & mut6 , & mut7 , & mut8 , & mut9 } ;
struct rw_semaphore * rwsems [ ] = { & rwsem0 , & rwsem1 , & rwsem2 , & rwsem3 , & rwsem4 ,
& rwsem5 , & rwsem6 , & rwsem7 , & rwsem8 , & rwsem9 } ;
struct srcu_struct * srcus [ ] = { & srcu0 , & srcu1 , & srcu2 , & srcu3 , & srcu4 ,
& srcu5 , & srcu6 , & srcu7 , & srcu8 , & srcu9 } ;
int testtype ;
if ( ! test_srcu_lockdep )
return ;
deadlock = test_srcu_lockdep / 1000 ;
testtype = ( test_srcu_lockdep / 10 ) % 100 ;
cyclelen = test_srcu_lockdep % 10 ;
WARN_ON_ONCE ( ARRAY_SIZE ( muts ) ! = ARRAY_SIZE ( srcus ) ) ;
if ( WARN_ONCE ( deadlock ! = ! ! deadlock ,
" %s: test_srcu_lockdep=%d and deadlock digit %d must be zero or one. \n " ,
__func__ , test_srcu_lockdep , deadlock ) )
err = true ;
if ( WARN_ONCE ( cyclelen < = 0 ,
" %s: test_srcu_lockdep=%d and cycle-length digit %d must be greater than zero. \n " ,
__func__ , test_srcu_lockdep , cyclelen ) )
err = true ;
if ( err )
goto err_out ;
if ( testtype = = 0 ) {
pr_info ( " %s: test_srcu_lockdep = %05d: SRCU %d-way %sdeadlock. \n " ,
__func__ , test_srcu_lockdep , cyclelen , deadlock ? " " : " non- " ) ;
if ( deadlock & & cyclelen = = 1 )
pr_info ( " %s: Expect hang. \n " , __func__ ) ;
for ( i = 0 ; i < cyclelen ; i + + ) {
j = srcu_lockdep_next ( __func__ , " srcu_read_lock " , " synchronize_srcu " ,
" srcu_read_unlock " , i , cyclelen , deadlock ) ;
idx = srcu_read_lock ( srcus [ i ] ) ;
if ( j > = 0 )
synchronize_srcu ( srcus [ j ] ) ;
srcu_read_unlock ( srcus [ i ] , idx ) ;
}
return ;
}
if ( testtype = = 1 ) {
pr_info ( " %s: test_srcu_lockdep = %05d: SRCU/mutex %d-way %sdeadlock. \n " ,
__func__ , test_srcu_lockdep , cyclelen , deadlock ? " " : " non- " ) ;
for ( i = 0 ; i < cyclelen ; i + + ) {
pr_info ( " %s: srcu_read_lock(%d), mutex_lock(%d), mutex_unlock(%d), srcu_read_unlock(%d) \n " ,
__func__ , i , i , i , i ) ;
idx = srcu_read_lock ( srcus [ i ] ) ;
mutex_lock ( muts [ i ] ) ;
mutex_unlock ( muts [ i ] ) ;
srcu_read_unlock ( srcus [ i ] , idx ) ;
j = srcu_lockdep_next ( __func__ , " mutex_lock " , " synchronize_srcu " ,
" mutex_unlock " , i , cyclelen , deadlock ) ;
mutex_lock ( muts [ i ] ) ;
if ( j > = 0 )
synchronize_srcu ( srcus [ j ] ) ;
mutex_unlock ( muts [ i ] ) ;
}
return ;
}
if ( testtype = = 2 ) {
pr_info ( " %s: test_srcu_lockdep = %05d: SRCU/rwsem %d-way %sdeadlock. \n " ,
__func__ , test_srcu_lockdep , cyclelen , deadlock ? " " : " non- " ) ;
for ( i = 0 ; i < cyclelen ; i + + ) {
pr_info ( " %s: srcu_read_lock(%d), down_read(%d), up_read(%d), srcu_read_unlock(%d) \n " ,
__func__ , i , i , i , i ) ;
idx = srcu_read_lock ( srcus [ i ] ) ;
down_read ( rwsems [ i ] ) ;
up_read ( rwsems [ i ] ) ;
srcu_read_unlock ( srcus [ i ] , idx ) ;
j = srcu_lockdep_next ( __func__ , " down_write " , " synchronize_srcu " ,
" up_write " , i , cyclelen , deadlock ) ;
down_write ( rwsems [ i ] ) ;
if ( j > = 0 )
synchronize_srcu ( srcus [ j ] ) ;
up_write ( rwsems [ i ] ) ;
}
return ;
}
2023-01-25 01:43:15 +08:00
# ifdef CONFIG_TASKS_TRACE_RCU
if ( testtype = = 3 ) {
pr_info ( " %s: test_srcu_lockdep = %05d: SRCU and Tasks Trace RCU %d-way %sdeadlock. \n " ,
__func__ , test_srcu_lockdep , cyclelen , deadlock ? " " : " non- " ) ;
if ( deadlock & & cyclelen = = 1 )
pr_info ( " %s: Expect hang. \n " , __func__ ) ;
for ( i = 0 ; i < cyclelen ; i + + ) {
char * fl = i = = 0 ? " rcu_read_lock_trace " : " srcu_read_lock " ;
char * fs = i = = cyclelen - 1 ? " synchronize_rcu_tasks_trace "
: " synchronize_srcu " ;
char * fu = i = = 0 ? " rcu_read_unlock_trace " : " srcu_read_unlock " ;
j = srcu_lockdep_next ( __func__ , fl , fs , fu , i , cyclelen , deadlock ) ;
if ( i = = 0 )
rcu_read_lock_trace ( ) ;
else
idx = srcu_read_lock ( srcus [ i ] ) ;
if ( j > = 0 ) {
if ( i = = cyclelen - 1 )
synchronize_rcu_tasks_trace ( ) ;
else
synchronize_srcu ( srcus [ j ] ) ;
}
if ( i = = 0 )
rcu_read_unlock_trace ( ) ;
else
srcu_read_unlock ( srcus [ i ] , idx ) ;
}
return ;
}
# endif // #ifdef CONFIG_TASKS_TRACE_RCU
2023-01-14 13:34:27 +08:00
err_out :
pr_info ( " %s: test_srcu_lockdep = %05d does nothing. \n " , __func__ , test_srcu_lockdep ) ;
pr_info ( " %s: test_srcu_lockdep = DNNL. \n " , __func__ ) ;
pr_info ( " %s: D: Deadlock if nonzero. \n " , __func__ ) ;
2023-01-25 01:43:15 +08:00
pr_info ( " %s: NN: Test number, 0=SRCU, 1=SRCU/mutex, 2=SRCU/rwsem, 3=SRCU/Tasks Trace RCU. \n " , __func__ ) ;
2023-01-14 13:34:27 +08:00
pr_info ( " %s: L: Cycle length. \n " , __func__ ) ;
2023-01-25 01:43:15 +08:00
if ( ! IS_ENABLED ( CONFIG_TASKS_TRACE_RCU ) )
pr_info ( " %s: NN=3 disallowed because kernel is built with CONFIG_TASKS_TRACE_RCU=n \n " , __func__ ) ;
2023-01-14 13:34:27 +08:00
}
2007-05-08 15:25:24 +08:00
static int __init
2005-10-31 07:03:12 +08:00
rcu_torture_init ( void )
{
2018-07-24 05:16:47 +08:00
long i ;
2005-10-31 07:03:12 +08:00
int cpu ;
int firsterr = 0 ;
2020-06-19 04:29:55 +08:00
int flags = 0 ;
unsigned long gp_seq = 0 ;
2013-06-13 06:12:21 +08:00
static struct rcu_torture_ops * torture_ops [ ] = {
2022-03-18 04:29:59 +08:00
& rcu_ops , & rcu_busted_ops , & srcu_ops , & srcud_ops , & busted_srcud_ops ,
2022-03-18 07:16:45 +08:00
TASKS_OPS TASKS_RUDE_OPS TASKS_TRACING_OPS
2022-03-18 04:29:59 +08:00
& trivial_ops ,
2013-06-13 06:12:21 +08:00
} ;
2005-10-31 07:03:12 +08:00
2017-11-22 12:19:17 +08:00
if ( ! torture_init_begin ( torture_type , verbose ) )
2014-04-08 00:14:11 +08:00
return - EBUSY ;
2008-12-16 08:13:07 +08:00
2005-10-31 07:03:12 +08:00
/* Process args and tell the world that the torturer is on the job. */
2007-05-08 15:33:22 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( torture_ops ) ; i + + ) {
2006-06-27 17:54:03 +08:00
cur_ops = torture_ops [ i ] ;
2007-05-08 15:33:22 +08:00
if ( strcmp ( torture_type , cur_ops - > name ) = = 0 )
2006-06-27 17:54:03 +08:00
break ;
}
2007-05-08 15:33:22 +08:00
if ( i = = ARRAY_SIZE ( torture_ops ) ) {
2012-08-10 07:30:45 +08:00
pr_alert ( " rcu-torture: invalid torture type: \" %s \" \n " ,
torture_type ) ;
pr_alert ( " rcu-torture types: " ) ;
2009-10-26 10:03:54 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( torture_ops ) ; i + + )
2018-05-15 04:27:33 +08:00
pr_cont ( " %s " , torture_ops [ i ] - > name ) ;
pr_cont ( " \n " ) ;
2015-08-25 02:37:58 +08:00
firsterr = - EINVAL ;
2019-03-22 00:27:28 +08:00
cur_ops = NULL ;
2015-08-25 02:37:58 +08:00
goto unwind ;
2006-06-27 17:54:03 +08:00
}
2010-01-05 07:09:10 +08:00
if ( cur_ops - > fqs = = NULL & & fqs_duration ! = 0 ) {
2012-08-10 07:30:45 +08:00
pr_alert ( " rcu-torture: ->fqs NULL and non-zero fqs_duration, fqs disabled. \n " ) ;
2010-01-05 07:09:10 +08:00
fqs_duration = 0 ;
}
2023-02-03 14:40:54 +08:00
if ( nocbs_nthreads ! = 0 & & ( cur_ops ! = & rcu_ops | |
! IS_ENABLED ( CONFIG_RCU_NOCB_CPU ) ) ) {
pr_alert ( " rcu-torture types: %s and CONFIG_RCU_NOCB_CPU=%d, nocb toggle disabled. \n " ,
cur_ops - > name , IS_ENABLED ( CONFIG_RCU_NOCB_CPU ) ) ;
nocbs_nthreads = 0 ;
}
2007-05-08 15:33:20 +08:00
if ( cur_ops - > init )
2015-08-25 02:37:58 +08:00
cur_ops - > init ( ) ;
2006-06-27 17:54:03 +08:00
2023-01-14 13:34:27 +08:00
rcu_torture_init_srcu_lockdep ( ) ;
2014-03-13 01:26:35 +08:00
if ( nreaders > = 0 ) {
2005-10-31 07:03:12 +08:00
nrealreaders = nreaders ;
2014-03-13 01:26:35 +08:00
} else {
2015-03-13 04:55:48 +08:00
nrealreaders = num_online_cpus ( ) - 2 - nreaders ;
2014-03-13 01:26:35 +08:00
if ( nrealreaders < = 0 )
nrealreaders = 1 ;
}
2010-09-03 07:16:14 +08:00
rcu_torture_print_module_parms ( cur_ops , " Start of test " ) ;
2020-06-19 04:29:55 +08:00
rcutorture_get_gp_data ( cur_ops - > ttype , & flags , & gp_seq ) ;
srcutorture_get_gp_data ( cur_ops - > ttype , srcu_ctlp , & flags , & gp_seq ) ;
start_gp_seq = gp_seq ;
pr_alert ( " %s: Start-test grace-period state: g%ld f%#x \n " ,
cur_ops - > name , ( long ) gp_seq , flags ) ;
2005-10-31 07:03:12 +08:00
/* Set up the freelist. */
INIT_LIST_HEAD ( & rcu_torture_freelist ) ;
2007-05-08 15:33:14 +08:00
for ( i = 0 ; i < ARRAY_SIZE ( rcu_tortures ) ; i + + ) {
2005-11-18 17:10:50 +08:00
rcu_tortures [ i ] . rtort_mbtest = 0 ;
2005-10-31 07:03:12 +08:00
list_add_tail ( & rcu_tortures [ i ] . rtort_free ,
& rcu_torture_freelist ) ;
}
/* Initialize the statistics so that each run gets its own numbers. */
rcu_torture_current = NULL ;
rcu_torture_current_version = 0 ;
atomic_set ( & n_rcu_torture_alloc , 0 ) ;
atomic_set ( & n_rcu_torture_alloc_fail , 0 ) ;
atomic_set ( & n_rcu_torture_free , 0 ) ;
2005-11-18 17:10:50 +08:00
atomic_set ( & n_rcu_torture_mberror , 0 ) ;
2020-10-30 06:08:57 +08:00
atomic_set ( & n_rcu_torture_mbchk_fail , 0 ) ;
atomic_set ( & n_rcu_torture_mbchk_tries , 0 ) ;
2005-11-18 17:10:50 +08:00
atomic_set ( & n_rcu_torture_error , 0 ) ;
2012-02-21 09:51:45 +08:00
n_rcu_torture_barrier_error = 0 ;
2010-09-03 07:16:14 +08:00
n_rcu_torture_boost_ktrerror = 0 ;
n_rcu_torture_boost_failure = 0 ;
n_rcu_torture_boosts = 0 ;
2005-10-31 07:03:12 +08:00
for ( i = 0 ; i < RCU_TORTURE_PIPE_LEN + 1 ; i + + )
atomic_set ( & rcu_torture_wcount [ i ] , 0 ) ;
2006-03-28 17:56:37 +08:00
for_each_possible_cpu ( cpu ) {
2005-10-31 07:03:12 +08:00
for ( i = 0 ; i < RCU_TORTURE_PIPE_LEN + 1 ; i + + ) {
per_cpu ( rcu_torture_count , cpu ) [ i ] = 0 ;
per_cpu ( rcu_torture_batch , cpu ) [ i ] = 0 ;
}
}
2018-07-14 03:09:14 +08:00
err_segs_recorded = 0 ;
rt_read_nsegs = 0 ;
2005-10-31 07:03:12 +08:00
/* Start up the kthreads. */
2020-11-17 08:46:06 +08:00
rcu_torture_write_types ( ) ;
2014-02-04 03:52:27 +08:00
firsterr = torture_create_kthread ( rcu_torture_writer , NULL ,
writer_task ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2005-10-31 07:03:12 +08:00
goto unwind ;
2015-05-15 06:42:40 +08:00
if ( nfakewriters > 0 ) {
2017-12-02 06:26:56 +08:00
fakewriter_tasks = kcalloc ( nfakewriters ,
2015-05-15 06:42:40 +08:00
sizeof ( fakewriter_tasks [ 0 ] ) ,
GFP_KERNEL ) ;
if ( fakewriter_tasks = = NULL ) {
2021-11-03 16:30:28 +08:00
TOROUT_ERRSTRING ( " out of memory " ) ;
2015-05-15 06:42:40 +08:00
firsterr = - ENOMEM ;
goto unwind ;
}
2006-10-04 17:17:13 +08:00
}
for ( i = 0 ; i < nfakewriters ; i + + ) {
2014-02-04 03:52:27 +08:00
firsterr = torture_create_kthread ( rcu_torture_fakewriter ,
NULL , fakewriter_tasks [ i ] ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2006-10-04 17:17:13 +08:00
goto unwind ;
}
2017-12-02 06:26:56 +08:00
reader_tasks = kcalloc ( nrealreaders , sizeof ( reader_tasks [ 0 ] ) ,
2005-10-31 07:03:12 +08:00
GFP_KERNEL ) ;
2020-10-30 06:08:57 +08:00
rcu_torture_reader_mbchk = kcalloc ( nrealreaders , sizeof ( * rcu_torture_reader_mbchk ) ,
GFP_KERNEL ) ;
if ( ! reader_tasks | | ! rcu_torture_reader_mbchk ) {
2021-11-03 16:30:28 +08:00
TOROUT_ERRSTRING ( " out of memory " ) ;
2005-10-31 07:03:12 +08:00
firsterr = - ENOMEM ;
goto unwind ;
}
for ( i = 0 ; i < nrealreaders ; i + + ) {
2020-10-30 06:08:57 +08:00
rcu_torture_reader_mbchk [ i ] . rtc_chkrdr = - 1 ;
2018-07-24 05:16:47 +08:00
firsterr = torture_create_kthread ( rcu_torture_reader , ( void * ) i ,
2014-02-04 03:52:27 +08:00
reader_tasks [ i ] ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2005-10-31 07:03:12 +08:00
goto unwind ;
}
2020-09-24 08:39:46 +08:00
nrealnocbers = nocbs_nthreads ;
if ( WARN_ON ( nrealnocbers < 0 ) )
nrealnocbers = 1 ;
if ( WARN_ON ( nocbs_toggle < 0 ) )
nocbs_toggle = HZ ;
if ( nrealnocbers > 0 ) {
nocb_tasks = kcalloc ( nrealnocbers , sizeof ( nocb_tasks [ 0 ] ) , GFP_KERNEL ) ;
if ( nocb_tasks = = NULL ) {
2021-11-03 16:30:28 +08:00
TOROUT_ERRSTRING ( " out of memory " ) ;
2020-09-24 08:39:46 +08:00
firsterr = - ENOMEM ;
goto unwind ;
}
} else {
nocb_tasks = NULL ;
}
for ( i = 0 ; i < nrealnocbers ; i + + ) {
firsterr = torture_create_kthread ( rcu_nocb_toggle , NULL , nocb_tasks [ i ] ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2020-09-24 08:39:46 +08:00
goto unwind ;
}
2005-10-31 07:03:12 +08:00
if ( stat_interval > 0 ) {
2014-02-04 03:52:27 +08:00
firsterr = torture_create_kthread ( rcu_torture_stats , NULL ,
stats_task ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2005-10-31 07:03:12 +08:00
goto unwind ;
}
2015-05-15 07:55:45 +08:00
if ( test_no_idle_hz & & shuffle_interval > 0 ) {
2014-01-29 07:29:21 +08:00
firsterr = torture_shuffle_init ( shuffle_interval * HZ ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2006-01-08 17:03:42 +08:00
goto unwind ;
}
2008-06-18 20:21:44 +08:00
if ( stutter < 0 )
stutter = 0 ;
if ( stutter ) {
2019-04-10 05:44:49 +08:00
int t ;
t = cur_ops - > stall_dur ? cur_ops - > stall_dur ( ) : stutter * HZ ;
firsterr = torture_stutter_init ( stutter * HZ , t ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2008-06-18 20:21:44 +08:00
goto unwind ;
}
2010-01-05 07:09:10 +08:00
if ( fqs_duration < 0 )
fqs_duration = 0 ;
if ( fqs_duration ) {
2014-02-01 03:57:43 +08:00
/* Create the fqs thread */
2014-03-18 11:56:45 +08:00
firsterr = torture_create_kthread ( rcu_torture_fqs , NULL ,
fqs_task ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2010-01-05 07:09:10 +08:00
goto unwind ;
}
2010-09-03 07:16:14 +08:00
if ( test_boost_interval < 1 )
test_boost_interval = 1 ;
if ( test_boost_duration < 2 )
test_boost_duration = 2 ;
2018-06-20 06:14:18 +08:00
if ( rcu_torture_can_boost ( ) ) {
2010-09-03 07:16:14 +08:00
boost_starttime = jiffies + test_boost_interval * HZ ;
2016-08-18 20:57:22 +08:00
firsterr = cpuhp_setup_state ( CPUHP_AP_ONLINE_DYN , " RCU_TORTURE " ,
rcutorture_booster_init ,
rcutorture_booster_cleanup ) ;
rcutor_hp = firsterr ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2016-08-18 20:57:22 +08:00
goto unwind ;
2010-09-03 07:16:14 +08:00
}
2019-07-10 23:30:00 +08:00
shutdown_jiffies = jiffies + shutdown_secs * HZ ;
2014-02-01 07:15:02 +08:00
firsterr = torture_shutdown_init ( shutdown_secs , rcu_torture_cleanup ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2012-02-18 14:12:18 +08:00
goto unwind ;
2018-12-11 01:44:52 +08:00
firsterr = torture_onoff_init ( onoff_holdoff * HZ , onoff_interval ,
rcutorture_sync ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2012-02-18 14:12:18 +08:00
goto unwind ;
2014-02-01 07:15:02 +08:00
firsterr = rcu_torture_stall_init ( ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2018-07-19 05:32:31 +08:00
goto unwind ;
firsterr = rcu_torture_fwd_prog_init ( ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2012-02-18 14:12:18 +08:00
goto unwind ;
2014-02-01 07:15:02 +08:00
firsterr = rcu_torture_barrier_init ( ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2020-04-25 02:21:40 +08:00
goto unwind ;
firsterr = rcu_torture_read_exit_init ( ) ;
2021-08-06 04:28:24 +08:00
if ( torture_init_error ( firsterr ) )
2012-02-21 09:51:45 +08:00
goto unwind ;
2013-04-24 08:05:42 +08:00
if ( object_debug )
rcu_test_debug_objects ( ) ;
2014-01-31 05:38:09 +08:00
torture_init_end ( ) ;
2022-02-05 04:45:18 +08:00
rcu_gp_slow_register ( & rcu_fwd_cb_nodelay ) ;
2005-10-31 07:03:12 +08:00
return 0 ;
unwind :
2014-01-31 05:38:09 +08:00
torture_init_end ( ) ;
2005-10-31 07:03:12 +08:00
rcu_torture_cleanup ( ) ;
2020-09-19 04:30:33 +08:00
if ( shutdown_secs ) {
WARN_ON ( ! IS_MODULE ( CONFIG_RCU_TORTURE_TEST ) ) ;
kernel_power_off ( ) ;
}
2005-10-31 07:03:12 +08:00
return firsterr ;
}
module_init ( rcu_torture_init ) ;
module_exit ( rcu_torture_cleanup ) ;