@@ -2164,82 +2164,99 @@ rcutorture_loop_extend(int *readstate, bool insoftirq, struct torture_random_sta
2164
2164
return & rtrsp [j ];
2165
2165
}
2166
2166
2167
- /*
2168
- * Do one read-side critical section, returning false if there was
2169
- * no data to read. Can be invoked both from process context and
2170
- * from a timer handler.
2171
- */
2172
- static bool rcu_torture_one_read (struct torture_random_state * trsp , long myid )
2173
- {
2174
- bool checkpolling = !(torture_random (trsp ) & 0xfff );
2167
+ struct rcu_torture_one_read_state {
2168
+ bool checkpolling ;
2175
2169
unsigned long cookie ;
2176
2170
struct rcu_gp_oldstate cookie_full ;
2177
- int i ;
2178
2171
unsigned long started ;
2179
- unsigned long completed ;
2180
- int newstate ;
2181
2172
struct rcu_torture * p ;
2182
- int pipe_count ;
2183
- bool preempted = false;
2184
- int readstate = 0 ;
2185
- struct rt_read_seg rtseg [RCUTORTURE_RDR_MAX_SEGS ] = { { 0 } };
2186
- struct rt_read_seg * rtrsp = & rtseg [0 ];
2187
- struct rt_read_seg * rtrsp1 ;
2173
+ int readstate ;
2174
+ struct rt_read_seg rtseg [RCUTORTURE_RDR_MAX_SEGS ];
2175
+ struct rt_read_seg * rtrsp ;
2188
2176
unsigned long long ts ;
2177
+ };
2189
2178
2190
- WARN_ON_ONCE (!rcu_is_watching ());
2191
- newstate = rcutorture_extend_mask (readstate , trsp );
2192
- rcutorture_one_extend (& readstate , newstate , myid < 0 , trsp , rtrsp ++ );
2193
- if (checkpolling ) {
2179
+ static void init_rcu_torture_one_read_state (struct rcu_torture_one_read_state * rtorsp ,
2180
+ struct torture_random_state * trsp )
2181
+ {
2182
+ memset (rtorsp , 0 , sizeof (* rtorsp ));
2183
+ rtorsp -> checkpolling = !(torture_random (trsp ) & 0xfff );
2184
+ rtorsp -> rtrsp = & rtorsp -> rtseg [0 ];
2185
+ }
2186
+
2187
+ /*
2188
+ * Set up the first segment of a series of overlapping read-side
2189
+ * critical sections. The caller must have actually initiated the
2190
+ * outermost read-side critical section.
2191
+ */
2192
+ static bool rcu_torture_one_read_start (struct rcu_torture_one_read_state * rtorsp ,
2193
+ struct torture_random_state * trsp , long myid )
2194
+ {
2195
+ if (rtorsp -> checkpolling ) {
2194
2196
if (cur_ops -> get_gp_state && cur_ops -> poll_gp_state )
2195
- cookie = cur_ops -> get_gp_state ();
2197
+ rtorsp -> cookie = cur_ops -> get_gp_state ();
2196
2198
if (cur_ops -> get_gp_state_full && cur_ops -> poll_gp_state_full )
2197
- cur_ops -> get_gp_state_full (& cookie_full );
2199
+ cur_ops -> get_gp_state_full (& rtorsp -> cookie_full );
2198
2200
}
2199
- started = cur_ops -> get_gp_seq ();
2200
- ts = rcu_trace_clock_local ();
2201
- p = rcu_dereference_check (rcu_torture_current ,
2201
+ rtorsp -> started = cur_ops -> get_gp_seq ();
2202
+ rtorsp -> ts = rcu_trace_clock_local ();
2203
+ rtorsp -> p = rcu_dereference_check (rcu_torture_current ,
2202
2204
!cur_ops -> readlock_held || cur_ops -> readlock_held ());
2203
- if (p == NULL ) {
2205
+ if (rtorsp -> p == NULL ) {
2204
2206
/* Wait for rcu_torture_writer to get underway */
2205
- rcutorture_one_extend (& readstate , 0 , myid < 0 , trsp , rtrsp );
2207
+ rcutorture_one_extend (& rtorsp -> readstate , 0 , myid < 0 , trsp , rtorsp -> rtrsp );
2206
2208
return false;
2207
2209
}
2208
- if (p -> rtort_mbtest == 0 )
2210
+ if (rtorsp -> p -> rtort_mbtest == 0 )
2209
2211
atomic_inc (& n_rcu_torture_mberror );
2210
- rcu_torture_reader_do_mbchk (myid , p , trsp );
2211
- rtrsp = rcutorture_loop_extend (& readstate , myid < 0 , trsp , rtrsp );
2212
+ rcu_torture_reader_do_mbchk (myid , rtorsp -> p , trsp );
2213
+ return true;
2214
+ }
2215
+
2216
+ /*
2217
+ * Complete the last segment of a series of overlapping read-side
2218
+ * critical sections and check for errors.
2219
+ */
2220
+ static void rcu_torture_one_read_end (struct rcu_torture_one_read_state * rtorsp ,
2221
+ struct torture_random_state * trsp , long myid )
2222
+ {
2223
+ int i ;
2224
+ unsigned long completed ;
2225
+ int pipe_count ;
2226
+ bool preempted = false;
2227
+ struct rt_read_seg * rtrsp1 ;
2228
+
2212
2229
preempt_disable ();
2213
- pipe_count = READ_ONCE (p -> rtort_pipe_count );
2230
+ pipe_count = READ_ONCE (rtorsp -> p -> rtort_pipe_count );
2214
2231
if (pipe_count > RCU_TORTURE_PIPE_LEN ) {
2215
2232
// Should not happen in a correct RCU implementation,
2216
2233
// happens quite often for torture_type=busted.
2217
2234
pipe_count = RCU_TORTURE_PIPE_LEN ;
2218
2235
}
2219
2236
completed = cur_ops -> get_gp_seq ();
2220
2237
if (pipe_count > 1 ) {
2221
- do_trace_rcu_torture_read (cur_ops -> name , & p -> rtort_rcu ,
2222
- ts , started , completed );
2238
+ do_trace_rcu_torture_read (cur_ops -> name , & rtorsp -> p -> rtort_rcu ,
2239
+ rtorsp -> ts , rtorsp -> started , completed );
2223
2240
rcu_ftrace_dump (DUMP_ALL );
2224
2241
}
2225
2242
__this_cpu_inc (rcu_torture_count [pipe_count ]);
2226
- completed = rcutorture_seq_diff (completed , started );
2243
+ completed = rcutorture_seq_diff (completed , rtorsp -> started );
2227
2244
if (completed > RCU_TORTURE_PIPE_LEN ) {
2228
2245
/* Should not happen, but... */
2229
2246
completed = RCU_TORTURE_PIPE_LEN ;
2230
2247
}
2231
2248
__this_cpu_inc (rcu_torture_batch [completed ]);
2232
2249
preempt_enable ();
2233
- if (checkpolling ) {
2250
+ if (rtorsp -> checkpolling ) {
2234
2251
if (cur_ops -> get_gp_state && cur_ops -> poll_gp_state )
2235
- WARN_ONCE (cur_ops -> poll_gp_state (cookie ),
2252
+ WARN_ONCE (cur_ops -> poll_gp_state (rtorsp -> cookie ),
2236
2253
"%s: Cookie check 2 failed %s(%d) %lu->%lu\n" ,
2237
2254
__func__ ,
2238
2255
rcu_torture_writer_state_getname (),
2239
2256
rcu_torture_writer_state ,
2240
- cookie , cur_ops -> get_gp_state ());
2257
+ rtorsp -> cookie , cur_ops -> get_gp_state ());
2241
2258
if (cur_ops -> get_gp_state_full && cur_ops -> poll_gp_state_full )
2242
- WARN_ONCE (cur_ops -> poll_gp_state_full (& cookie_full ),
2259
+ WARN_ONCE (cur_ops -> poll_gp_state_full (& rtorsp -> cookie_full ),
2243
2260
"%s: Cookie check 6 failed %s(%d) online %*pbl\n" ,
2244
2261
__func__ ,
2245
2262
rcu_torture_writer_state_getname (),
@@ -2248,21 +2265,42 @@ static bool rcu_torture_one_read(struct torture_random_state *trsp, long myid)
2248
2265
}
2249
2266
if (cur_ops -> reader_blocked )
2250
2267
preempted = cur_ops -> reader_blocked ();
2251
- rcutorture_one_extend (& readstate , 0 , myid < 0 , trsp , rtrsp );
2252
- WARN_ON_ONCE (readstate );
2268
+ rcutorture_one_extend (& rtorsp -> readstate , 0 , myid < 0 , trsp , rtorsp -> rtrsp );
2269
+ WARN_ON_ONCE (rtorsp -> readstate );
2253
2270
// This next splat is expected behavior if leakpointer, especially
2254
2271
// for CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels.
2255
- WARN_ON_ONCE (leakpointer && READ_ONCE (p -> rtort_pipe_count ) > 1 );
2272
+ WARN_ON_ONCE (leakpointer && READ_ONCE (rtorsp -> p -> rtort_pipe_count ) > 1 );
2256
2273
2257
2274
/* If error or close call, record the sequence of reader protections. */
2258
2275
if ((pipe_count > 1 || completed > 1 ) && !xchg (& err_segs_recorded , 1 )) {
2259
2276
i = 0 ;
2260
- for (rtrsp1 = & rtseg [0 ]; rtrsp1 < rtrsp ; rtrsp1 ++ )
2277
+ for (rtrsp1 = & rtorsp -> rtseg [0 ]; rtrsp1 < rtorsp -> rtrsp ; rtrsp1 ++ )
2261
2278
err_segs [i ++ ] = * rtrsp1 ;
2262
2279
rt_read_nsegs = i ;
2263
2280
rt_read_preempted = preempted ;
2264
2281
}
2282
+ }
2265
2283
2284
+ /*
2285
+ * Do one read-side critical section, returning false if there was
2286
+ * no data to read. Can be invoked both from process context and
2287
+ * from a timer handler.
2288
+ */
2289
+ static bool rcu_torture_one_read (struct torture_random_state * trsp , long myid )
2290
+ {
2291
+ int newstate ;
2292
+ struct rcu_torture_one_read_state rtors ;
2293
+
2294
+ WARN_ON_ONCE (!rcu_is_watching ());
2295
+ init_rcu_torture_one_read_state (& rtors , trsp );
2296
+ newstate = rcutorture_extend_mask (rtors .readstate , trsp );
2297
+ rcutorture_one_extend (& rtors .readstate , newstate , myid < 0 , trsp , rtors .rtrsp ++ );
2298
+ if (!rcu_torture_one_read_start (& rtors , trsp , myid )) {
2299
+ rcutorture_one_extend (& rtors .readstate , 0 , myid < 0 , trsp , rtors .rtrsp );
2300
+ return false;
2301
+ }
2302
+ rtors .rtrsp = rcutorture_loop_extend (& rtors .readstate , myid < 0 , trsp , rtors .rtrsp );
2303
+ rcu_torture_one_read_end (& rtors , trsp , myid );
2266
2304
return true;
2267
2305
}
2268
2306
0 commit comments