Skip to content

Commit e73e5b7

Browse files
paulmckrcuJoel Fernandes
authored andcommitted
rcutorture: Split out beginning and end from rcu_torture_one_read()
The rcu_torture_one_read() function is designed for RCU readers that are confined to a task, such that a single thread of control extends from the beginning of a given RCU read-side critical section to its end. This does not suffice for things like srcu_down_read() and srcu_up_read(), where the critical section might start at task level and end in a timer handler. This commit therefore creates separate init_rcu_torture_one_read_state(), rcu_torture_one_read_start(), and rcu_torture_one_read_end() functions, along with a rcu_torture_one_read_state structure to coordinate their actions. These will be used to create tests for srcu_down_read() and friends. One caution: The caller to rcu_torture_one_read_start() must enter the initial read-side critical section prior to the call. This enables use of non-standard primitives such as srcu_down_read() while still using the same validation code. Signed-off-by: Paul E. McKenney <[email protected]> Signed-off-by: Joel Fernandes <[email protected]>
1 parent 75d8bf4 commit e73e5b7

File tree

1 file changed

+81
-43
lines changed

1 file changed

+81
-43
lines changed

kernel/rcu/rcutorture.c

Lines changed: 81 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2164,82 +2164,99 @@ rcutorture_loop_extend(int *readstate, bool insoftirq, struct torture_random_sta
21642164
return &rtrsp[j];
21652165
}
21662166

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;
21752169
unsigned long cookie;
21762170
struct rcu_gp_oldstate cookie_full;
2177-
int i;
21782171
unsigned long started;
2179-
unsigned long completed;
2180-
int newstate;
21812172
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;
21882176
unsigned long long ts;
2177+
};
21892178

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) {
21942196
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();
21962198
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);
21982200
}
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,
22022204
!cur_ops->readlock_held || cur_ops->readlock_held());
2203-
if (p == NULL) {
2205+
if (rtorsp->p == NULL) {
22042206
/* 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);
22062208
return false;
22072209
}
2208-
if (p->rtort_mbtest == 0)
2210+
if (rtorsp->p->rtort_mbtest == 0)
22092211
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+
22122229
preempt_disable();
2213-
pipe_count = READ_ONCE(p->rtort_pipe_count);
2230+
pipe_count = READ_ONCE(rtorsp->p->rtort_pipe_count);
22142231
if (pipe_count > RCU_TORTURE_PIPE_LEN) {
22152232
// Should not happen in a correct RCU implementation,
22162233
// happens quite often for torture_type=busted.
22172234
pipe_count = RCU_TORTURE_PIPE_LEN;
22182235
}
22192236
completed = cur_ops->get_gp_seq();
22202237
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);
22232240
rcu_ftrace_dump(DUMP_ALL);
22242241
}
22252242
__this_cpu_inc(rcu_torture_count[pipe_count]);
2226-
completed = rcutorture_seq_diff(completed, started);
2243+
completed = rcutorture_seq_diff(completed, rtorsp->started);
22272244
if (completed > RCU_TORTURE_PIPE_LEN) {
22282245
/* Should not happen, but... */
22292246
completed = RCU_TORTURE_PIPE_LEN;
22302247
}
22312248
__this_cpu_inc(rcu_torture_batch[completed]);
22322249
preempt_enable();
2233-
if (checkpolling) {
2250+
if (rtorsp->checkpolling) {
22342251
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),
22362253
"%s: Cookie check 2 failed %s(%d) %lu->%lu\n",
22372254
__func__,
22382255
rcu_torture_writer_state_getname(),
22392256
rcu_torture_writer_state,
2240-
cookie, cur_ops->get_gp_state());
2257+
rtorsp->cookie, cur_ops->get_gp_state());
22412258
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),
22432260
"%s: Cookie check 6 failed %s(%d) online %*pbl\n",
22442261
__func__,
22452262
rcu_torture_writer_state_getname(),
@@ -2248,21 +2265,42 @@ static bool rcu_torture_one_read(struct torture_random_state *trsp, long myid)
22482265
}
22492266
if (cur_ops->reader_blocked)
22502267
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);
22532270
// This next splat is expected behavior if leakpointer, especially
22542271
// 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);
22562273

22572274
/* If error or close call, record the sequence of reader protections. */
22582275
if ((pipe_count > 1 || completed > 1) && !xchg(&err_segs_recorded, 1)) {
22592276
i = 0;
2260-
for (rtrsp1 = &rtseg[0]; rtrsp1 < rtrsp; rtrsp1++)
2277+
for (rtrsp1 = &rtorsp->rtseg[0]; rtrsp1 < rtorsp->rtrsp; rtrsp1++)
22612278
err_segs[i++] = *rtrsp1;
22622279
rt_read_nsegs = i;
22632280
rt_read_preempted = preempted;
22642281
}
2282+
}
22652283

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);
22662304
return true;
22672305
}
22682306

0 commit comments

Comments
 (0)