@@ -109,6 +109,10 @@ torture_param(int, object_debug, 0,
109
109
torture_param (int , onoff_holdoff , 0 , "Time after boot before CPU hotplugs (s)" );
110
110
torture_param (int , onoff_interval , 0 ,
111
111
"Time between CPU hotplugs (jiffies), 0=disable" );
112
+ torture_param (int , read_exit_delay , 13 ,
113
+ "Delay between read-then-exit episodes (s)" );
114
+ torture_param (int , read_exit_burst , 16 ,
115
+ "# of read-then-exit bursts per episode, zero to disable" );
112
116
torture_param (int , shuffle_interval , 3 , "Number of seconds between shuffles" );
113
117
torture_param (int , shutdown_secs , 0 , "Shutdown time (s), <= zero to disable." );
114
118
torture_param (int , stall_cpu , 0 , "Stall duration (s), zero to disable." );
@@ -146,6 +150,7 @@ static struct task_struct *stall_task;
146
150
static struct task_struct * fwd_prog_task ;
147
151
static struct task_struct * * barrier_cbs_tasks ;
148
152
static struct task_struct * barrier_task ;
153
+ static struct task_struct * read_exit_task ;
149
154
150
155
#define RCU_TORTURE_PIPE_LEN 10
151
156
@@ -177,6 +182,7 @@ static long n_rcu_torture_boosts;
177
182
static atomic_long_t n_rcu_torture_timers ;
178
183
static long n_barrier_attempts ;
179
184
static long n_barrier_successes ; /* did rcu_barrier test succeed? */
185
+ static unsigned long n_read_exits ;
180
186
static struct list_head rcu_torture_removed ;
181
187
static unsigned long shutdown_jiffies ;
182
188
@@ -1539,10 +1545,11 @@ rcu_torture_stats_print(void)
1539
1545
n_rcu_torture_boosts ,
1540
1546
atomic_long_read (& n_rcu_torture_timers ));
1541
1547
torture_onoff_stats ();
1542
- pr_cont ("barrier: %ld/%ld:%ld\n " ,
1548
+ pr_cont ("barrier: %ld/%ld:%ld " ,
1543
1549
data_race (n_barrier_successes ),
1544
1550
data_race (n_barrier_attempts ),
1545
1551
data_race (n_rcu_torture_barrier_error ));
1552
+ pr_cont ("read-exits: %ld\n" , data_race (n_read_exits ));
1546
1553
1547
1554
pr_alert ("%s%s " , torture_type , TORTURE_FLAG );
1548
1555
if (atomic_read (& n_rcu_torture_mberror ) ||
@@ -1634,7 +1641,8 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
1634
1641
"stall_cpu=%d stall_cpu_holdoff=%d stall_cpu_irqsoff=%d "
1635
1642
"stall_cpu_block=%d "
1636
1643
"n_barrier_cbs=%d "
1637
- "onoff_interval=%d onoff_holdoff=%d\n" ,
1644
+ "onoff_interval=%d onoff_holdoff=%d "
1645
+ "read_exit_delay=%d read_exit_burst=%d\n" ,
1638
1646
torture_type , tag , nrealreaders , nfakewriters ,
1639
1647
stat_interval , verbose , test_no_idle_hz , shuffle_interval ,
1640
1648
stutter , irqreader , fqs_duration , fqs_holdoff , fqs_stutter ,
@@ -1643,7 +1651,8 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
1643
1651
stall_cpu , stall_cpu_holdoff , stall_cpu_irqsoff ,
1644
1652
stall_cpu_block ,
1645
1653
n_barrier_cbs ,
1646
- onoff_interval , onoff_holdoff );
1654
+ onoff_interval , onoff_holdoff ,
1655
+ read_exit_delay , read_exit_burst );
1647
1656
}
1648
1657
1649
1658
static int rcutorture_booster_cleanup (unsigned int cpu )
@@ -2338,6 +2347,99 @@ static bool rcu_torture_can_boost(void)
2338
2347
return true;
2339
2348
}
2340
2349
2350
+ static bool read_exit_child_stop ;
2351
+ static bool read_exit_child_stopped ;
2352
+ static wait_queue_head_t read_exit_wq ;
2353
+
2354
+ // Child kthread which just does an rcutorture reader and exits.
2355
+ static int rcu_torture_read_exit_child (void * trsp_in )
2356
+ {
2357
+ struct torture_random_state * trsp = trsp_in ;
2358
+
2359
+ set_user_nice (current , MAX_NICE );
2360
+ // Minimize time between reading and exiting.
2361
+ while (!kthread_should_stop ())
2362
+ schedule_timeout_uninterruptible (1 );
2363
+ (void )rcu_torture_one_read (trsp );
2364
+ return 0 ;
2365
+ }
2366
+
2367
+ // Parent kthread which creates and destroys read-exit child kthreads.
2368
+ static int rcu_torture_read_exit (void * unused )
2369
+ {
2370
+ int count = 0 ;
2371
+ bool errexit = false;
2372
+ int i ;
2373
+ struct task_struct * tsp ;
2374
+ DEFINE_TORTURE_RANDOM (trs );
2375
+
2376
+ // Allocate and initialize.
2377
+ set_user_nice (current , MAX_NICE );
2378
+ VERBOSE_TOROUT_STRING ("rcu_torture_read_exit: Start of test" );
2379
+
2380
+ // Each pass through this loop does one read-exit episode.
2381
+ do {
2382
+ if (++ count > read_exit_burst ) {
2383
+ VERBOSE_TOROUT_STRING ("rcu_torture_read_exit: End of episode" );
2384
+ rcu_barrier (); // Wait for task_struct free, avoid OOM.
2385
+ for (i = 0 ; i < read_exit_delay ; i ++ ) {
2386
+ schedule_timeout_uninterruptible (HZ );
2387
+ if (READ_ONCE (read_exit_child_stop ))
2388
+ break ;
2389
+ }
2390
+ if (!READ_ONCE (read_exit_child_stop ))
2391
+ VERBOSE_TOROUT_STRING ("rcu_torture_read_exit: Start of episode" );
2392
+ count = 0 ;
2393
+ }
2394
+ if (READ_ONCE (read_exit_child_stop ))
2395
+ break ;
2396
+ // Spawn child.
2397
+ tsp = kthread_run (rcu_torture_read_exit_child ,
2398
+ & trs , "%s" ,
2399
+ "rcu_torture_read_exit_child" );
2400
+ if (IS_ERR (tsp )) {
2401
+ VERBOSE_TOROUT_ERRSTRING ("out of memory" );
2402
+ errexit = true;
2403
+ tsp = NULL ;
2404
+ break ;
2405
+ }
2406
+ cond_resched ();
2407
+ kthread_stop (tsp );
2408
+ n_read_exits ++ ;
2409
+ stutter_wait ("rcu_torture_read_exit" );
2410
+ } while (!errexit && !READ_ONCE (read_exit_child_stop ));
2411
+
2412
+ // Clean up and exit.
2413
+ smp_store_release (& read_exit_child_stopped , true); // After reaping.
2414
+ smp_mb (); // Store before wakeup.
2415
+ wake_up (& read_exit_wq );
2416
+ while (!torture_must_stop ())
2417
+ schedule_timeout_uninterruptible (1 );
2418
+ torture_kthread_stopping ("rcu_torture_read_exit" );
2419
+ return 0 ;
2420
+ }
2421
+
2422
+ static int rcu_torture_read_exit_init (void )
2423
+ {
2424
+ if (read_exit_burst <= 0 )
2425
+ return - EINVAL ;
2426
+ init_waitqueue_head (& read_exit_wq );
2427
+ read_exit_child_stop = false;
2428
+ read_exit_child_stopped = false;
2429
+ return torture_create_kthread (rcu_torture_read_exit , NULL ,
2430
+ read_exit_task );
2431
+ }
2432
+
2433
+ static void rcu_torture_read_exit_cleanup (void )
2434
+ {
2435
+ if (!read_exit_task )
2436
+ return ;
2437
+ WRITE_ONCE (read_exit_child_stop , true);
2438
+ smp_mb (); // Above write before wait.
2439
+ wait_event (read_exit_wq , smp_load_acquire (& read_exit_child_stopped ));
2440
+ torture_stop_kthread (rcutorture_read_exit , read_exit_task );
2441
+ }
2442
+
2341
2443
static enum cpuhp_state rcutor_hp ;
2342
2444
2343
2445
static void
@@ -2359,6 +2461,7 @@ rcu_torture_cleanup(void)
2359
2461
}
2360
2462
2361
2463
show_rcu_gp_kthreads ();
2464
+ rcu_torture_read_exit_cleanup ();
2362
2465
rcu_torture_barrier_cleanup ();
2363
2466
torture_stop_kthread (rcu_torture_fwd_prog , fwd_prog_task );
2364
2467
torture_stop_kthread (rcu_torture_stall , stall_task );
@@ -2680,6 +2783,9 @@ rcu_torture_init(void)
2680
2783
if (firsterr )
2681
2784
goto unwind ;
2682
2785
firsterr = rcu_torture_barrier_init ();
2786
+ if (firsterr )
2787
+ goto unwind ;
2788
+ firsterr = rcu_torture_read_exit_init ();
2683
2789
if (firsterr )
2684
2790
goto unwind ;
2685
2791
if (object_debug )
0 commit comments