|
@@ -244,6 +244,7 @@ struct rcu_torture_ops {
|
|
|
int (*readlock)(void);
|
|
|
void (*read_delay)(struct torture_random_state *rrsp);
|
|
|
void (*readunlock)(int idx);
|
|
|
+ unsigned long (*started)(void);
|
|
|
unsigned long (*completed)(void);
|
|
|
void (*deferred_free)(struct rcu_torture *p);
|
|
|
void (*sync)(void);
|
|
@@ -372,6 +373,7 @@ static struct rcu_torture_ops rcu_ops = {
|
|
|
.readlock = rcu_torture_read_lock,
|
|
|
.read_delay = rcu_read_delay,
|
|
|
.readunlock = rcu_torture_read_unlock,
|
|
|
+ .started = rcu_batches_started,
|
|
|
.completed = rcu_batches_completed,
|
|
|
.deferred_free = rcu_torture_deferred_free,
|
|
|
.sync = synchronize_rcu,
|
|
@@ -413,6 +415,7 @@ static struct rcu_torture_ops rcu_bh_ops = {
|
|
|
.readlock = rcu_bh_torture_read_lock,
|
|
|
.read_delay = rcu_read_delay, /* just reuse rcu's version. */
|
|
|
.readunlock = rcu_bh_torture_read_unlock,
|
|
|
+ .started = rcu_batches_started_bh,
|
|
|
.completed = rcu_batches_completed_bh,
|
|
|
.deferred_free = rcu_bh_torture_deferred_free,
|
|
|
.sync = synchronize_rcu_bh,
|
|
@@ -456,6 +459,7 @@ static struct rcu_torture_ops rcu_busted_ops = {
|
|
|
.readlock = rcu_torture_read_lock,
|
|
|
.read_delay = rcu_read_delay, /* just reuse rcu's version. */
|
|
|
.readunlock = rcu_torture_read_unlock,
|
|
|
+ .started = rcu_no_completed,
|
|
|
.completed = rcu_no_completed,
|
|
|
.deferred_free = rcu_busted_torture_deferred_free,
|
|
|
.sync = synchronize_rcu_busted,
|
|
@@ -554,6 +558,7 @@ static struct rcu_torture_ops srcu_ops = {
|
|
|
.readlock = srcu_torture_read_lock,
|
|
|
.read_delay = srcu_read_delay,
|
|
|
.readunlock = srcu_torture_read_unlock,
|
|
|
+ .started = NULL,
|
|
|
.completed = srcu_torture_completed,
|
|
|
.deferred_free = srcu_torture_deferred_free,
|
|
|
.sync = srcu_torture_synchronize,
|
|
@@ -590,6 +595,7 @@ static struct rcu_torture_ops sched_ops = {
|
|
|
.readlock = sched_torture_read_lock,
|
|
|
.read_delay = rcu_read_delay, /* just reuse rcu's version. */
|
|
|
.readunlock = sched_torture_read_unlock,
|
|
|
+ .started = rcu_batches_started_sched,
|
|
|
.completed = rcu_batches_completed_sched,
|
|
|
.deferred_free = rcu_sched_torture_deferred_free,
|
|
|
.sync = synchronize_sched,
|
|
@@ -628,6 +634,7 @@ static struct rcu_torture_ops tasks_ops = {
|
|
|
.readlock = tasks_torture_read_lock,
|
|
|
.read_delay = rcu_read_delay, /* just reuse rcu's version. */
|
|
|
.readunlock = tasks_torture_read_unlock,
|
|
|
+ .started = rcu_no_completed,
|
|
|
.completed = rcu_no_completed,
|
|
|
.deferred_free = rcu_tasks_torture_deferred_free,
|
|
|
.sync = synchronize_rcu_tasks,
|
|
@@ -1005,8 +1012,8 @@ static void rcutorture_trace_dump(void)
|
|
|
static void rcu_torture_timer(unsigned long unused)
|
|
|
{
|
|
|
int idx;
|
|
|
+ unsigned long started;
|
|
|
unsigned long completed;
|
|
|
- unsigned long completed_end;
|
|
|
static DEFINE_TORTURE_RANDOM(rand);
|
|
|
static DEFINE_SPINLOCK(rand_lock);
|
|
|
struct rcu_torture *p;
|
|
@@ -1014,7 +1021,10 @@ static void rcu_torture_timer(unsigned long unused)
|
|
|
unsigned long long ts;
|
|
|
|
|
|
idx = cur_ops->readlock();
|
|
|
- completed = cur_ops->completed();
|
|
|
+ if (cur_ops->started)
|
|
|
+ started = cur_ops->started();
|
|
|
+ else
|
|
|
+ started = cur_ops->completed();
|
|
|
ts = rcu_trace_clock_local();
|
|
|
p = rcu_dereference_check(rcu_torture_current,
|
|
|
rcu_read_lock_bh_held() ||
|
|
@@ -1037,14 +1047,16 @@ static void rcu_torture_timer(unsigned long unused)
|
|
|
/* Should not happen, but... */
|
|
|
pipe_count = RCU_TORTURE_PIPE_LEN;
|
|
|
}
|
|
|
- completed_end = cur_ops->completed();
|
|
|
+ completed = cur_ops->completed();
|
|
|
if (pipe_count > 1) {
|
|
|
do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts,
|
|
|
- completed, completed_end);
|
|
|
+ started, completed);
|
|
|
rcutorture_trace_dump();
|
|
|
}
|
|
|
__this_cpu_inc(rcu_torture_count[pipe_count]);
|
|
|
- completed = completed_end - completed;
|
|
|
+ completed = completed - started;
|
|
|
+ if (cur_ops->started)
|
|
|
+ completed++;
|
|
|
if (completed > RCU_TORTURE_PIPE_LEN) {
|
|
|
/* Should not happen, but... */
|
|
|
completed = RCU_TORTURE_PIPE_LEN;
|
|
@@ -1063,8 +1075,8 @@ static void rcu_torture_timer(unsigned long unused)
|
|
|
static int
|
|
|
rcu_torture_reader(void *arg)
|
|
|
{
|
|
|
+ unsigned long started;
|
|
|
unsigned long completed;
|
|
|
- unsigned long completed_end;
|
|
|
int idx;
|
|
|
DEFINE_TORTURE_RANDOM(rand);
|
|
|
struct rcu_torture *p;
|
|
@@ -1083,7 +1095,10 @@ rcu_torture_reader(void *arg)
|
|
|
mod_timer(&t, jiffies + 1);
|
|
|
}
|
|
|
idx = cur_ops->readlock();
|
|
|
- completed = cur_ops->completed();
|
|
|
+ if (cur_ops->started)
|
|
|
+ started = cur_ops->started();
|
|
|
+ else
|
|
|
+ started = cur_ops->completed();
|
|
|
ts = rcu_trace_clock_local();
|
|
|
p = rcu_dereference_check(rcu_torture_current,
|
|
|
rcu_read_lock_bh_held() ||
|
|
@@ -1104,14 +1119,16 @@ rcu_torture_reader(void *arg)
|
|
|
/* Should not happen, but... */
|
|
|
pipe_count = RCU_TORTURE_PIPE_LEN;
|
|
|
}
|
|
|
- completed_end = cur_ops->completed();
|
|
|
+ completed = cur_ops->completed();
|
|
|
if (pipe_count > 1) {
|
|
|
do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu,
|
|
|
- ts, completed, completed_end);
|
|
|
+ ts, started, completed);
|
|
|
rcutorture_trace_dump();
|
|
|
}
|
|
|
__this_cpu_inc(rcu_torture_count[pipe_count]);
|
|
|
- completed = completed_end - completed;
|
|
|
+ completed = completed - started;
|
|
|
+ if (cur_ops->started)
|
|
|
+ completed++;
|
|
|
if (completed > RCU_TORTURE_PIPE_LEN) {
|
|
|
/* Should not happen, but... */
|
|
|
completed = RCU_TORTURE_PIPE_LEN;
|