@@ -1432,28 +1432,34 @@ static void rcutorture_one_extend(int *readstate, int newstate,
14321432 /* First, put new protection in place to avoid critical-section gap. */
14331433 if (statesnew & RCUTORTURE_RDR_BH )
14341434 local_bh_disable ();
1435+ if (statesnew & RCUTORTURE_RDR_RBH )
1436+ rcu_read_lock_bh ();
14351437 if (statesnew & RCUTORTURE_RDR_IRQ )
14361438 local_irq_disable ();
14371439 if (statesnew & RCUTORTURE_RDR_PREEMPT )
14381440 preempt_disable ();
1439- if (statesnew & RCUTORTURE_RDR_RBH )
1440- rcu_read_lock_bh ();
14411441 if (statesnew & RCUTORTURE_RDR_SCHED )
14421442 rcu_read_lock_sched ();
14431443 if (statesnew & RCUTORTURE_RDR_RCU )
14441444 idxnew = cur_ops -> readlock () << RCUTORTURE_RDR_SHIFT ;
14451445
1446- /* Next, remove old protection, irq first due to bh conflict. */
1446+ /*
1447+ * Next, remove old protection, in decreasing order of strength
1448+ * to avoid unlock paths that aren't safe in the stronger
1449+ * context. Namely: BH can not be enabled with disabled interrupts.
1450+ * Additionally PREEMPT_RT requires that BH is enabled in preemptible
1451+ * context.
1452+ */
14471453 if (statesold & RCUTORTURE_RDR_IRQ )
14481454 local_irq_enable ();
1449- if (statesold & RCUTORTURE_RDR_BH )
1450- local_bh_enable ();
14511455 if (statesold & RCUTORTURE_RDR_PREEMPT )
14521456 preempt_enable ();
1453- if (statesold & RCUTORTURE_RDR_RBH )
1454- rcu_read_unlock_bh ();
14551457 if (statesold & RCUTORTURE_RDR_SCHED )
14561458 rcu_read_unlock_sched ();
1459+ if (statesold & RCUTORTURE_RDR_BH )
1460+ local_bh_enable ();
1461+ if (statesold & RCUTORTURE_RDR_RBH )
1462+ rcu_read_unlock_bh ();
14571463 if (statesold & RCUTORTURE_RDR_RCU ) {
14581464 bool lockit = !statesnew && !(torture_random (trsp ) & 0xffff );
14591465
@@ -1496,18 +1502,36 @@ rcutorture_extend_mask(int oldmask, struct torture_random_state *trsp)
14961502 int mask = rcutorture_extend_mask_max ();
14971503 unsigned long randmask1 = torture_random (trsp ) >> 8 ;
14981504 unsigned long randmask2 = randmask1 >> 3 ;
1505+ unsigned long preempts = RCUTORTURE_RDR_PREEMPT | RCUTORTURE_RDR_SCHED ;
1506+ unsigned long preempts_irq = preempts | RCUTORTURE_RDR_IRQ ;
1507+ unsigned long bhs = RCUTORTURE_RDR_BH | RCUTORTURE_RDR_RBH ;
14991508
15001509 WARN_ON_ONCE (mask >> RCUTORTURE_RDR_SHIFT );
15011510 /* Mostly only one bit (need preemption!), sometimes lots of bits. */
15021511 if (!(randmask1 & 0x7 ))
15031512 mask = mask & randmask2 ;
15041513 else
15051514 mask = mask & (1 << (randmask2 % RCUTORTURE_RDR_NBITS ));
1506- /* Can't enable bh w/irq disabled. */
1507- if ((mask & RCUTORTURE_RDR_IRQ ) &&
1508- ((!(mask & RCUTORTURE_RDR_BH ) && (oldmask & RCUTORTURE_RDR_BH )) ||
1509- (!(mask & RCUTORTURE_RDR_RBH ) && (oldmask & RCUTORTURE_RDR_RBH ))))
1510- mask |= RCUTORTURE_RDR_BH | RCUTORTURE_RDR_RBH ;
1515+
1516+ /*
1517+ * Can't enable bh w/irq disabled.
1518+ */
1519+ if (mask & RCUTORTURE_RDR_IRQ )
1520+ mask |= oldmask & bhs ;
1521+
1522+ /*
1523+ * Ideally these sequences would be detected in debug builds
1524+ * (regardless of RT), but until then don't stop testing
1525+ * them on non-RT.
1526+ */
1527+ if (IS_ENABLED (CONFIG_PREEMPT_RT )) {
1528+ /* Can't modify BH in atomic context */
1529+ if (oldmask & preempts_irq )
1530+ mask &= ~bhs ;
1531+ if ((oldmask | mask ) & preempts_irq )
1532+ mask |= oldmask & bhs ;
1533+ }
1534+
15111535 return mask ?: RCUTORTURE_RDR_RCU ;
15121536}
15131537
@@ -2741,7 +2765,7 @@ static int rcu_torture_read_exit(void *unused)
27412765static int rcu_torture_read_exit_init (void )
27422766{
27432767 if (read_exit_burst <= 0 )
2744- return - EINVAL ;
2768+ return 0 ;
27452769 init_waitqueue_head (& read_exit_wq );
27462770 read_exit_child_stop = false;
27472771 read_exit_child_stopped = false;
@@ -2819,7 +2843,7 @@ rcu_torture_cleanup(void)
28192843 rcutorture_seq_diff (gp_seq , start_gp_seq ));
28202844 torture_stop_kthread (rcu_torture_stats , stats_task );
28212845 torture_stop_kthread (rcu_torture_fqs , fqs_task );
2822- if (rcu_torture_can_boost ())
2846+ if (rcu_torture_can_boost () && rcutor_hp >= 0 )
28232847 cpuhp_remove_state (rcutor_hp );
28242848
28252849 /*
@@ -3037,7 +3061,7 @@ rcu_torture_init(void)
30373061 rcu_torture_write_types ();
30383062 firsterr = torture_create_kthread (rcu_torture_writer , NULL ,
30393063 writer_task );
3040- if (firsterr )
3064+ if (torture_init_error ( firsterr ) )
30413065 goto unwind ;
30423066 if (nfakewriters > 0 ) {
30433067 fakewriter_tasks = kcalloc (nfakewriters ,
@@ -3052,7 +3076,7 @@ rcu_torture_init(void)
30523076 for (i = 0 ; i < nfakewriters ; i ++ ) {
30533077 firsterr = torture_create_kthread (rcu_torture_fakewriter ,
30543078 NULL , fakewriter_tasks [i ]);
3055- if (firsterr )
3079+ if (torture_init_error ( firsterr ) )
30563080 goto unwind ;
30573081 }
30583082 reader_tasks = kcalloc (nrealreaders , sizeof (reader_tasks [0 ]),
@@ -3068,7 +3092,7 @@ rcu_torture_init(void)
30683092 rcu_torture_reader_mbchk [i ].rtc_chkrdr = -1 ;
30693093 firsterr = torture_create_kthread (rcu_torture_reader , (void * )i ,
30703094 reader_tasks [i ]);
3071- if (firsterr )
3095+ if (torture_init_error ( firsterr ) )
30723096 goto unwind ;
30733097 }
30743098 nrealnocbers = nocbs_nthreads ;
@@ -3088,18 +3112,18 @@ rcu_torture_init(void)
30883112 }
30893113 for (i = 0 ; i < nrealnocbers ; i ++ ) {
30903114 firsterr = torture_create_kthread (rcu_nocb_toggle , NULL , nocb_tasks [i ]);
3091- if (firsterr )
3115+ if (torture_init_error ( firsterr ) )
30923116 goto unwind ;
30933117 }
30943118 if (stat_interval > 0 ) {
30953119 firsterr = torture_create_kthread (rcu_torture_stats , NULL ,
30963120 stats_task );
3097- if (firsterr )
3121+ if (torture_init_error ( firsterr ) )
30983122 goto unwind ;
30993123 }
31003124 if (test_no_idle_hz && shuffle_interval > 0 ) {
31013125 firsterr = torture_shuffle_init (shuffle_interval * HZ );
3102- if (firsterr )
3126+ if (torture_init_error ( firsterr ) )
31033127 goto unwind ;
31043128 }
31053129 if (stutter < 0 )
@@ -3109,7 +3133,7 @@ rcu_torture_init(void)
31093133
31103134 t = cur_ops -> stall_dur ? cur_ops -> stall_dur () : stutter * HZ ;
31113135 firsterr = torture_stutter_init (stutter * HZ , t );
3112- if (firsterr )
3136+ if (torture_init_error ( firsterr ) )
31133137 goto unwind ;
31143138 }
31153139 if (fqs_duration < 0 )
@@ -3118,7 +3142,7 @@ rcu_torture_init(void)
31183142 /* Create the fqs thread */
31193143 firsterr = torture_create_kthread (rcu_torture_fqs , NULL ,
31203144 fqs_task );
3121- if (firsterr )
3145+ if (torture_init_error ( firsterr ) )
31223146 goto unwind ;
31233147 }
31243148 if (test_boost_interval < 1 )
@@ -3132,9 +3156,9 @@ rcu_torture_init(void)
31323156 firsterr = cpuhp_setup_state (CPUHP_AP_ONLINE_DYN , "RCU_TORTURE" ,
31333157 rcutorture_booster_init ,
31343158 rcutorture_booster_cleanup );
3135- if (firsterr < 0 )
3136- goto unwind ;
31373159 rcutor_hp = firsterr ;
3160+ if (torture_init_error (firsterr ))
3161+ goto unwind ;
31383162
31393163 // Testing RCU priority boosting requires rcutorture do
31403164 // some serious abuse. Counter this by running ksoftirqd
@@ -3153,23 +3177,23 @@ rcu_torture_init(void)
31533177 }
31543178 shutdown_jiffies = jiffies + shutdown_secs * HZ ;
31553179 firsterr = torture_shutdown_init (shutdown_secs , rcu_torture_cleanup );
3156- if (firsterr )
3180+ if (torture_init_error ( firsterr ) )
31573181 goto unwind ;
31583182 firsterr = torture_onoff_init (onoff_holdoff * HZ , onoff_interval ,
31593183 rcutorture_sync );
3160- if (firsterr )
3184+ if (torture_init_error ( firsterr ) )
31613185 goto unwind ;
31623186 firsterr = rcu_torture_stall_init ();
3163- if (firsterr )
3187+ if (torture_init_error ( firsterr ) )
31643188 goto unwind ;
31653189 firsterr = rcu_torture_fwd_prog_init ();
3166- if (firsterr )
3190+ if (torture_init_error ( firsterr ) )
31673191 goto unwind ;
31683192 firsterr = rcu_torture_barrier_init ();
3169- if (firsterr )
3193+ if (torture_init_error ( firsterr ) )
31703194 goto unwind ;
31713195 firsterr = rcu_torture_read_exit_init ();
3172- if (firsterr )
3196+ if (torture_init_error ( firsterr ) )
31733197 goto unwind ;
31743198 if (object_debug )
31753199 rcu_test_debug_objects ();
0 commit comments