rcu: Introduce rcutorture testing for rcu_barrier()
Although rcutorture does invoke rcu_barrier() and friends, it cannot really be called a torture test given that it invokes them only once at the end of the test. This commit therefore introduces heavy-duty rcutorture testing for rcu_barrier(), which may be carried out concurrently with normal rcutorture testing. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
This commit is contained in:
parent
37e377d282
commit
fae4b54f28
@ -47,6 +47,16 @@ irqreader Says to invoke RCU readers from irq level. This is currently
|
|||||||
permit this. (Or, more accurately, variants of RCU that do
|
permit this. (Or, more accurately, variants of RCU that do
|
||||||
-not- permit this know to ignore this variable.)
|
-not- permit this know to ignore this variable.)
|
||||||
|
|
||||||
|
n_barrier_cbs If this is nonzero, RCU barrier testing will be conducted,
|
||||||
|
in which case n_barrier_cbs specifies the number of
|
||||||
|
RCU callbacks (and corresponding kthreads) to use for
|
||||||
|
this testing. The value cannot be negative. If you
|
||||||
|
specify this to be non-zero when torture_type indicates a
|
||||||
|
synchronous RCU implementation (one for which a member of
|
||||||
|
the synchronize_rcu() rather than the call_rcu() family is
|
||||||
|
used -- see the documentation for torture_type below), an
|
||||||
|
error will be reported and no testing will be carried out.
|
||||||
|
|
||||||
nfakewriters This is the number of RCU fake writer threads to run. Fake
|
nfakewriters This is the number of RCU fake writer threads to run. Fake
|
||||||
writer threads repeatedly use the synchronous "wait for
|
writer threads repeatedly use the synchronous "wait for
|
||||||
current readers" function of the interface selected by
|
current readers" function of the interface selected by
|
||||||
@ -188,7 +198,7 @@ OUTPUT
|
|||||||
The statistics output is as follows:
|
The statistics output is as follows:
|
||||||
|
|
||||||
rcu-torture:--- Start of test: nreaders=16 nfakewriters=4 stat_interval=30 verbose=0 test_no_idle_hz=1 shuffle_interval=3 stutter=5 irqreader=1 fqs_duration=0 fqs_holdoff=0 fqs_stutter=3 test_boost=1/0 test_boost_interval=7 test_boost_duration=4
|
rcu-torture:--- Start of test: nreaders=16 nfakewriters=4 stat_interval=30 verbose=0 test_no_idle_hz=1 shuffle_interval=3 stutter=5 irqreader=1 fqs_duration=0 fqs_holdoff=0 fqs_stutter=3 test_boost=1/0 test_boost_interval=7 test_boost_duration=4
|
||||||
rcu-torture: rtc: (null) ver: 155441 tfle: 0 rta: 155441 rtaf: 8884 rtf: 155440 rtmbe: 0 rtbke: 0 rtbre: 0 rtbf: 0 rtb: 0 nt: 3055767
|
rcu-torture: rtc: (null) ver: 155441 tfle: 0 rta: 155441 rtaf: 8884 rtf: 155440 rtmbe: 0 rtbe: 0 rtbke: 0 rtbre: 0 rtbf: 0 rtb: 0 nt: 3055767
|
||||||
rcu-torture: Reader Pipe: 727860534 34213 0 0 0 0 0 0 0 0 0
|
rcu-torture: Reader Pipe: 727860534 34213 0 0 0 0 0 0 0 0 0
|
||||||
rcu-torture: Reader Batch: 727877838 17003 0 0 0 0 0 0 0 0 0
|
rcu-torture: Reader Batch: 727877838 17003 0 0 0 0 0 0 0 0 0
|
||||||
rcu-torture: Free-Block Circulation: 155440 155440 155440 155440 155440 155440 155440 155440 155440 155440 0
|
rcu-torture: Free-Block Circulation: 155440 155440 155440 155440 155440 155440 155440 155440 155440 155440 0
|
||||||
@ -230,6 +240,9 @@ o "rtmbe": A non-zero value indicates that rcutorture believes that
|
|||||||
rcu_assign_pointer() and rcu_dereference() are not working
|
rcu_assign_pointer() and rcu_dereference() are not working
|
||||||
correctly. This value should be zero.
|
correctly. This value should be zero.
|
||||||
|
|
||||||
|
o "rtbe": A non-zero value indicates that one of the rcu_barrier()
|
||||||
|
family of functions is not working correctly.
|
||||||
|
|
||||||
o "rtbke": rcutorture was unable to create the real-time kthreads
|
o "rtbke": rcutorture was unable to create the real-time kthreads
|
||||||
used to force RCU priority inversion. This value should be zero.
|
used to force RCU priority inversion. This value should be zero.
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ static int irqreader = 1; /* RCU readers from irq (timers). */
|
|||||||
static int fqs_duration; /* Duration of bursts (us), 0 to disable. */
|
static int fqs_duration; /* Duration of bursts (us), 0 to disable. */
|
||||||
static int fqs_holdoff; /* Hold time within burst (us). */
|
static int fqs_holdoff; /* Hold time within burst (us). */
|
||||||
static int fqs_stutter = 3; /* Wait time between bursts (s). */
|
static int fqs_stutter = 3; /* Wait time between bursts (s). */
|
||||||
|
static int n_barrier_cbs; /* Number of callbacks to test RCU barriers. */
|
||||||
static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */
|
static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */
|
||||||
static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */
|
static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */
|
||||||
static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */
|
static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */
|
||||||
@ -96,6 +97,8 @@ module_param(fqs_holdoff, int, 0444);
|
|||||||
MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
|
MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
|
||||||
module_param(fqs_stutter, int, 0444);
|
module_param(fqs_stutter, int, 0444);
|
||||||
MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
|
MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
|
||||||
|
module_param(n_barrier_cbs, int, 0444);
|
||||||
|
MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
|
||||||
module_param(onoff_interval, int, 0444);
|
module_param(onoff_interval, int, 0444);
|
||||||
MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
|
MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
|
||||||
module_param(onoff_holdoff, int, 0444);
|
module_param(onoff_holdoff, int, 0444);
|
||||||
@ -139,6 +142,8 @@ static struct task_struct *shutdown_task;
|
|||||||
static struct task_struct *onoff_task;
|
static struct task_struct *onoff_task;
|
||||||
#endif /* #ifdef CONFIG_HOTPLUG_CPU */
|
#endif /* #ifdef CONFIG_HOTPLUG_CPU */
|
||||||
static struct task_struct *stall_task;
|
static struct task_struct *stall_task;
|
||||||
|
static struct task_struct **barrier_cbs_tasks;
|
||||||
|
static struct task_struct *barrier_task;
|
||||||
|
|
||||||
#define RCU_TORTURE_PIPE_LEN 10
|
#define RCU_TORTURE_PIPE_LEN 10
|
||||||
|
|
||||||
@ -164,6 +169,7 @@ static atomic_t n_rcu_torture_alloc_fail;
|
|||||||
static atomic_t n_rcu_torture_free;
|
static atomic_t n_rcu_torture_free;
|
||||||
static atomic_t n_rcu_torture_mberror;
|
static atomic_t n_rcu_torture_mberror;
|
||||||
static atomic_t n_rcu_torture_error;
|
static atomic_t n_rcu_torture_error;
|
||||||
|
static long n_rcu_torture_barrier_error;
|
||||||
static long n_rcu_torture_boost_ktrerror;
|
static long n_rcu_torture_boost_ktrerror;
|
||||||
static long n_rcu_torture_boost_rterror;
|
static long n_rcu_torture_boost_rterror;
|
||||||
static long n_rcu_torture_boost_failure;
|
static long n_rcu_torture_boost_failure;
|
||||||
@ -173,6 +179,8 @@ static long n_offline_attempts;
|
|||||||
static long n_offline_successes;
|
static long n_offline_successes;
|
||||||
static long n_online_attempts;
|
static long n_online_attempts;
|
||||||
static long n_online_successes;
|
static long n_online_successes;
|
||||||
|
static long n_barrier_attempts;
|
||||||
|
static long n_barrier_successes;
|
||||||
static struct list_head rcu_torture_removed;
|
static struct list_head rcu_torture_removed;
|
||||||
static cpumask_var_t shuffle_tmp_mask;
|
static cpumask_var_t shuffle_tmp_mask;
|
||||||
|
|
||||||
@ -197,6 +205,10 @@ static unsigned long shutdown_time; /* jiffies to system shutdown. */
|
|||||||
static unsigned long boost_starttime; /* jiffies of next boost test start. */
|
static unsigned long boost_starttime; /* jiffies of next boost test start. */
|
||||||
DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */
|
DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */
|
||||||
/* and boost task create/destroy. */
|
/* and boost task create/destroy. */
|
||||||
|
static atomic_t barrier_cbs_count; /* Barrier callbacks registered. */
|
||||||
|
static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */
|
||||||
|
static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */
|
||||||
|
static DECLARE_WAIT_QUEUE_HEAD(barrier_wq);
|
||||||
|
|
||||||
/* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */
|
/* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */
|
||||||
|
|
||||||
@ -327,6 +339,7 @@ struct rcu_torture_ops {
|
|||||||
int (*completed)(void);
|
int (*completed)(void);
|
||||||
void (*deferred_free)(struct rcu_torture *p);
|
void (*deferred_free)(struct rcu_torture *p);
|
||||||
void (*sync)(void);
|
void (*sync)(void);
|
||||||
|
void (*call)(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
|
||||||
void (*cb_barrier)(void);
|
void (*cb_barrier)(void);
|
||||||
void (*fqs)(void);
|
void (*fqs)(void);
|
||||||
int (*stats)(char *page);
|
int (*stats)(char *page);
|
||||||
@ -417,6 +430,7 @@ static struct rcu_torture_ops rcu_ops = {
|
|||||||
.completed = rcu_torture_completed,
|
.completed = rcu_torture_completed,
|
||||||
.deferred_free = rcu_torture_deferred_free,
|
.deferred_free = rcu_torture_deferred_free,
|
||||||
.sync = synchronize_rcu,
|
.sync = synchronize_rcu,
|
||||||
|
.call = call_rcu,
|
||||||
.cb_barrier = rcu_barrier,
|
.cb_barrier = rcu_barrier,
|
||||||
.fqs = rcu_force_quiescent_state,
|
.fqs = rcu_force_quiescent_state,
|
||||||
.stats = NULL,
|
.stats = NULL,
|
||||||
@ -460,6 +474,7 @@ static struct rcu_torture_ops rcu_sync_ops = {
|
|||||||
.completed = rcu_torture_completed,
|
.completed = rcu_torture_completed,
|
||||||
.deferred_free = rcu_sync_torture_deferred_free,
|
.deferred_free = rcu_sync_torture_deferred_free,
|
||||||
.sync = synchronize_rcu,
|
.sync = synchronize_rcu,
|
||||||
|
.call = NULL,
|
||||||
.cb_barrier = NULL,
|
.cb_barrier = NULL,
|
||||||
.fqs = rcu_force_quiescent_state,
|
.fqs = rcu_force_quiescent_state,
|
||||||
.stats = NULL,
|
.stats = NULL,
|
||||||
@ -477,6 +492,7 @@ static struct rcu_torture_ops rcu_expedited_ops = {
|
|||||||
.completed = rcu_no_completed,
|
.completed = rcu_no_completed,
|
||||||
.deferred_free = rcu_sync_torture_deferred_free,
|
.deferred_free = rcu_sync_torture_deferred_free,
|
||||||
.sync = synchronize_rcu_expedited,
|
.sync = synchronize_rcu_expedited,
|
||||||
|
.call = NULL,
|
||||||
.cb_barrier = NULL,
|
.cb_barrier = NULL,
|
||||||
.fqs = rcu_force_quiescent_state,
|
.fqs = rcu_force_quiescent_state,
|
||||||
.stats = NULL,
|
.stats = NULL,
|
||||||
@ -519,6 +535,7 @@ static struct rcu_torture_ops rcu_bh_ops = {
|
|||||||
.completed = rcu_bh_torture_completed,
|
.completed = rcu_bh_torture_completed,
|
||||||
.deferred_free = rcu_bh_torture_deferred_free,
|
.deferred_free = rcu_bh_torture_deferred_free,
|
||||||
.sync = synchronize_rcu_bh,
|
.sync = synchronize_rcu_bh,
|
||||||
|
.call = call_rcu_bh,
|
||||||
.cb_barrier = rcu_barrier_bh,
|
.cb_barrier = rcu_barrier_bh,
|
||||||
.fqs = rcu_bh_force_quiescent_state,
|
.fqs = rcu_bh_force_quiescent_state,
|
||||||
.stats = NULL,
|
.stats = NULL,
|
||||||
@ -535,6 +552,7 @@ static struct rcu_torture_ops rcu_bh_sync_ops = {
|
|||||||
.completed = rcu_bh_torture_completed,
|
.completed = rcu_bh_torture_completed,
|
||||||
.deferred_free = rcu_sync_torture_deferred_free,
|
.deferred_free = rcu_sync_torture_deferred_free,
|
||||||
.sync = synchronize_rcu_bh,
|
.sync = synchronize_rcu_bh,
|
||||||
|
.call = NULL,
|
||||||
.cb_barrier = NULL,
|
.cb_barrier = NULL,
|
||||||
.fqs = rcu_bh_force_quiescent_state,
|
.fqs = rcu_bh_force_quiescent_state,
|
||||||
.stats = NULL,
|
.stats = NULL,
|
||||||
@ -551,6 +569,7 @@ static struct rcu_torture_ops rcu_bh_expedited_ops = {
|
|||||||
.completed = rcu_bh_torture_completed,
|
.completed = rcu_bh_torture_completed,
|
||||||
.deferred_free = rcu_sync_torture_deferred_free,
|
.deferred_free = rcu_sync_torture_deferred_free,
|
||||||
.sync = synchronize_rcu_bh_expedited,
|
.sync = synchronize_rcu_bh_expedited,
|
||||||
|
.call = NULL,
|
||||||
.cb_barrier = NULL,
|
.cb_barrier = NULL,
|
||||||
.fqs = rcu_bh_force_quiescent_state,
|
.fqs = rcu_bh_force_quiescent_state,
|
||||||
.stats = NULL,
|
.stats = NULL,
|
||||||
@ -637,6 +656,7 @@ static struct rcu_torture_ops srcu_ops = {
|
|||||||
.completed = srcu_torture_completed,
|
.completed = srcu_torture_completed,
|
||||||
.deferred_free = rcu_sync_torture_deferred_free,
|
.deferred_free = rcu_sync_torture_deferred_free,
|
||||||
.sync = srcu_torture_synchronize,
|
.sync = srcu_torture_synchronize,
|
||||||
|
.call = NULL,
|
||||||
.cb_barrier = NULL,
|
.cb_barrier = NULL,
|
||||||
.stats = srcu_torture_stats,
|
.stats = srcu_torture_stats,
|
||||||
.name = "srcu"
|
.name = "srcu"
|
||||||
@ -661,6 +681,7 @@ static struct rcu_torture_ops srcu_raw_ops = {
|
|||||||
.completed = srcu_torture_completed,
|
.completed = srcu_torture_completed,
|
||||||
.deferred_free = rcu_sync_torture_deferred_free,
|
.deferred_free = rcu_sync_torture_deferred_free,
|
||||||
.sync = srcu_torture_synchronize,
|
.sync = srcu_torture_synchronize,
|
||||||
|
.call = NULL,
|
||||||
.cb_barrier = NULL,
|
.cb_barrier = NULL,
|
||||||
.stats = srcu_torture_stats,
|
.stats = srcu_torture_stats,
|
||||||
.name = "srcu_raw"
|
.name = "srcu_raw"
|
||||||
@ -680,6 +701,7 @@ static struct rcu_torture_ops srcu_expedited_ops = {
|
|||||||
.completed = srcu_torture_completed,
|
.completed = srcu_torture_completed,
|
||||||
.deferred_free = rcu_sync_torture_deferred_free,
|
.deferred_free = rcu_sync_torture_deferred_free,
|
||||||
.sync = srcu_torture_synchronize_expedited,
|
.sync = srcu_torture_synchronize_expedited,
|
||||||
|
.call = NULL,
|
||||||
.cb_barrier = NULL,
|
.cb_barrier = NULL,
|
||||||
.stats = srcu_torture_stats,
|
.stats = srcu_torture_stats,
|
||||||
.name = "srcu_expedited"
|
.name = "srcu_expedited"
|
||||||
@ -1129,7 +1151,8 @@ rcu_torture_printk(char *page)
|
|||||||
"rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d "
|
"rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d "
|
||||||
"rtmbe: %d rtbke: %ld rtbre: %ld "
|
"rtmbe: %d rtbke: %ld rtbre: %ld "
|
||||||
"rtbf: %ld rtb: %ld nt: %ld "
|
"rtbf: %ld rtb: %ld nt: %ld "
|
||||||
"onoff: %ld/%ld:%ld/%ld",
|
"onoff: %ld/%ld:%ld/%ld "
|
||||||
|
"barrier: %ld/%ld:%ld",
|
||||||
rcu_torture_current,
|
rcu_torture_current,
|
||||||
rcu_torture_current_version,
|
rcu_torture_current_version,
|
||||||
list_empty(&rcu_torture_freelist),
|
list_empty(&rcu_torture_freelist),
|
||||||
@ -1145,14 +1168,17 @@ rcu_torture_printk(char *page)
|
|||||||
n_online_successes,
|
n_online_successes,
|
||||||
n_online_attempts,
|
n_online_attempts,
|
||||||
n_offline_successes,
|
n_offline_successes,
|
||||||
n_offline_attempts);
|
n_offline_attempts,
|
||||||
|
n_barrier_successes,
|
||||||
|
n_barrier_attempts,
|
||||||
|
n_rcu_torture_barrier_error);
|
||||||
|
cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
|
||||||
if (atomic_read(&n_rcu_torture_mberror) != 0 ||
|
if (atomic_read(&n_rcu_torture_mberror) != 0 ||
|
||||||
|
n_rcu_torture_barrier_error != 0 ||
|
||||||
n_rcu_torture_boost_ktrerror != 0 ||
|
n_rcu_torture_boost_ktrerror != 0 ||
|
||||||
n_rcu_torture_boost_rterror != 0 ||
|
n_rcu_torture_boost_rterror != 0 ||
|
||||||
n_rcu_torture_boost_failure != 0)
|
n_rcu_torture_boost_failure != 0 ||
|
||||||
cnt += sprintf(&page[cnt], " !!!");
|
i > 1) {
|
||||||
cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
|
|
||||||
if (i > 1) {
|
|
||||||
cnt += sprintf(&page[cnt], "!!! ");
|
cnt += sprintf(&page[cnt], "!!! ");
|
||||||
atomic_inc(&n_rcu_torture_error);
|
atomic_inc(&n_rcu_torture_error);
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
@ -1560,6 +1586,151 @@ static void rcu_torture_stall_cleanup(void)
|
|||||||
stall_task = NULL;
|
stall_task = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback function for RCU barrier testing. */
|
||||||
|
void rcu_torture_barrier_cbf(struct rcu_head *rcu)
|
||||||
|
{
|
||||||
|
atomic_inc(&barrier_cbs_invoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* kthread function to register callbacks used to test RCU barriers. */
|
||||||
|
static int rcu_torture_barrier_cbs(void *arg)
|
||||||
|
{
|
||||||
|
long myid = (long)arg;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
|
||||||
|
init_rcu_head_on_stack(&rcu);
|
||||||
|
VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task started");
|
||||||
|
set_user_nice(current, 19);
|
||||||
|
do {
|
||||||
|
wait_event(barrier_cbs_wq[myid],
|
||||||
|
atomic_read(&barrier_cbs_count) == n_barrier_cbs ||
|
||||||
|
kthread_should_stop() ||
|
||||||
|
fullstop != FULLSTOP_DONTSTOP);
|
||||||
|
if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
|
||||||
|
break;
|
||||||
|
cur_ops->call(&rcu, rcu_torture_barrier_cbf);
|
||||||
|
if (atomic_dec_and_test(&barrier_cbs_count))
|
||||||
|
wake_up(&barrier_wq);
|
||||||
|
} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
|
||||||
|
VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task stopping");
|
||||||
|
rcutorture_shutdown_absorb("rcu_torture_barrier_cbs");
|
||||||
|
while (!kthread_should_stop())
|
||||||
|
schedule_timeout_interruptible(1);
|
||||||
|
cur_ops->cb_barrier();
|
||||||
|
destroy_rcu_head_on_stack(&rcu);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* kthread function to drive and coordinate RCU barrier testing. */
|
||||||
|
static int rcu_torture_barrier(void *arg)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VERBOSE_PRINTK_STRING("rcu_torture_barrier task starting");
|
||||||
|
do {
|
||||||
|
atomic_set(&barrier_cbs_invoked, 0);
|
||||||
|
atomic_set(&barrier_cbs_count, n_barrier_cbs);
|
||||||
|
/* wake_up() path contains the required barriers. */
|
||||||
|
for (i = 0; i < n_barrier_cbs; i++)
|
||||||
|
wake_up(&barrier_cbs_wq[i]);
|
||||||
|
wait_event(barrier_wq,
|
||||||
|
atomic_read(&barrier_cbs_count) == 0 ||
|
||||||
|
kthread_should_stop() ||
|
||||||
|
fullstop != FULLSTOP_DONTSTOP);
|
||||||
|
if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
|
||||||
|
break;
|
||||||
|
n_barrier_attempts++;
|
||||||
|
cur_ops->cb_barrier();
|
||||||
|
if (atomic_read(&barrier_cbs_invoked) != n_barrier_cbs) {
|
||||||
|
n_rcu_torture_barrier_error++;
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
}
|
||||||
|
n_barrier_successes++;
|
||||||
|
schedule_timeout_interruptible(HZ / 10);
|
||||||
|
} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
|
||||||
|
VERBOSE_PRINTK_STRING("rcu_torture_barrier task stopping");
|
||||||
|
rcutorture_shutdown_absorb("rcu_torture_barrier_cbs");
|
||||||
|
while (!kthread_should_stop())
|
||||||
|
schedule_timeout_interruptible(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize RCU barrier testing. */
|
||||||
|
static int rcu_torture_barrier_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (n_barrier_cbs == 0)
|
||||||
|
return 0;
|
||||||
|
if (cur_ops->call == NULL || cur_ops->cb_barrier == NULL) {
|
||||||
|
printk(KERN_ALERT "%s" TORTURE_FLAG
|
||||||
|
" Call or barrier ops missing for %s,\n",
|
||||||
|
torture_type, cur_ops->name);
|
||||||
|
printk(KERN_ALERT "%s" TORTURE_FLAG
|
||||||
|
" RCU barrier testing omitted from run.\n",
|
||||||
|
torture_type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
atomic_set(&barrier_cbs_count, 0);
|
||||||
|
atomic_set(&barrier_cbs_invoked, 0);
|
||||||
|
barrier_cbs_tasks =
|
||||||
|
kzalloc(n_barrier_cbs * sizeof(barrier_cbs_tasks[0]),
|
||||||
|
GFP_KERNEL);
|
||||||
|
barrier_cbs_wq =
|
||||||
|
kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (barrier_cbs_tasks == NULL || barrier_cbs_wq == 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
for (i = 0; i < n_barrier_cbs; i++) {
|
||||||
|
init_waitqueue_head(&barrier_cbs_wq[i]);
|
||||||
|
barrier_cbs_tasks[i] = kthread_run(rcu_torture_barrier_cbs,
|
||||||
|
(void *)i,
|
||||||
|
"rcu_torture_barrier_cbs");
|
||||||
|
if (IS_ERR(barrier_cbs_tasks[i])) {
|
||||||
|
ret = PTR_ERR(barrier_cbs_tasks[i]);
|
||||||
|
VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier_cbs");
|
||||||
|
barrier_cbs_tasks[i] = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
barrier_task = kthread_run(rcu_torture_barrier, NULL,
|
||||||
|
"rcu_torture_barrier");
|
||||||
|
if (IS_ERR(barrier_task)) {
|
||||||
|
ret = PTR_ERR(barrier_task);
|
||||||
|
VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier");
|
||||||
|
barrier_task = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up after RCU barrier testing. */
|
||||||
|
static void rcu_torture_barrier_cleanup(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (barrier_task != NULL) {
|
||||||
|
VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier task");
|
||||||
|
kthread_stop(barrier_task);
|
||||||
|
barrier_task = NULL;
|
||||||
|
}
|
||||||
|
if (barrier_cbs_tasks != NULL) {
|
||||||
|
for (i = 0; i < n_barrier_cbs; i++) {
|
||||||
|
if (barrier_cbs_tasks[i] != NULL) {
|
||||||
|
VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier_cbs task");
|
||||||
|
kthread_stop(barrier_cbs_tasks[i]);
|
||||||
|
barrier_cbs_tasks[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kfree(barrier_cbs_tasks);
|
||||||
|
barrier_cbs_tasks = NULL;
|
||||||
|
}
|
||||||
|
if (barrier_cbs_wq != NULL) {
|
||||||
|
kfree(barrier_cbs_wq);
|
||||||
|
barrier_cbs_wq = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int rcutorture_cpu_notify(struct notifier_block *self,
|
static int rcutorture_cpu_notify(struct notifier_block *self,
|
||||||
unsigned long action, void *hcpu)
|
unsigned long action, void *hcpu)
|
||||||
{
|
{
|
||||||
@ -1602,6 +1773,7 @@ rcu_torture_cleanup(void)
|
|||||||
fullstop = FULLSTOP_RMMOD;
|
fullstop = FULLSTOP_RMMOD;
|
||||||
mutex_unlock(&fullstop_mutex);
|
mutex_unlock(&fullstop_mutex);
|
||||||
unregister_reboot_notifier(&rcutorture_shutdown_nb);
|
unregister_reboot_notifier(&rcutorture_shutdown_nb);
|
||||||
|
rcu_torture_barrier_cleanup();
|
||||||
rcu_torture_stall_cleanup();
|
rcu_torture_stall_cleanup();
|
||||||
if (stutter_task) {
|
if (stutter_task) {
|
||||||
VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
|
VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
|
||||||
@ -1681,7 +1853,7 @@ rcu_torture_cleanup(void)
|
|||||||
|
|
||||||
if (cur_ops->cleanup)
|
if (cur_ops->cleanup)
|
||||||
cur_ops->cleanup();
|
cur_ops->cleanup();
|
||||||
if (atomic_read(&n_rcu_torture_error))
|
if (atomic_read(&n_rcu_torture_error) || n_rcu_torture_barrier_error)
|
||||||
rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE");
|
rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE");
|
||||||
else if (n_online_successes != n_online_attempts ||
|
else if (n_online_successes != n_online_attempts ||
|
||||||
n_offline_successes != n_offline_attempts)
|
n_offline_successes != n_offline_attempts)
|
||||||
@ -1697,6 +1869,7 @@ rcu_torture_init(void)
|
|||||||
int i;
|
int i;
|
||||||
int cpu;
|
int cpu;
|
||||||
int firsterr = 0;
|
int firsterr = 0;
|
||||||
|
int retval;
|
||||||
static struct rcu_torture_ops *torture_ops[] =
|
static struct rcu_torture_ops *torture_ops[] =
|
||||||
{ &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
|
{ &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
|
||||||
&rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops,
|
&rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops,
|
||||||
@ -1754,6 +1927,7 @@ rcu_torture_init(void)
|
|||||||
atomic_set(&n_rcu_torture_free, 0);
|
atomic_set(&n_rcu_torture_free, 0);
|
||||||
atomic_set(&n_rcu_torture_mberror, 0);
|
atomic_set(&n_rcu_torture_mberror, 0);
|
||||||
atomic_set(&n_rcu_torture_error, 0);
|
atomic_set(&n_rcu_torture_error, 0);
|
||||||
|
n_rcu_torture_barrier_error = 0;
|
||||||
n_rcu_torture_boost_ktrerror = 0;
|
n_rcu_torture_boost_ktrerror = 0;
|
||||||
n_rcu_torture_boost_rterror = 0;
|
n_rcu_torture_boost_rterror = 0;
|
||||||
n_rcu_torture_boost_failure = 0;
|
n_rcu_torture_boost_failure = 0;
|
||||||
@ -1877,7 +2051,6 @@ rcu_torture_init(void)
|
|||||||
test_boost_duration = 2;
|
test_boost_duration = 2;
|
||||||
if ((test_boost == 1 && cur_ops->can_boost) ||
|
if ((test_boost == 1 && cur_ops->can_boost) ||
|
||||||
test_boost == 2) {
|
test_boost == 2) {
|
||||||
int retval;
|
|
||||||
|
|
||||||
boost_starttime = jiffies + test_boost_interval * HZ;
|
boost_starttime = jiffies + test_boost_interval * HZ;
|
||||||
register_cpu_notifier(&rcutorture_cpu_nb);
|
register_cpu_notifier(&rcutorture_cpu_nb);
|
||||||
@ -1913,6 +2086,11 @@ rcu_torture_init(void)
|
|||||||
firsterr = i;
|
firsterr = i;
|
||||||
goto unwind;
|
goto unwind;
|
||||||
}
|
}
|
||||||
|
retval = rcu_torture_barrier_init();
|
||||||
|
if (retval != 0) {
|
||||||
|
firsterr = retval;
|
||||||
|
goto unwind;
|
||||||
|
}
|
||||||
rcutorture_record_test_transition();
|
rcutorture_record_test_transition();
|
||||||
mutex_unlock(&fullstop_mutex);
|
mutex_unlock(&fullstop_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user