@@ -79,7 +79,7 @@ torture_param(int, fqs_duration, 0,
7979 "Duration of fqs bursts (us), 0 to disable" );
8080torture_param (int , fqs_holdoff , 0 , "Holdoff time within fqs bursts (us)" );
8181torture_param (int , fqs_stutter , 3 , "Wait time between fqs bursts (s)" );
82- torture_param (bool , fwd_progress , 1 , "Test grace-period forward progress" );
82+ torture_param (int , fwd_progress , 1 , "Test grace-period forward progress" );
8383torture_param (int , fwd_progress_div , 4 , "Fraction of CPU stall to wait" );
8484torture_param (int , fwd_progress_holdoff , 60 ,
8585 "Time between forward-progress tests (s)" );
@@ -146,7 +146,7 @@ static struct task_struct *stats_task;
146146static struct task_struct * fqs_task ;
147147static struct task_struct * boost_tasks [NR_CPUS ];
148148static struct task_struct * stall_task ;
149- static struct task_struct * fwd_prog_task ;
149+ static struct task_struct * * fwd_prog_tasks ;
150150static struct task_struct * * barrier_cbs_tasks ;
151151static struct task_struct * barrier_task ;
152152static struct task_struct * read_exit_task ;
@@ -2161,10 +2161,12 @@ struct rcu_fwd {
21612161 unsigned long rcu_fwd_startat ;
21622162 struct rcu_launder_hist n_launders_hist [N_LAUNDERS_HIST ];
21632163 unsigned long rcu_launder_gp_seq_start ;
2164+ int rcu_fwd_id ;
21642165};
21652166
21662167static DEFINE_MUTEX (rcu_fwd_mutex );
21672168static struct rcu_fwd * rcu_fwds ;
2169+ static unsigned long rcu_fwd_seq ;
21682170static bool rcu_fwd_emergency_stop ;
21692171
21702172static void rcu_torture_fwd_cb_hist (struct rcu_fwd * rfp )
@@ -2177,8 +2179,9 @@ static void rcu_torture_fwd_cb_hist(struct rcu_fwd *rfp)
21772179 for (i = ARRAY_SIZE (rfp -> n_launders_hist ) - 1 ; i > 0 ; i -- )
21782180 if (rfp -> n_launders_hist [i ].n_launders > 0 )
21792181 break ;
2180- pr_alert ("%s: Callback-invocation histogram (duration %lu jiffies):" ,
2181- __func__ , jiffies - rfp -> rcu_fwd_startat );
2182+ mutex_lock (& rcu_fwd_mutex ); // Serialize histograms.
2183+ pr_alert ("%s: Callback-invocation histogram %d (duration %lu jiffies):" ,
2184+ __func__ , rfp -> rcu_fwd_id , jiffies - rfp -> rcu_fwd_startat );
21822185 gps_old = rfp -> rcu_launder_gp_seq_start ;
21832186 for (j = 0 ; j <= i ; j ++ ) {
21842187 gps = rfp -> n_launders_hist [j ].launder_gp_seq ;
@@ -2189,6 +2192,7 @@ static void rcu_torture_fwd_cb_hist(struct rcu_fwd *rfp)
21892192 gps_old = gps ;
21902193 }
21912194 pr_cont ("\n" );
2195+ mutex_unlock (& rcu_fwd_mutex );
21922196}
21932197
21942198/* Callback function for continuous-flood RCU callbacks. */
@@ -2314,7 +2318,8 @@ static void rcu_torture_fwd_prog_nr(struct rcu_fwd *rfp,
23142318 cver = READ_ONCE (rcu_torture_current_version ) - cver ;
23152319 gps = rcutorture_seq_diff (cur_ops -> get_gp_seq (), gps );
23162320 WARN_ON (!cver && gps < 2 );
2317- pr_alert ("%s: Duration %ld cver %ld gps %ld\n" , __func__ , dur , cver , gps );
2321+ pr_alert ("%s: %d Duration %ld cver %ld gps %ld\n" , __func__ ,
2322+ rfp -> rcu_fwd_id , dur , cver , gps );
23182323 }
23192324 if (selfpropcb ) {
23202325 WRITE_ONCE (fcs .stop , 1 );
@@ -2432,6 +2437,8 @@ static void rcu_torture_fwd_prog_cr(struct rcu_fwd *rfp)
24322437static int rcutorture_oom_notify (struct notifier_block * self ,
24332438 unsigned long notused , void * nfreed )
24342439{
2440+ int i ;
2441+ long ncbs ;
24352442 struct rcu_fwd * rfp ;
24362443
24372444 mutex_lock (& rcu_fwd_mutex );
@@ -2442,18 +2449,26 @@ static int rcutorture_oom_notify(struct notifier_block *self,
24422449 }
24432450 WARN (1 , "%s invoked upon OOM during forward-progress testing.\n" ,
24442451 __func__ );
2445- rcu_torture_fwd_cb_hist (rfp );
2446- rcu_fwd_progress_check (1 + (jiffies - READ_ONCE (rfp -> rcu_fwd_startat )) / 2 );
2452+ for (i = 0 ; i < fwd_progress ; i ++ ) {
2453+ rcu_torture_fwd_cb_hist (& rfp [i ]);
2454+ rcu_fwd_progress_check (1 + (jiffies - READ_ONCE (rfp [i ].rcu_fwd_startat )) / 2 );
2455+ }
24472456 WRITE_ONCE (rcu_fwd_emergency_stop , true);
24482457 smp_mb (); /* Emergency stop before free and wait to avoid hangs. */
2449- pr_info ("%s: Freed %lu RCU callbacks.\n" ,
2450- __func__ , rcu_torture_fwd_prog_cbfree (rfp ));
2458+ ncbs = 0 ;
2459+ for (i = 0 ; i < fwd_progress ; i ++ )
2460+ ncbs += rcu_torture_fwd_prog_cbfree (& rfp [i ]);
2461+ pr_info ("%s: Freed %lu RCU callbacks.\n" , __func__ , ncbs );
24512462 rcu_barrier ();
2452- pr_info ("%s: Freed %lu RCU callbacks.\n" ,
2453- __func__ , rcu_torture_fwd_prog_cbfree (rfp ));
2463+ ncbs = 0 ;
2464+ for (i = 0 ; i < fwd_progress ; i ++ )
2465+ ncbs += rcu_torture_fwd_prog_cbfree (& rfp [i ]);
2466+ pr_info ("%s: Freed %lu RCU callbacks.\n" , __func__ , ncbs );
24542467 rcu_barrier ();
2455- pr_info ("%s: Freed %lu RCU callbacks.\n" ,
2456- __func__ , rcu_torture_fwd_prog_cbfree (rfp ));
2468+ ncbs = 0 ;
2469+ for (i = 0 ; i < fwd_progress ; i ++ )
2470+ ncbs += rcu_torture_fwd_prog_cbfree (& rfp [i ]);
2471+ pr_info ("%s: Freed %lu RCU callbacks.\n" , __func__ , ncbs );
24572472 smp_mb (); /* Frees before return to avoid redoing OOM. */
24582473 (* (unsigned long * )nfreed )++ ; /* Forward progress CBs freed! */
24592474 pr_info ("%s returning after OOM processing.\n" , __func__ );
@@ -2469,6 +2484,7 @@ static struct notifier_block rcutorture_oom_nb = {
24692484static int rcu_torture_fwd_prog (void * args )
24702485{
24712486 int oldnice = task_nice (current );
2487+ unsigned long oldseq = READ_ONCE (rcu_fwd_seq );
24722488 struct rcu_fwd * rfp = args ;
24732489 int tested = 0 ;
24742490 int tested_tries = 0 ;
@@ -2478,39 +2494,59 @@ static int rcu_torture_fwd_prog(void *args)
24782494 if (!IS_ENABLED (CONFIG_SMP ) || !IS_ENABLED (CONFIG_RCU_BOOST ))
24792495 set_user_nice (current , MAX_NICE );
24802496 do {
2481- schedule_timeout_interruptible (fwd_progress_holdoff * HZ );
2482- WRITE_ONCE (rcu_fwd_emergency_stop , false);
2497+ if (!rfp -> rcu_fwd_id ) {
2498+ schedule_timeout_interruptible (fwd_progress_holdoff * HZ );
2499+ WRITE_ONCE (rcu_fwd_emergency_stop , false);
2500+ WRITE_ONCE (rcu_fwd_seq , rcu_fwd_seq + 1 );
2501+ } else {
2502+ while (READ_ONCE (rcu_fwd_seq ) == oldseq )
2503+ schedule_timeout_interruptible (1 );
2504+ oldseq = READ_ONCE (rcu_fwd_seq );
2505+ }
2506+ pr_alert ("%s: Starting forward-progress test %d\n" , __func__ , rfp -> rcu_fwd_id );
2507+ if (rcu_inkernel_boot_has_ended () && torture_num_online_cpus () > rfp -> rcu_fwd_id )
2508+ rcu_torture_fwd_prog_cr (rfp );
24832509 if (!IS_ENABLED (CONFIG_TINY_RCU ) ||
2484- rcu_inkernel_boot_has_ended ())
2510+ ( rcu_inkernel_boot_has_ended () && torture_num_online_cpus () > rfp -> rcu_fwd_id ))
24852511 rcu_torture_fwd_prog_nr (rfp , & tested , & tested_tries );
2486- if (rcu_inkernel_boot_has_ended ())
2487- rcu_torture_fwd_prog_cr (rfp );
24882512
24892513 /* Avoid slow periods, better to test when busy. */
24902514 if (stutter_wait ("rcu_torture_fwd_prog" ))
24912515 sched_set_normal (current , oldnice );
24922516 } while (!torture_must_stop ());
24932517 /* Short runs might not contain a valid forward-progress attempt. */
2494- WARN_ON (!tested && tested_tries >= 5 );
2495- pr_alert ("%s: tested %d tested_tries %d\n" , __func__ , tested , tested_tries );
2518+ if (!rfp -> rcu_fwd_id ) {
2519+ WARN_ON (!tested && tested_tries >= 5 );
2520+ pr_alert ("%s: tested %d tested_tries %d\n" , __func__ , tested , tested_tries );
2521+ }
24962522 torture_kthread_stopping ("rcu_torture_fwd_prog" );
24972523 return 0 ;
24982524}
24992525
25002526/* If forward-progress checking is requested and feasible, spawn the thread. */
25012527static int __init rcu_torture_fwd_prog_init (void )
25022528{
2529+ int i ;
2530+ int ret = 0 ;
25032531 struct rcu_fwd * rfp ;
25042532
25052533 if (!fwd_progress )
25062534 return 0 ; /* Not requested, so don't do it. */
2535+ if (fwd_progress >= nr_cpu_ids ) {
2536+ VERBOSE_TOROUT_STRING ("rcu_torture_fwd_prog_init: Limiting fwd_progress to # CPUs.\n" );
2537+ fwd_progress = nr_cpu_ids ;
2538+ } else if (fwd_progress < 0 ) {
2539+ fwd_progress = nr_cpu_ids ;
2540+ }
25072541 if ((!cur_ops -> sync && !cur_ops -> call ) ||
25082542 !cur_ops -> stall_dur || cur_ops -> stall_dur () <= 0 || cur_ops == & rcu_busted_ops ) {
25092543 VERBOSE_TOROUT_STRING ("rcu_torture_fwd_prog_init: Disabled, unsupported by RCU flavor under test" );
2544+ fwd_progress = 0 ;
25102545 return 0 ;
25112546 }
25122547 if (stall_cpu > 0 ) {
25132548 VERBOSE_TOROUT_STRING ("rcu_torture_fwd_prog_init: Disabled, conflicts with CPU-stall testing" );
2549+ fwd_progress = 0 ;
25142550 if (IS_MODULE (CONFIG_RCU_TORTURE_TEST ))
25152551 return - EINVAL ; /* In module, can fail back to user. */
25162552 WARN_ON (1 ); /* Make sure rcutorture notices conflict. */
@@ -2520,29 +2556,51 @@ static int __init rcu_torture_fwd_prog_init(void)
25202556 fwd_progress_holdoff = 1 ;
25212557 if (fwd_progress_div <= 0 )
25222558 fwd_progress_div = 4 ;
2523- rfp = kzalloc (sizeof (* rfp ), GFP_KERNEL );
2524- if (!rfp )
2559+ rfp = kcalloc (fwd_progress , sizeof (* rfp ), GFP_KERNEL );
2560+ fwd_prog_tasks = kcalloc (fwd_progress , sizeof (* fwd_prog_tasks ), GFP_KERNEL );
2561+ if (!rfp || !fwd_prog_tasks ) {
2562+ kfree (rfp );
2563+ kfree (fwd_prog_tasks );
2564+ fwd_prog_tasks = NULL ;
2565+ fwd_progress = 0 ;
25252566 return - ENOMEM ;
2526- spin_lock_init (& rfp -> rcu_fwd_lock );
2527- rfp -> rcu_fwd_cb_tail = & rfp -> rcu_fwd_cb_head ;
2567+ }
2568+ for (i = 0 ; i < fwd_progress ; i ++ ) {
2569+ spin_lock_init (& rfp [i ].rcu_fwd_lock );
2570+ rfp [i ].rcu_fwd_cb_tail = & rfp [i ].rcu_fwd_cb_head ;
2571+ rfp [i ].rcu_fwd_id = i ;
2572+ }
25282573 mutex_lock (& rcu_fwd_mutex );
25292574 rcu_fwds = rfp ;
25302575 mutex_unlock (& rcu_fwd_mutex );
25312576 register_oom_notifier (& rcutorture_oom_nb );
2532- return torture_create_kthread (rcu_torture_fwd_prog , rfp , fwd_prog_task );
2577+ for (i = 0 ; i < fwd_progress ; i ++ ) {
2578+ ret = torture_create_kthread (rcu_torture_fwd_prog , & rcu_fwds [i ], fwd_prog_tasks [i ]);
2579+ if (ret ) {
2580+ fwd_progress = i ;
2581+ return ret ;
2582+ }
2583+ }
2584+ return 0 ;
25332585}
25342586
25352587static void rcu_torture_fwd_prog_cleanup (void )
25362588{
2589+ int i ;
25372590 struct rcu_fwd * rfp ;
25382591
2539- torture_stop_kthread (rcu_torture_fwd_prog , fwd_prog_task );
2540- rfp = rcu_fwds ;
2592+ if (!rcu_fwds || !fwd_prog_tasks )
2593+ return ;
2594+ for (i = 0 ; i < fwd_progress ; i ++ )
2595+ torture_stop_kthread (rcu_torture_fwd_prog , fwd_prog_tasks [i ]);
2596+ unregister_oom_notifier (& rcutorture_oom_nb );
25412597 mutex_lock (& rcu_fwd_mutex );
2598+ rfp = rcu_fwds ;
25422599 rcu_fwds = NULL ;
25432600 mutex_unlock (& rcu_fwd_mutex );
2544- unregister_oom_notifier (& rcutorture_oom_nb );
25452601 kfree (rfp );
2602+ kfree (fwd_prog_tasks );
2603+ fwd_prog_tasks = NULL ;
25462604}
25472605
25482606/* Callback function for RCU barrier testing. */
0 commit comments