@@ -115,6 +115,10 @@ torture_param(int, nreaders, -1, "Number of RCU reader threads");
115
115
torture_param (int , object_debug , 0 , "Enable debug-object double call_rcu() testing" );
116
116
torture_param (int , onoff_holdoff , 0 , "Time after boot before CPU hotplugs (s)" );
117
117
torture_param (int , onoff_interval , 0 , "Time between CPU hotplugs (jiffies), 0=disable" );
118
+ torture_param (bool , gpwrap_lag , true, "Enable grace-period wrap lag testing" );
119
+ torture_param (int , gpwrap_lag_gps , 8 , "Value to set for set_gpwrap_lag during an active testing period." );
120
+ torture_param (int , gpwrap_lag_cycle_mins , 30 , "Total cycle duration for gpwrap lag testing (in minutes)" );
121
+ torture_param (int , gpwrap_lag_active_mins , 5 , "Duration for which gpwrap lag is active within each cycle (in minutes)" );
118
122
torture_param (int , nocbs_nthreads , 0 , "Number of NOCB toggle threads, 0 to disable" );
119
123
torture_param (int , nocbs_toggle , 1000 , "Time between toggling nocb state (ms)" );
120
124
torture_param (int , preempt_duration , 0 , "Preemption duration (ms), zero to disable" );
@@ -413,6 +417,8 @@ struct rcu_torture_ops {
413
417
bool (* reader_blocked )(void );
414
418
unsigned long long (* gather_gp_seqs )(void );
415
419
void (* format_gp_seqs )(unsigned long long seqs , char * cp , size_t len );
420
+ void (* set_gpwrap_lag )(unsigned long lag );
421
+ int (* get_gpwrap_count )(int cpu );
416
422
long cbflood_max ;
417
423
int irq_capable ;
418
424
int can_boost ;
@@ -619,6 +625,8 @@ static struct rcu_torture_ops rcu_ops = {
619
625
: NULL ,
620
626
.gather_gp_seqs = rcutorture_gather_gp_seqs ,
621
627
.format_gp_seqs = rcutorture_format_gp_seqs ,
628
+ .set_gpwrap_lag = rcu_set_gpwrap_lag ,
629
+ .get_gpwrap_count = rcu_get_gpwrap_count ,
622
630
.irq_capable = 1 ,
623
631
.can_boost = IS_ENABLED (CONFIG_RCU_BOOST ),
624
632
.extendables = RCUTORTURE_MAX_EXTEND ,
@@ -2432,6 +2440,7 @@ rcu_torture_stats_print(void)
2432
2440
int i ;
2433
2441
long pipesummary [RCU_TORTURE_PIPE_LEN + 1 ] = { 0 };
2434
2442
long batchsummary [RCU_TORTURE_PIPE_LEN + 1 ] = { 0 };
2443
+ long n_gpwraps = 0 ;
2435
2444
struct rcu_torture * rtcp ;
2436
2445
static unsigned long rtcv_snap = ULONG_MAX ;
2437
2446
static bool splatted ;
@@ -2442,6 +2451,8 @@ rcu_torture_stats_print(void)
2442
2451
pipesummary [i ] += READ_ONCE (per_cpu (rcu_torture_count , cpu )[i ]);
2443
2452
batchsummary [i ] += READ_ONCE (per_cpu (rcu_torture_batch , cpu )[i ]);
2444
2453
}
2454
+ if (cur_ops -> get_gpwrap_count )
2455
+ n_gpwraps += cur_ops -> get_gpwrap_count (cpu );
2445
2456
}
2446
2457
for (i = RCU_TORTURE_PIPE_LEN ; i >= 0 ; i -- ) {
2447
2458
if (pipesummary [i ] != 0 )
@@ -2473,8 +2484,9 @@ rcu_torture_stats_print(void)
2473
2484
data_race (n_barrier_attempts ),
2474
2485
data_race (n_rcu_torture_barrier_error ));
2475
2486
pr_cont ("read-exits: %ld " , data_race (n_read_exits )); // Statistic.
2476
- pr_cont ("nocb-toggles: %ld:%ld\n " ,
2487
+ pr_cont ("nocb-toggles: %ld:%ld " ,
2477
2488
atomic_long_read (& n_nocb_offload ), atomic_long_read (& n_nocb_deoffload ));
2489
+ pr_cont ("gpwraps: %ld\n" , n_gpwraps );
2478
2490
2479
2491
pr_alert ("%s%s " , torture_type , TORTURE_FLAG );
2480
2492
if (atomic_read (& n_rcu_torture_mberror ) ||
@@ -3645,6 +3657,57 @@ static int rcu_torture_preempt(void *unused)
3645
3657
3646
3658
static enum cpuhp_state rcutor_hp ;
3647
3659
3660
+ static struct hrtimer gpwrap_lag_timer ;
3661
+ static bool gpwrap_lag_active ;
3662
+
3663
+ /* Timer handler for toggling RCU grace-period sequence overflow test lag value */
3664
+ static enum hrtimer_restart rcu_gpwrap_lag_timer (struct hrtimer * timer )
3665
+ {
3666
+ ktime_t next_delay ;
3667
+
3668
+ if (gpwrap_lag_active ) {
3669
+ pr_alert ("rcu-torture: Disabling gpwrap lag (value=0)\n" );
3670
+ cur_ops -> set_gpwrap_lag (0 );
3671
+ gpwrap_lag_active = false;
3672
+ next_delay = ktime_set ((gpwrap_lag_cycle_mins - gpwrap_lag_active_mins ) * 60 , 0 );
3673
+ } else {
3674
+ pr_alert ("rcu-torture: Enabling gpwrap lag (value=%d)\n" , gpwrap_lag_gps );
3675
+ cur_ops -> set_gpwrap_lag (gpwrap_lag_gps );
3676
+ gpwrap_lag_active = true;
3677
+ next_delay = ktime_set (gpwrap_lag_active_mins * 60 , 0 );
3678
+ }
3679
+
3680
+ if (torture_must_stop_irq ())
3681
+ return HRTIMER_NORESTART ;
3682
+
3683
+ hrtimer_forward_now (timer , next_delay );
3684
+ return HRTIMER_RESTART ;
3685
+ }
3686
+
3687
+ static int rcu_gpwrap_lag_init (void )
3688
+ {
3689
+ if (!gpwrap_lag )
3690
+ return 0 ;
3691
+
3692
+ if (gpwrap_lag_cycle_mins <= 0 || gpwrap_lag_active_mins <= 0 ) {
3693
+ pr_alert ("rcu-torture: lag timing parameters must be positive\n" );
3694
+ return - EINVAL ;
3695
+ }
3696
+
3697
+ hrtimer_setup (& gpwrap_lag_timer , rcu_gpwrap_lag_timer , CLOCK_MONOTONIC , HRTIMER_MODE_REL );
3698
+ gpwrap_lag_active = false;
3699
+ hrtimer_start (& gpwrap_lag_timer ,
3700
+ ktime_set ((gpwrap_lag_cycle_mins - gpwrap_lag_active_mins ) * 60 , 0 ), HRTIMER_MODE_REL );
3701
+
3702
+ return 0 ;
3703
+ }
3704
+
3705
+ static void rcu_gpwrap_lag_cleanup (void )
3706
+ {
3707
+ hrtimer_cancel (& gpwrap_lag_timer );
3708
+ cur_ops -> set_gpwrap_lag (0 );
3709
+ gpwrap_lag_active = false;
3710
+ }
3648
3711
static void
3649
3712
rcu_torture_cleanup (void )
3650
3713
{
@@ -3814,6 +3877,9 @@ rcu_torture_cleanup(void)
3814
3877
torture_cleanup_end ();
3815
3878
if (cur_ops -> gp_slow_unregister )
3816
3879
cur_ops -> gp_slow_unregister (NULL );
3880
+
3881
+ if (gpwrap_lag && cur_ops -> set_gpwrap_lag )
3882
+ rcu_gpwrap_lag_cleanup ();
3817
3883
}
3818
3884
3819
3885
static void rcu_torture_leak_cb (struct rcu_head * rhp )
@@ -4310,9 +4376,17 @@ rcu_torture_init(void)
4310
4376
}
4311
4377
if (object_debug )
4312
4378
rcu_test_debug_objects ();
4313
- torture_init_end ();
4379
+
4314
4380
if (cur_ops -> gp_slow_register && !WARN_ON_ONCE (!cur_ops -> gp_slow_unregister ))
4315
4381
cur_ops -> gp_slow_register (& rcu_fwd_cb_nodelay );
4382
+
4383
+ if (gpwrap_lag && cur_ops -> set_gpwrap_lag ) {
4384
+ firsterr = rcu_gpwrap_lag_init ();
4385
+ if (torture_init_error (firsterr ))
4386
+ goto unwind ;
4387
+ }
4388
+
4389
+ torture_init_end ();
4316
4390
return 0 ;
4317
4391
4318
4392
unwind :
0 commit comments