/*
- * Read-Copy Update module-based torture test facility
+ * Read-Copy Update /proc-based torture test facility
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
static int verbose; /* Print more debug info. */
static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */
static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
-static char *torture_type = "rcu"; /* What to torture. */
module_param(nreaders, int, 0);
MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
module_param(shuffle_interval, int, 0);
MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-module_param(torture_type, charp, 0);
-MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh)");
-
-#define TORTURE_FLAG "-torture:"
+#define TORTURE_FLAG "rcutorture: "
#define PRINTK_STRING(s) \
- do { printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
+ do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
#define VERBOSE_PRINTK_STRING(s) \
- do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
+ do { if (verbose) printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
#define VERBOSE_PRINTK_ERRSTRING(s) \
- do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0)
+ do { if (verbose) printk(KERN_ALERT TORTURE_FLAG "!!! " s "\n"); } while (0)
static char printk_buf[4096];
spin_unlock_bh(&rcu_torture_lock);
}
-struct rcu_random_state {
- unsigned long rrs_state;
- unsigned long rrs_count;
-};
-
-#define RCU_RANDOM_MULT 39916801 /* prime */
-#define RCU_RANDOM_ADD 479001701 /* prime */
-#define RCU_RANDOM_REFRESH 10000
-
-#define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 }
-
-/*
- * Crude but fast random-number generator. Uses a linear congruential
- * generator, with occasional help from get_random_bytes().
- */
-static long
-rcu_random(struct rcu_random_state *rrsp)
-{
- long refresh;
-
- if (--rrsp->rrs_count < 0) {
- get_random_bytes(&refresh, sizeof(refresh));
- rrsp->rrs_state += refresh;
- rrsp->rrs_count = RCU_RANDOM_REFRESH;
- }
- rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
- return swahw32(rrsp->rrs_state);
-}
-
-/*
- * Operations vector for selecting different types of tests.
- */
-
-struct rcu_torture_ops {
- void (*init)(void);
- void (*cleanup)(void);
- int (*readlock)(void);
- void (*readunlock)(int idx);
- int (*completed)(void);
- void (*deferredfree)(struct rcu_torture *p);
- int (*stats)(char *page);
- char *name;
-};
-static struct rcu_torture_ops *cur_ops = NULL;
-
-/*
- * Definitions for rcu torture testing.
- */
-
-static int rcu_torture_read_lock(void)
-{
- rcu_read_lock();
- return 0;
-}
-
-static void rcu_torture_read_unlock(int idx)
-{
- rcu_read_unlock();
-}
-
-static int rcu_torture_completed(void)
-{
- return rcu_batches_completed();
-}
-
static void
rcu_torture_cb(struct rcu_head *p)
{
rp->rtort_mbtest = 0;
rcu_torture_free(rp);
} else
- cur_ops->deferredfree(rp);
-}
-
-static void rcu_torture_deferred_free(struct rcu_torture *p)
-{
- call_rcu(&p->rtort_rcu, rcu_torture_cb);
+ call_rcu(p, rcu_torture_cb);
}
-static struct rcu_torture_ops rcu_ops = {
- .init = NULL,
- .cleanup = NULL,
- .readlock = rcu_torture_read_lock,
- .readunlock = rcu_torture_read_unlock,
- .completed = rcu_torture_completed,
- .deferredfree = rcu_torture_deferred_free,
- .stats = NULL,
- .name = "rcu"
+struct rcu_random_state {
+ unsigned long rrs_state;
+ unsigned long rrs_count;
};
-/*
- * Definitions for rcu_bh torture testing.
- */
-
-static int rcu_bh_torture_read_lock(void)
-{
- rcu_read_lock_bh();
- return 0;
-}
+#define RCU_RANDOM_MULT 39916801 /* prime */
+#define RCU_RANDOM_ADD 479001701 /* prime */
+#define RCU_RANDOM_REFRESH 10000
-static void rcu_bh_torture_read_unlock(int idx)
-{
- rcu_read_unlock_bh();
-}
+#define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 }
-static int rcu_bh_torture_completed(void)
+/*
+ * Crude but fast random-number generator. Uses a linear congruential
+ * generator, with occasional help from get_random_bytes().
+ */
+static long
+rcu_random(struct rcu_random_state *rrsp)
{
- return rcu_batches_completed_bh();
-}
+ long refresh;
-static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
-{
- call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
+ if (--rrsp->rrs_count < 0) {
+ get_random_bytes(&refresh, sizeof(refresh));
+ rrsp->rrs_state += refresh;
+ rrsp->rrs_count = RCU_RANDOM_REFRESH;
+ }
+ rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
+ return swahw32(rrsp->rrs_state);
}
-static struct rcu_torture_ops rcu_bh_ops = {
- .init = NULL,
- .cleanup = NULL,
- .readlock = rcu_bh_torture_read_lock,
- .readunlock = rcu_bh_torture_read_unlock,
- .completed = rcu_bh_torture_completed,
- .deferredfree = rcu_bh_torture_deferred_free,
- .stats = NULL,
- .name = "rcu_bh"
-};
-
-static struct rcu_torture_ops *torture_ops[] =
- { &rcu_ops, &rcu_bh_ops, NULL };
-
/*
* RCU torture writer kthread. Repeatedly substitutes a new structure
* for that pointed to by rcu_torture_current, freeing the old structure
do {
schedule_timeout_uninterruptible(1);
+ if (rcu_batches_completed() == oldbatch)
+ continue;
if ((rp = rcu_torture_alloc()) == NULL)
continue;
rp->rtort_pipe_count = 0;
i = RCU_TORTURE_PIPE_LEN;
atomic_inc(&rcu_torture_wcount[i]);
old_rp->rtort_pipe_count++;
- cur_ops->deferredfree(old_rp);
+ call_rcu(&old_rp->rtort_rcu, rcu_torture_cb);
}
rcu_torture_current_version++;
- oldbatch = cur_ops->completed();
+ oldbatch = rcu_batches_completed();
} while (!kthread_should_stop() && !fullstop);
VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
while (!kthread_should_stop())
rcu_torture_reader(void *arg)
{
int completed;
- int idx;
DEFINE_RCU_RANDOM(rand);
struct rcu_torture *p;
int pipe_count;
set_user_nice(current, 19);
do {
- idx = cur_ops->readlock();
- completed = cur_ops->completed();
+ rcu_read_lock();
+ completed = rcu_batches_completed();
p = rcu_dereference(rcu_torture_current);
if (p == NULL) {
/* Wait for rcu_torture_writer to get underway */
- cur_ops->readunlock(idx);
+ rcu_read_unlock();
schedule_timeout_interruptible(HZ);
continue;
}
pipe_count = RCU_TORTURE_PIPE_LEN;
}
++__get_cpu_var(rcu_torture_count)[pipe_count];
- completed = cur_ops->completed() - completed;
+ completed = rcu_batches_completed() - completed;
if (completed > RCU_TORTURE_PIPE_LEN) {
/* Should not happen, but... */
completed = RCU_TORTURE_PIPE_LEN;
}
++__get_cpu_var(rcu_torture_batch)[completed];
preempt_enable();
- cur_ops->readunlock(idx);
+ rcu_read_unlock();
schedule();
} while (!kthread_should_stop() && !fullstop);
VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
if (pipesummary[i] != 0)
break;
}
- cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
+ cnt += sprintf(&page[cnt], "rcutorture: ");
cnt += sprintf(&page[cnt],
"rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
"rtmbe: %d",
atomic_read(&n_rcu_torture_mberror));
if (atomic_read(&n_rcu_torture_mberror) != 0)
cnt += sprintf(&page[cnt], " !!!");
- cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
+ cnt += sprintf(&page[cnt], "\nrcutorture: ");
if (i > 1) {
cnt += sprintf(&page[cnt], "!!! ");
atomic_inc(&n_rcu_torture_error);
cnt += sprintf(&page[cnt], "Reader Pipe: ");
for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
cnt += sprintf(&page[cnt], " %ld", pipesummary[i]);
- cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
+ cnt += sprintf(&page[cnt], "\nrcutorture: ");
cnt += sprintf(&page[cnt], "Reader Batch: ");
- for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
+ for (i = 0; i < RCU_TORTURE_PIPE_LEN; i++)
cnt += sprintf(&page[cnt], " %ld", batchsummary[i]);
- cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
+ cnt += sprintf(&page[cnt], "\nrcutorture: ");
cnt += sprintf(&page[cnt], "Free-Block Circulation: ");
for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
cnt += sprintf(&page[cnt], " %d",
atomic_read(&rcu_torture_wcount[i]));
}
cnt += sprintf(&page[cnt], "\n");
- if (cur_ops->stats != NULL)
- cnt += cur_ops->stats(&page[cnt]);
return cnt;
}
static inline void
rcu_torture_print_module_parms(char *tag)
{
- printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d "
+ printk(KERN_ALERT TORTURE_FLAG "--- %s: nreaders=%d "
"stat_interval=%d verbose=%d test_no_idle_hz=%d "
"shuffle_interval = %d\n",
- torture_type, tag, nrealreaders, stat_interval, verbose,
- test_no_idle_hz, shuffle_interval);
+ tag, nrealreaders, stat_interval, verbose, test_no_idle_hz,
+ shuffle_interval);
}
static void
rcu_barrier();
rcu_torture_stats_print(); /* -After- the stats thread is stopped! */
-
- if (cur_ops->cleanup != NULL)
- cur_ops->cleanup();
if (atomic_read(&n_rcu_torture_error))
rcu_torture_print_module_parms("End of test: FAILURE");
else
/* Process args and tell the world that the torturer is on the job. */
- for (i = 0; cur_ops = torture_ops[i], cur_ops != NULL; i++) {
- cur_ops = torture_ops[i];
- if (strcmp(torture_type, cur_ops->name) == 0) {
- break;
- }
- }
- if (cur_ops == NULL) {
- printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
- torture_type);
- return (-EINVAL);
- }
- if (cur_ops->init != NULL)
- cur_ops->init(); /* no "goto unwind" prior to this point!!! */
-
if (nreaders >= 0)
nrealreaders = nreaders;
else