| 1 | |
| 2 | * Read-Copy Update module-based torture test facility
|
| 3 | *
|
| 4 | * This program is free software; you can redistribute it and/or modify
|
| 5 | * it under the terms of the GNU General Public License as published by
|
| 6 | * the Free Software Foundation; either version 2 of the License, or
|
| 7 | * (at your option) any later version.
|
| 8 | *
|
| 9 | * This program is distributed in the hope that it will be useful,
|
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 12 | * GNU General Public License for more details.
|
| 13 | *
|
| 14 | * You should have received a copy of the GNU General Public License
|
| 15 | * along with this program; if not, write to the Free Software
|
| 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
| 17 | *
|
| 18 | * Copyright (C) IBM Corporation, 2005, 2006
|
| 19 | *
|
| 20 | * Authors: Paul E. McKenney <[email protected]>
|
| 21 | * Josh Triplett <[email protected]>
|
| 22 | *
|
| 23 | * See also: Documentation/RCU/torture.txt
|
| 24 |
|
| 25 | #include <linux/types.h>
|
| 26 | #include <linux/kernel.h>
|
| 27 | #include <linux/init.h>
|
| 28 | #include <linux/module.h>
|
| 29 | #include <linux/kthread.h>
|
| 30 | #include <linux/err.h>
|
| 31 | #include <linux/spinlock.h>
|
| 32 | #include <linux/smp.h>
|
| 33 | #include <linux/rcupdate.h>
|
| 34 | #include <linux/interrupt.h>
|
| 35 | #include <linux/sched.h>
|
| 36 | #include <linux/atomic.h>
|
| 37 | #include <linux/bitops.h>
|
| 38 | #include <linux/completion.h>
|
| 39 | #include <linux/moduleparam.h>
|
| 40 | #include <linux/percpu.h>
|
| 41 | #include <linux/notifier.h>
|
| 42 | #include <linux/reboot.h>
|
| 43 | #include <linux/freezer.h>
|
| 44 | #include <linux/cpu.h>
|
| 45 | #include <linux/delay.h>
|
| 46 | #include <linux/stat.h>
|
| 47 | #include <linux/srcu.h>
|
| 48 | #include <linux/slab.h>
|
| 49 | #include <asm/byteorder.h>
|
| 50 |
|
| 51 | MODULE_LICENSE("GPL");
|
| 52 | MODULE_AUTHOR("Paul E. McKenney <[email protected]> and "
|
| 53 | "Josh Triplett <[email protected]>");
|
| 54 |
|
| 55 | static int nreaders = -1;
|
| 56 | static int nfakewriters = 4;
|
| 57 | static int stat_interval;
|
| 58 |
|
| 59 | static int verbose;
|
| 60 | static int test_no_idle_hz;
|
| 61 | static int shuffle_interval = 3;
|
| 62 | static int stutter = 5;
|
| 63 | static int irqreader = 1;
|
| 64 | static int fqs_duration = 0;
|
| 65 | static int fqs_holdoff = 0;
|
| 66 | static int fqs_stutter = 3;
|
| 67 | static int test_boost = 1;
|
| 68 | static int test_boost_interval = 7;
|
| 69 | static int test_boost_duration = 4;
|
| 70 | static char *torture_type = "rcu";
|
| 71 |
|
| 72 | module_param(nreaders, int, 0444);
|
| 73 | MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
|
| 74 | module_param(nfakewriters, int, 0444);
|
| 75 | MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
|
| 76 | module_param(stat_interval, int, 0444);
|
| 77 | MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
|
| 78 | module_param(verbose, bool, 0444);
|
| 79 | MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
|
| 80 | module_param(test_no_idle_hz, bool, 0444);
|
| 81 | MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
|
| 82 | module_param(shuffle_interval, int, 0444);
|
| 83 | MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
|
| 84 | module_param(stutter, int, 0444);
|
| 85 | MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
|
| 86 | module_param(irqreader, int, 0444);
|
| 87 | MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
|
| 88 | module_param(fqs_duration, int, 0444);
|
| 89 | MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us)");
|
| 90 | module_param(fqs_holdoff, int, 0444);
|
| 91 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
|
| 92 | module_param(fqs_stutter, int, 0444);
|
| 93 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
|
| 94 | module_param(test_boost, int, 0444);
|
| 95 | MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
|
| 96 | module_param(test_boost_interval, int, 0444);
|
| 97 | MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
|
| 98 | module_param(test_boost_duration, int, 0444);
|
| 99 | MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds.");
|
| 100 | module_param(torture_type, charp, 0444);
|
| 101 | MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
|
| 102 |
|
| 103 | #define TORTURE_FLAG "-torture:"
|
| 104 | #define PRINTK_STRING(s) \
|
| 105 | do { printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
|
| 106 | #define VERBOSE_PRINTK_STRING(s) \
|
| 107 | do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0)
|
| 108 | #define VERBOSE_PRINTK_ERRSTRING(s) \
|
| 109 | do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0)
|
| 110 |
|
| 111 | static char printk_buf[4096];
|
| 112 |
|
| 113 | static int nrealreaders;
|
| 114 | static struct task_struct *writer_task;
|
| 115 | static struct task_struct **fakewriter_tasks;
|
| 116 | static struct task_struct **reader_tasks;
|
| 117 | static struct task_struct *stats_task;
|
| 118 | static struct task_struct *shuffler_task;
|
| 119 | static struct task_struct *stutter_task;
|
| 120 | static struct task_struct *fqs_task;
|
| 121 | static struct task_struct *boost_tasks[NR_CPUS];
|
| 122 |
|
| 123 | #define RCU_TORTURE_PIPE_LEN 10
|
| 124 |
|
| 125 | struct rcu_torture {
|
| 126 | struct rcu_head rtort_rcu;
|
| 127 | int rtort_pipe_count;
|
| 128 | struct list_head rtort_free;
|
| 129 | int rtort_mbtest;
|
| 130 | };
|
| 131 |
|
| 132 | static LIST_HEAD(rcu_torture_freelist);
|
| 133 | static struct rcu_torture __rcu *rcu_torture_current;
|
| 134 | static unsigned long rcu_torture_current_version;
|
| 135 | static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
|
| 136 | static DEFINE_SPINLOCK(rcu_torture_lock);
|
| 137 | static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) =
|
| 138 | { 0 };
|
| 139 | static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) =
|
| 140 | { 0 };
|
| 141 | static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
|
| 142 | static atomic_t n_rcu_torture_alloc;
|
| 143 | static atomic_t n_rcu_torture_alloc_fail;
|
| 144 | static atomic_t n_rcu_torture_free;
|
| 145 | static atomic_t n_rcu_torture_mberror;
|
| 146 | static atomic_t n_rcu_torture_error;
|
| 147 | static long n_rcu_torture_boost_ktrerror;
|
| 148 | static long n_rcu_torture_boost_rterror;
|
| 149 | static long n_rcu_torture_boost_failure;
|
| 150 | static long n_rcu_torture_boosts;
|
| 151 | static long n_rcu_torture_timers;
|
| 152 | static struct list_head rcu_torture_removed;
|
| 153 | static cpumask_var_t shuffle_tmp_mask;
|
| 154 |
|
| 155 | static int stutter_pause_test;
|
| 156 |
|
| 157 | #if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE)
|
| 158 | #define RCUTORTURE_RUNNABLE_INIT 1
|
| 159 | #else
|
| 160 | #define RCUTORTURE_RUNNABLE_INIT 0
|
| 161 | #endif
|
| 162 | int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
|
| 163 |
|
| 164 | #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU)
|
| 165 | #define rcu_can_boost() 1
|
| 166 | #else
|
| 167 | #define rcu_can_boost() 0
|
| 168 | #endif
|
| 169 |
|
| 170 | static unsigned long boost_starttime;
|
| 171 | DEFINE_MUTEX(boost_mutex);
|
| 172 |
|
| 173 |
|
| 174 |
|
| 175 |
|
| 176 | #define FULLSTOP_DONTSTOP 0
|
| 177 | #define FULLSTOP_SHUTDOWN 1
|
| 178 | #define FULLSTOP_RMMOD 2
|
| 179 | static int fullstop = FULLSTOP_RMMOD;
|
| 180 | |
| 181 | * Protect fullstop transitions and spawning of kthreads.
|
| 182 |
|
| 183 | static DEFINE_MUTEX(fullstop_mutex);
|
| 184 |
|
| 185 | |
| 186 | * Detect and respond to a system shutdown.
|
| 187 |
|
| 188 | static int
|
| 189 | rcutorture_shutdown_notify(struct notifier_block *unused1,
|
| 190 | unsigned long unused2, void *unused3)
|
| 191 | {
|
| 192 | mutex_lock(&fullstop_mutex);
|
| 193 | if (fullstop == FULLSTOP_DONTSTOP)
|
| 194 | fullstop = FULLSTOP_SHUTDOWN;
|
| 195 | else
|
| 196 | printk(KERN_WARNING
|
| 197 | "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
|
| 198 | mutex_unlock(&fullstop_mutex);
|
| 199 | return NOTIFY_DONE;
|
| 200 | }
|
| 201 |
|
| 202 | |
| 203 | * Absorb kthreads into a kernel function that won't return, so that
|
| 204 | * they won't ever access module text or data again.
|
| 205 |
|
| 206 | static void rcutorture_shutdown_absorb(char *title)
|
| 207 | {
|
| 208 | if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
|
| 209 | printk(KERN_NOTICE
|
| 210 | "rcutorture thread %s parking due to system shutdown\n",
|
| 211 | title);
|
| 212 | schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT);
|
| 213 | }
|
| 214 | }
|
| 215 |
|
| 216 | |
| 217 | * Allocate an element from the rcu_tortures pool.
|
| 218 |
|
| 219 | static struct rcu_torture *
|
| 220 | rcu_torture_alloc(void)
|
| 221 | {
|
| 222 | struct list_head *p;
|
| 223 |
|
| 224 | spin_lock_bh(&rcu_torture_lock);
|
| 225 | if (list_empty(&rcu_torture_freelist)) {
|
| 226 | atomic_inc(&n_rcu_torture_alloc_fail);
|
| 227 | spin_unlock_bh(&rcu_torture_lock);
|
| 228 | return NULL;
|
| 229 | }
|
| 230 | atomic_inc(&n_rcu_torture_alloc);
|
| 231 | p = rcu_torture_freelist.next;
|
| 232 | list_del_init(p);
|
| 233 | spin_unlock_bh(&rcu_torture_lock);
|
| 234 | return container_of(p, struct rcu_torture, rtort_free);
|
| 235 | }
|
| 236 |
|
| 237 | |
| 238 | * Free an element to the rcu_tortures pool.
|
| 239 |
|
| 240 | static void
|
| 241 | rcu_torture_free(struct rcu_torture *p)
|
| 242 | {
|
| 243 | atomic_inc(&n_rcu_torture_free);
|
| 244 | spin_lock_bh(&rcu_torture_lock);
|
| 245 | list_add_tail(&p->rtort_free, &rcu_torture_freelist);
|
| 246 | spin_unlock_bh(&rcu_torture_lock);
|
| 247 | }
|
| 248 |
|
| 249 | struct rcu_random_state {
|
| 250 | unsigned long rrs_state;
|
| 251 | long rrs_count;
|
| 252 | };
|
| 253 |
|
| 254 | #define RCU_RANDOM_MULT 39916801
|
| 255 | #define RCU_RANDOM_ADD 479001701
|
| 256 | #define RCU_RANDOM_REFRESH 10000
|
| 257 |
|
| 258 | #define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 }
|
| 259 |
|
| 260 | |
| 261 | * Crude but fast random-number generator. Uses a linear congruential
|
| 262 | * generator, with occasional help from cpu_clock().
|
| 263 |
|
| 264 | static unsigned long
|
| 265 | rcu_random(struct rcu_random_state *rrsp)
|
| 266 | {
|
| 267 | if (--rrsp->rrs_count < 0) {
|
| 268 | rrsp->rrs_state += (unsigned long)local_clock();
|
| 269 | rrsp->rrs_count = RCU_RANDOM_REFRESH;
|
| 270 | }
|
| 271 | rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
|
| 272 | return swahw32(rrsp->rrs_state);
|
| 273 | }
|
| 274 |
|
| 275 | static void
|
| 276 | rcu_stutter_wait(char *title)
|
| 277 | {
|
| 278 | while (stutter_pause_test || !rcutorture_runnable) {
|
| 279 | if (rcutorture_runnable)
|
| 280 | schedule_timeout_interruptible(1);
|
| 281 | else
|
| 282 | schedule_timeout_interruptible(round_jiffies_relative(HZ));
|
| 283 | rcutorture_shutdown_absorb(title);
|
| 284 | }
|
| 285 | }
|
| 286 |
|
| 287 | |
| 288 | * Operations vector for selecting different types of tests.
|
| 289 |
|
| 290 |
|
| 291 | struct rcu_torture_ops {
|
| 292 | void (*init)(void);
|
| 293 | void (*cleanup)(void);
|
| 294 | int (*readlock)(void);
|
| 295 | void (*read_delay)(struct rcu_random_state *rrsp);
|
| 296 | void (*readunlock)(int idx);
|
| 297 | int (*completed)(void);
|
| 298 | void (*deferred_free)(struct rcu_torture *p);
|
| 299 | void (*sync)(void);
|
| 300 | void (*cb_barrier)(void);
|
| 301 | void (*fqs)(void);
|
| 302 | int (*stats)(char *page);
|
| 303 | int irq_capable;
|
| 304 | int can_boost;
|
| 305 | char *name;
|
| 306 | };
|
| 307 |
|
| 308 | static struct rcu_torture_ops *cur_ops;
|
| 309 |
|
| 310 | |
| 311 | * Definitions for rcu torture testing.
|
| 312 |
|
| 313 |
|
| 314 | static int rcu_torture_read_lock(void) __acquires(RCU)
|
| 315 | {
|
| 316 | rcu_read_lock();
|
| 317 | return 0;
|
| 318 | }
|
| 319 |
|
| 320 | static void rcu_read_delay(struct rcu_random_state *rrsp)
|
| 321 | {
|
| 322 | const unsigned long shortdelay_us = 200;
|
| 323 | const unsigned long longdelay_ms = 50;
|
| 324 |
|
| 325 | |
| 326 | * period, and we want a long delay occasionally to trigger
|
| 327 | * force_quiescent_state.
|
| 328 |
|
| 329 | if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
|
| 330 | mdelay(longdelay_ms);
|
| 331 | if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
|
| 332 | udelay(shortdelay_us);
|
| 333 | #ifdef CONFIG_PREEMPT
|
| 334 | if (!preempt_count() && !(rcu_random(rrsp) % (nrealreaders * 20000)))
|
| 335 | preempt_schedule();
|
| 336 | #endif
|
| 337 | }
|
| 338 |
|
| 339 | static void rcu_torture_read_unlock(int idx) __releases(RCU)
|
| 340 | {
|
| 341 | rcu_read_unlock();
|
| 342 | }
|
| 343 |
|
| 344 | static int rcu_torture_completed(void)
|
| 345 | {
|
| 346 | return rcu_batches_completed();
|
| 347 | }
|
| 348 |
|
| 349 | static void
|
| 350 | rcu_torture_cb(struct rcu_head *p)
|
| 351 | {
|
| 352 | int i;
|
| 353 | struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu);
|
| 354 |
|
| 355 | if (fullstop != FULLSTOP_DONTSTOP) {
|
| 356 |
|
| 357 |
|
| 358 | return;
|
| 359 | }
|
| 360 | i = rp->rtort_pipe_count;
|
| 361 | if (i > RCU_TORTURE_PIPE_LEN)
|
| 362 | i = RCU_TORTURE_PIPE_LEN;
|
| 363 | atomic_inc(&rcu_torture_wcount[i]);
|
| 364 | if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
|
| 365 | rp->rtort_mbtest = 0;
|
| 366 | rcu_torture_free(rp);
|
| 367 | } else
|
| 368 | cur_ops->deferred_free(rp);
|
| 369 | }
|
| 370 |
|
| 371 | static int rcu_no_completed(void)
|
| 372 | {
|
| 373 | return 0;
|
| 374 | }
|
| 375 |
|
| 376 | static void rcu_torture_deferred_free(struct rcu_torture *p)
|
| 377 | {
|
| 378 | call_rcu(&p->rtort_rcu, rcu_torture_cb);
|
| 379 | }
|
| 380 |
|
| 381 | static struct rcu_torture_ops rcu_ops = {
|
| 382 | .init = NULL,
|
| 383 | .cleanup = NULL,
|
| 384 | .readlock = rcu_torture_read_lock,
|
| 385 | .read_delay = rcu_read_delay,
|
| 386 | .readunlock = rcu_torture_read_unlock,
|
| 387 | .completed = rcu_torture_completed,
|
| 388 | .deferred_free = rcu_torture_deferred_free,
|
| 389 | .sync = synchronize_rcu,
|
| 390 | .cb_barrier = rcu_barrier,
|
| 391 | .fqs = rcu_force_quiescent_state,
|
| 392 | .stats = NULL,
|
| 393 | .irq_capable = 1,
|
| 394 | .can_boost = rcu_can_boost(),
|
| 395 | .name = "rcu"
|
| 396 | };
|
| 397 |
|
| 398 | static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
|
| 399 | {
|
| 400 | int i;
|
| 401 | struct rcu_torture *rp;
|
| 402 | struct rcu_torture *rp1;
|
| 403 |
|
| 404 | cur_ops->sync();
|
| 405 | list_add(&p->rtort_free, &rcu_torture_removed);
|
| 406 | list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
|
| 407 | i = rp->rtort_pipe_count;
|
| 408 | if (i > RCU_TORTURE_PIPE_LEN)
|
| 409 | i = RCU_TORTURE_PIPE_LEN;
|
| 410 | atomic_inc(&rcu_torture_wcount[i]);
|
| 411 | if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
|
| 412 | rp->rtort_mbtest = 0;
|
| 413 | list_del(&rp->rtort_free);
|
| 414 | rcu_torture_free(rp);
|
| 415 | }
|
| 416 | }
|
| 417 | }
|
| 418 |
|
| 419 | static void rcu_sync_torture_init(void)
|
| 420 | {
|
| 421 | INIT_LIST_HEAD(&rcu_torture_removed);
|
| 422 | }
|
| 423 |
|
| 424 | static struct rcu_torture_ops rcu_sync_ops = {
|
| 425 | .init = rcu_sync_torture_init,
|
| 426 | .cleanup = NULL,
|
| 427 | .readlock = rcu_torture_read_lock,
|
| 428 | .read_delay = rcu_read_delay,
|
| 429 | .readunlock = rcu_torture_read_unlock,
|
| 430 | .completed = rcu_torture_completed,
|
| 431 | .deferred_free = rcu_sync_torture_deferred_free,
|
| 432 | .sync = synchronize_rcu,
|
| 433 | .cb_barrier = NULL,
|
| 434 | .fqs = rcu_force_quiescent_state,
|
| 435 | .stats = NULL,
|
| 436 | .irq_capable = 1,
|
| 437 | .can_boost = rcu_can_boost(),
|
| 438 | .name = "rcu_sync"
|
| 439 | };
|
| 440 |
|
| 441 | static struct rcu_torture_ops rcu_expedited_ops = {
|
| 442 | .init = rcu_sync_torture_init,
|
| 443 | .cleanup = NULL,
|
| 444 | .readlock = rcu_torture_read_lock,
|
| 445 | .read_delay = rcu_read_delay,
|
| 446 | .readunlock = rcu_torture_read_unlock,
|
| 447 | .completed = rcu_no_completed,
|
| 448 | .deferred_free = rcu_sync_torture_deferred_free,
|
| 449 | .sync = synchronize_rcu_expedited,
|
| 450 | .cb_barrier = NULL,
|
| 451 | .fqs = rcu_force_quiescent_state,
|
| 452 | .stats = NULL,
|
| 453 | .irq_capable = 1,
|
| 454 | .can_boost = rcu_can_boost(),
|
| 455 | .name = "rcu_expedited"
|
| 456 | };
|
| 457 |
|
| 458 | |
| 459 | * Definitions for rcu_bh torture testing.
|
| 460 |
|
| 461 |
|
| 462 | static int rcu_bh_torture_read_lock(void) __acquires(RCU_BH)
|
| 463 | {
|
| 464 | rcu_read_lock_bh();
|
| 465 | return 0;
|
| 466 | }
|
| 467 |
|
| 468 | static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH)
|
| 469 | {
|
| 470 | rcu_read_unlock_bh();
|
| 471 | }
|
| 472 |
|
| 473 | static int rcu_bh_torture_completed(void)
|
| 474 | {
|
| 475 | return rcu_batches_completed_bh();
|
| 476 | }
|
| 477 |
|
| 478 | static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
|
| 479 | {
|
| 480 | call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
|
| 481 | }
|
| 482 |
|
| 483 | struct rcu_bh_torture_synchronize {
|
| 484 | struct rcu_head head;
|
| 485 | struct completion completion;
|
| 486 | };
|
| 487 |
|
| 488 | static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head)
|
| 489 | {
|
| 490 | struct rcu_bh_torture_synchronize *rcu;
|
| 491 |
|
| 492 | rcu = container_of(head, struct rcu_bh_torture_synchronize, head);
|
| 493 | complete(&rcu->completion);
|
| 494 | }
|
| 495 |
|
| 496 | static void rcu_bh_torture_synchronize(void)
|
| 497 | {
|
| 498 | struct rcu_bh_torture_synchronize rcu;
|
| 499 |
|
| 500 | init_rcu_head_on_stack(&rcu.head);
|
| 501 | init_completion(&rcu.completion);
|
| 502 | call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
|
| 503 | wait_for_completion(&rcu.completion);
|
| 504 | destroy_rcu_head_on_stack(&rcu.head);
|
| 505 | }
|
| 506 |
|
| 507 | static struct rcu_torture_ops rcu_bh_ops = {
|
| 508 | .init = NULL,
|
| 509 | .cleanup = NULL,
|
| 510 | .readlock = rcu_bh_torture_read_lock,
|
| 511 | .read_delay = rcu_read_delay,
|
| 512 | .readunlock = rcu_bh_torture_read_unlock,
|
| 513 | .completed = rcu_bh_torture_completed,
|
| 514 | .deferred_free = rcu_bh_torture_deferred_free,
|
| 515 | .sync = rcu_bh_torture_synchronize,
|
| 516 | .cb_barrier = rcu_barrier_bh,
|
| 517 | .fqs = rcu_bh_force_quiescent_state,
|
| 518 | .stats = NULL,
|
| 519 | .irq_capable = 1,
|
| 520 | .name = "rcu_bh"
|
| 521 | };
|
| 522 |
|
| 523 | static struct rcu_torture_ops rcu_bh_sync_ops = {
|
| 524 | .init = rcu_sync_torture_init,
|
| 525 | .cleanup = NULL,
|
| 526 | .readlock = rcu_bh_torture_read_lock,
|
| 527 | .read_delay = rcu_read_delay,
|
| 528 | .readunlock = rcu_bh_torture_read_unlock,
|
| 529 | .completed = rcu_bh_torture_completed,
|
| 530 | .deferred_free = rcu_sync_torture_deferred_free,
|
| 531 | .sync = rcu_bh_torture_synchronize,
|
| 532 | .cb_barrier = NULL,
|
| 533 | .fqs = rcu_bh_force_quiescent_state,
|
| 534 | .stats = NULL,
|
| 535 | .irq_capable = 1,
|
| 536 | .name = "rcu_bh_sync"
|
| 537 | };
|
| 538 |
|
| 539 | |
| 540 | * Definitions for srcu torture testing.
|
| 541 |
|
| 542 |
|
| 543 | static struct srcu_struct srcu_ctl;
|
| 544 |
|
| 545 | static void srcu_torture_init(void)
|
| 546 | {
|
| 547 | init_srcu_struct(&srcu_ctl);
|
| 548 | rcu_sync_torture_init();
|
| 549 | }
|
| 550 |
|
| 551 | static void srcu_torture_cleanup(void)
|
| 552 | {
|
| 553 | synchronize_srcu(&srcu_ctl);
|
| 554 | cleanup_srcu_struct(&srcu_ctl);
|
| 555 | }
|
| 556 |
|
| 557 | static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
|
| 558 | {
|
| 559 | return srcu_read_lock(&srcu_ctl);
|
| 560 | }
|
| 561 |
|
| 562 | static void srcu_read_delay(struct rcu_random_state *rrsp)
|
| 563 | {
|
| 564 | long delay;
|
| 565 | const long uspertick = 1000000 / HZ;
|
| 566 | const long longdelay = 10;
|
| 567 |
|
| 568 |
|
| 569 |
|
| 570 | delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
|
| 571 | if (!delay)
|
| 572 | schedule_timeout_interruptible(longdelay);
|
| 573 | else
|
| 574 | rcu_read_delay(rrsp);
|
| 575 | }
|
| 576 |
|
| 577 | static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl)
|
| 578 | {
|
| 579 | srcu_read_unlock(&srcu_ctl, idx);
|
| 580 | }
|
| 581 |
|
| 582 | static int srcu_torture_completed(void)
|
| 583 | {
|
| 584 | return srcu_batches_completed(&srcu_ctl);
|
| 585 | }
|
| 586 |
|
| 587 | static void srcu_torture_synchronize(void)
|
| 588 | {
|
| 589 | synchronize_srcu(&srcu_ctl);
|
| 590 | }
|
| 591 |
|
| 592 | static int srcu_torture_stats(char *page)
|
| 593 | {
|
| 594 | int cnt = 0;
|
| 595 | int cpu;
|
| 596 | int idx = srcu_ctl.completed & 0x1;
|
| 597 |
|
| 598 | cnt += sprintf(&page[cnt], "%s%s per-CPU(idx=%d):",
|
| 599 | torture_type, TORTURE_FLAG, idx);
|
| 600 | for_each_possible_cpu(cpu) {
|
| 601 | cnt += sprintf(&page[cnt], " %d(%d,%d)", cpu,
|
| 602 | per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx],
|
| 603 | per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]);
|
| 604 | }
|
| 605 | cnt += sprintf(&page[cnt], "\n");
|
| 606 | return cnt;
|
| 607 | }
|
| 608 |
|
| 609 | static struct rcu_torture_ops srcu_ops = {
|
| 610 | .init = srcu_torture_init,
|
| 611 | .cleanup = srcu_torture_cleanup,
|
| 612 | .readlock = srcu_torture_read_lock,
|
| 613 | .read_delay = srcu_read_delay,
|
| 614 | .readunlock = srcu_torture_read_unlock,
|
| 615 | .completed = srcu_torture_completed,
|
| 616 | .deferred_free = rcu_sync_torture_deferred_free,
|
| 617 | .sync = srcu_torture_synchronize,
|
| 618 | .cb_barrier = NULL,
|
| 619 | .stats = srcu_torture_stats,
|
| 620 | .name = "srcu"
|
| 621 | };
|
| 622 |
|
| 623 | static void srcu_torture_synchronize_expedited(void)
|
| 624 | {
|
| 625 | synchronize_srcu_expedited(&srcu_ctl);
|
| 626 | }
|
| 627 |
|
| 628 | static struct rcu_torture_ops srcu_expedited_ops = {
|
| 629 | .init = srcu_torture_init,
|
| 630 | .cleanup = srcu_torture_cleanup,
|
| 631 | .readlock = srcu_torture_read_lock,
|
| 632 | .read_delay = srcu_read_delay,
|
| 633 | .readunlock = srcu_torture_read_unlock,
|
| 634 | .completed = srcu_torture_completed,
|
| 635 | .deferred_free = rcu_sync_torture_deferred_free,
|
| 636 | .sync = srcu_torture_synchronize_expedited,
|
| 637 | .cb_barrier = NULL,
|
| 638 | .stats = srcu_torture_stats,
|
| 639 | .name = "srcu_expedited"
|
| 640 | };
|
| 641 |
|
| 642 | |
| 643 | * Definitions for sched torture testing.
|
| 644 |
|
| 645 |
|
| 646 | static int sched_torture_read_lock(void)
|
| 647 | {
|
| 648 | preempt_disable();
|
| 649 | return 0;
|
| 650 | }
|
| 651 |
|
| 652 | static void sched_torture_read_unlock(int idx)
|
| 653 | {
|
| 654 | preempt_enable();
|
| 655 | }
|
| 656 |
|
| 657 | static void rcu_sched_torture_deferred_free(struct rcu_torture *p)
|
| 658 | {
|
| 659 | call_rcu_sched(&p->rtort_rcu, rcu_torture_cb);
|
| 660 | }
|
| 661 |
|
| 662 | static void sched_torture_synchronize(void)
|
| 663 | {
|
| 664 | synchronize_sched();
|
| 665 | }
|
| 666 |
|
| 667 | static struct rcu_torture_ops sched_ops = {
|
| 668 | .init = rcu_sync_torture_init,
|
| 669 | .cleanup = NULL,
|
| 670 | .readlock = sched_torture_read_lock,
|
| 671 | .read_delay = rcu_read_delay,
|
| 672 | .readunlock = sched_torture_read_unlock,
|
| 673 | .completed = rcu_no_completed,
|
| 674 | .deferred_free = rcu_sched_torture_deferred_free,
|
| 675 | .sync = sched_torture_synchronize,
|
| 676 | .cb_barrier = rcu_barrier_sched,
|
| 677 | .fqs = rcu_sched_force_quiescent_state,
|
| 678 | .stats = NULL,
|
| 679 | .irq_capable = 1,
|
| 680 | .name = "sched"
|
| 681 | };
|
| 682 |
|
| 683 | static struct rcu_torture_ops sched_sync_ops = {
|
| 684 | .init = rcu_sync_torture_init,
|
| 685 | .cleanup = NULL,
|
| 686 | .readlock = sched_torture_read_lock,
|
| 687 | .read_delay = rcu_read_delay,
|
| 688 | .readunlock = sched_torture_read_unlock,
|
| 689 | .completed = rcu_no_completed,
|
| 690 | .deferred_free = rcu_sync_torture_deferred_free,
|
| 691 | .sync = sched_torture_synchronize,
|
| 692 | .cb_barrier = NULL,
|
| 693 | .fqs = rcu_sched_force_quiescent_state,
|
| 694 | .stats = NULL,
|
| 695 | .name = "sched_sync"
|
| 696 | };
|
| 697 |
|
| 698 | static struct rcu_torture_ops sched_expedited_ops = {
|
| 699 | .init = rcu_sync_torture_init,
|
| 700 | .cleanup = NULL,
|
| 701 | .readlock = sched_torture_read_lock,
|
| 702 | .read_delay = rcu_read_delay,
|
| 703 | .readunlock = sched_torture_read_unlock,
|
| 704 | .completed = rcu_no_completed,
|
| 705 | .deferred_free = rcu_sync_torture_deferred_free,
|
| 706 | .sync = synchronize_sched_expedited,
|
| 707 | .cb_barrier = NULL,
|
| 708 | .fqs = rcu_sched_force_quiescent_state,
|
| 709 | .stats = NULL,
|
| 710 | .irq_capable = 1,
|
| 711 | .name = "sched_expedited"
|
| 712 | };
|
| 713 |
|
| 714 | |
| 715 | * RCU torture priority-boost testing. Runs one real-time thread per
|
| 716 | * CPU for moderate bursts, repeatedly registering RCU callbacks and
|
| 717 | * spinning waiting for them to be invoked. If a given callback takes
|
| 718 | * too long to be invoked, we assume that priority inversion has occurred.
|
| 719 |
|
| 720 |
|
| 721 | struct rcu_boost_inflight {
|
| 722 | struct rcu_head rcu;
|
| 723 | int inflight;
|
| 724 | };
|
| 725 |
|
| 726 | static void rcu_torture_boost_cb(struct rcu_head *head)
|
| 727 | {
|
| 728 | struct rcu_boost_inflight *rbip =
|
| 729 | container_of(head, struct rcu_boost_inflight, rcu);
|
| 730 |
|
| 731 | smp_mb();
|
| 732 | rbip->inflight = 0;
|
| 733 | }
|
| 734 |
|
| 735 | static int rcu_torture_boost(void *arg)
|
| 736 | {
|
| 737 | unsigned long call_rcu_time;
|
| 738 | unsigned long endtime;
|
| 739 | unsigned long oldstarttime;
|
| 740 | struct rcu_boost_inflight rbi = { .inflight = 0 };
|
| 741 | struct sched_param sp;
|
| 742 |
|
| 743 | VERBOSE_PRINTK_STRING("rcu_torture_boost started");
|
| 744 |
|
| 745 |
|
| 746 | sp.sched_priority = 1;
|
| 747 | if (sched_setscheduler(current, SCHED_FIFO, &sp) < 0) {
|
| 748 | VERBOSE_PRINTK_STRING("rcu_torture_boost RT prio failed!");
|
| 749 | n_rcu_torture_boost_rterror++;
|
| 750 | }
|
| 751 |
|
| 752 | init_rcu_head_on_stack(&rbi.rcu);
|
| 753 |
|
| 754 | do {
|
| 755 |
|
| 756 | oldstarttime = boost_starttime;
|
| 757 | while (jiffies - oldstarttime > ULONG_MAX / 2) {
|
| 758 | schedule_timeout_uninterruptible(1);
|
| 759 | rcu_stutter_wait("rcu_torture_boost");
|
| 760 | if (kthread_should_stop() ||
|
| 761 | fullstop != FULLSTOP_DONTSTOP)
|
| 762 | goto checkwait;
|
| 763 | }
|
| 764 |
|
| 765 |
|
| 766 | endtime = oldstarttime + test_boost_duration * HZ;
|
| 767 | call_rcu_time = jiffies;
|
| 768 | while (jiffies - endtime > ULONG_MAX / 2) {
|
| 769 |
|
| 770 | if (!rbi.inflight) {
|
| 771 | smp_mb();
|
| 772 | rbi.inflight = 1;
|
| 773 | call_rcu(&rbi.rcu, rcu_torture_boost_cb);
|
| 774 | if (jiffies - call_rcu_time >
|
| 775 | test_boost_duration * HZ - HZ / 2) {
|
| 776 | VERBOSE_PRINTK_STRING("rcu_torture_boost boosting failed");
|
| 777 | n_rcu_torture_boost_failure++;
|
| 778 | }
|
| 779 | call_rcu_time = jiffies;
|
| 780 | }
|
| 781 | cond_resched();
|
| 782 | rcu_stutter_wait("rcu_torture_boost");
|
| 783 | if (kthread_should_stop() ||
|
| 784 | fullstop != FULLSTOP_DONTSTOP)
|
| 785 | goto checkwait;
|
| 786 | }
|
| 787 |
|
| 788 | |
| 789 | * Set the start time of the next test interval.
|
| 790 | * Yes, this is vulnerable to long delays, but such
|
| 791 | * delays simply cause a false negative for the next
|
| 792 | * interval. Besides, we are running at RT priority,
|
| 793 | * so delays should be relatively rare.
|
| 794 |
|
| 795 | while (oldstarttime == boost_starttime) {
|
| 796 | if (mutex_trylock(&boost_mutex)) {
|
| 797 | boost_starttime = jiffies +
|
| 798 | test_boost_interval * HZ;
|
| 799 | n_rcu_torture_boosts++;
|
| 800 | mutex_unlock(&boost_mutex);
|
| 801 | break;
|
| 802 | }
|
| 803 | schedule_timeout_uninterruptible(1);
|
| 804 | }
|
| 805 |
|
| 806 |
|
| 807 | checkwait: rcu_stutter_wait("rcu_torture_boost");
|
| 808 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
|
| 809 |
|
| 810 |
|
| 811 | VERBOSE_PRINTK_STRING("rcu_torture_boost task stopping");
|
| 812 | destroy_rcu_head_on_stack(&rbi.rcu);
|
| 813 | rcutorture_shutdown_absorb("rcu_torture_boost");
|
| 814 | while (!kthread_should_stop() || rbi.inflight)
|
| 815 | schedule_timeout_uninterruptible(1);
|
| 816 | smp_mb();
|
| 817 | return 0;
|
| 818 | }
|
| 819 |
|
| 820 | |
| 821 | * RCU torture force-quiescent-state kthread. Repeatedly induces
|
| 822 | * bursts of calls to force_quiescent_state(), increasing the probability
|
| 823 | * of occurrence of some important types of race conditions.
|
| 824 |
|
| 825 | static int
|
| 826 | rcu_torture_fqs(void *arg)
|
| 827 | {
|
| 828 | unsigned long fqs_resume_time;
|
| 829 | int fqs_burst_remaining;
|
| 830 |
|
| 831 | VERBOSE_PRINTK_STRING("rcu_torture_fqs task started");
|
| 832 | do {
|
| 833 | fqs_resume_time = jiffies + fqs_stutter * HZ;
|
| 834 | while (jiffies - fqs_resume_time > LONG_MAX) {
|
| 835 | schedule_timeout_interruptible(1);
|
| 836 | }
|
| 837 | fqs_burst_remaining = fqs_duration;
|
| 838 | while (fqs_burst_remaining > 0) {
|
| 839 | cur_ops->fqs();
|
| 840 | udelay(fqs_holdoff);
|
| 841 | fqs_burst_remaining -= fqs_holdoff;
|
| 842 | }
|
| 843 | rcu_stutter_wait("rcu_torture_fqs");
|
| 844 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
|
| 845 | VERBOSE_PRINTK_STRING("rcu_torture_fqs task stopping");
|
| 846 | rcutorture_shutdown_absorb("rcu_torture_fqs");
|
| 847 | while (!kthread_should_stop())
|
| 848 | schedule_timeout_uninterruptible(1);
|
| 849 | return 0;
|
| 850 | }
|
| 851 |
|
| 852 | |
| 853 | * RCU torture writer kthread. Repeatedly substitutes a new structure
|
| 854 | * for that pointed to by rcu_torture_current, freeing the old structure
|
| 855 | * after a series of grace periods (the "pipeline").
|
| 856 |
|
| 857 | static int
|
| 858 | rcu_torture_writer(void *arg)
|
| 859 | {
|
| 860 | int i;
|
| 861 | long oldbatch = rcu_batches_completed();
|
| 862 | struct rcu_torture *rp;
|
| 863 | struct rcu_torture *old_rp;
|
| 864 | static DEFINE_RCU_RANDOM(rand);
|
| 865 |
|
| 866 | VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
|
| 867 | set_user_nice(current, 19);
|
| 868 |
|
| 869 | do {
|
| 870 | schedule_timeout_uninterruptible(1);
|
| 871 | rp = rcu_torture_alloc();
|
| 872 | if (rp == NULL)
|
| 873 | continue;
|
| 874 | rp->rtort_pipe_count = 0;
|
| 875 | udelay(rcu_random(&rand) & 0x3ff);
|
| 876 | old_rp = rcu_dereference_check(rcu_torture_current,
|
| 877 | current == writer_task);
|
| 878 | rp->rtort_mbtest = 1;
|
| 879 | rcu_assign_pointer(rcu_torture_current, rp);
|
| 880 | smp_wmb();
|
| 881 | if (old_rp) {
|
| 882 | i = old_rp->rtort_pipe_count;
|
| 883 | if (i > RCU_TORTURE_PIPE_LEN)
|
| 884 | i = RCU_TORTURE_PIPE_LEN;
|
| 885 | atomic_inc(&rcu_torture_wcount[i]);
|
| 886 | old_rp->rtort_pipe_count++;
|
| 887 | cur_ops->deferred_free(old_rp);
|
| 888 | }
|
| 889 | rcutorture_record_progress(++rcu_torture_current_version);
|
| 890 | oldbatch = cur_ops->completed();
|
| 891 | rcu_stutter_wait("rcu_torture_writer");
|
| 892 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
|
| 893 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
|
| 894 | rcutorture_shutdown_absorb("rcu_torture_writer");
|
| 895 | while (!kthread_should_stop())
|
| 896 | schedule_timeout_uninterruptible(1);
|
| 897 | return 0;
|
| 898 | }
|
| 899 |
|
| 900 | |
| 901 | * RCU torture fake writer kthread. Repeatedly calls sync, with a random
|
| 902 | * delay between calls.
|
| 903 |
|
| 904 | static int
|
| 905 | rcu_torture_fakewriter(void *arg)
|
| 906 | {
|
| 907 | DEFINE_RCU_RANDOM(rand);
|
| 908 |
|
| 909 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
|
| 910 | set_user_nice(current, 19);
|
| 911 |
|
| 912 | do {
|
| 913 | schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
|
| 914 | udelay(rcu_random(&rand) & 0x3ff);
|
| 915 | cur_ops->sync();
|
| 916 | rcu_stutter_wait("rcu_torture_fakewriter");
|
| 917 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
|
| 918 |
|
| 919 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
|
| 920 | rcutorture_shutdown_absorb("rcu_torture_fakewriter");
|
| 921 | while (!kthread_should_stop())
|
| 922 | schedule_timeout_uninterruptible(1);
|
| 923 | return 0;
|
| 924 | }
|
| 925 |
|
| 926 | |
| 927 | * RCU torture reader from timer handler. Dereferences rcu_torture_current,
|
| 928 | * incrementing the corresponding element of the pipeline array. The
|
| 929 | * counter in the element should never be greater than 1, otherwise, the
|
| 930 | * RCU implementation is broken.
|
| 931 |
|
| 932 | static void rcu_torture_timer(unsigned long unused)
|
| 933 | {
|
| 934 | int idx;
|
| 935 | int completed;
|
| 936 | static DEFINE_RCU_RANDOM(rand);
|
| 937 | static DEFINE_SPINLOCK(rand_lock);
|
| 938 | struct rcu_torture *p;
|
| 939 | int pipe_count;
|
| 940 |
|
| 941 | idx = cur_ops->readlock();
|
| 942 | completed = cur_ops->completed();
|
| 943 | p = rcu_dereference_check(rcu_torture_current,
|
| 944 | rcu_read_lock_bh_held() ||
|
| 945 | rcu_read_lock_sched_held() ||
|
| 946 | srcu_read_lock_held(&srcu_ctl));
|
| 947 | if (p == NULL) {
|
| 948 |
|
| 949 | cur_ops->readunlock(idx);
|
| 950 | return;
|
| 951 | }
|
| 952 | if (p->rtort_mbtest == 0)
|
| 953 | atomic_inc(&n_rcu_torture_mberror);
|
| 954 | spin_lock(&rand_lock);
|
| 955 | cur_ops->read_delay(&rand);
|
| 956 | n_rcu_torture_timers++;
|
| 957 | spin_unlock(&rand_lock);
|
| 958 | preempt_disable();
|
| 959 | pipe_count = p->rtort_pipe_count;
|
| 960 | if (pipe_count > RCU_TORTURE_PIPE_LEN) {
|
| 961 |
|
| 962 | pipe_count = RCU_TORTURE_PIPE_LEN;
|
| 963 | }
|
| 964 | __this_cpu_inc(rcu_torture_count[pipe_count]);
|
| 965 | completed = cur_ops->completed() - completed;
|
| 966 | if (completed > RCU_TORTURE_PIPE_LEN) {
|
| 967 |
|
| 968 | completed = RCU_TORTURE_PIPE_LEN;
|
| 969 | }
|
| 970 | __this_cpu_inc(rcu_torture_batch[completed]);
|
| 971 | preempt_enable();
|
| 972 | cur_ops->readunlock(idx);
|
| 973 | }
|
| 974 |
|
| 975 | |
| 976 | * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current,
|
| 977 | * incrementing the corresponding element of the pipeline array. The
|
| 978 | * counter in the element should never be greater than 1, otherwise, the
|
| 979 | * RCU implementation is broken.
|
| 980 |
|
| 981 | static int
|
| 982 | rcu_torture_reader(void *arg)
|
| 983 | {
|
| 984 | int completed;
|
| 985 | int idx;
|
| 986 | DEFINE_RCU_RANDOM(rand);
|
| 987 | struct rcu_torture *p;
|
| 988 | int pipe_count;
|
| 989 | struct timer_list t;
|
| 990 |
|
| 991 | VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
|
| 992 | set_user_nice(current, 19);
|
| 993 | if (irqreader && cur_ops->irq_capable)
|
| 994 | setup_timer_on_stack(&t, rcu_torture_timer, 0);
|
| 995 |
|
| 996 | do {
|
| 997 | if (irqreader && cur_ops->irq_capable) {
|
| 998 | if (!timer_pending(&t))
|
| 999 | mod_timer(&t, jiffies + 1);
|
| 1000 | }
|
| 1001 | idx = cur_ops->readlock();
|
| 1002 | completed = cur_ops->completed();
|
| 1003 | p = rcu_dereference_check(rcu_torture_current,
|
| 1004 | rcu_read_lock_bh_held() ||
|
| 1005 | rcu_read_lock_sched_held() ||
|
| 1006 | srcu_read_lock_held(&srcu_ctl));
|
| 1007 | if (p == NULL) {
|
| 1008 |
|
| 1009 | cur_ops->readunlock(idx);
|
| 1010 | schedule_timeout_interruptible(HZ);
|
| 1011 | continue;
|
| 1012 | }
|
| 1013 | if (p->rtort_mbtest == 0)
|
| 1014 | atomic_inc(&n_rcu_torture_mberror);
|
| 1015 | cur_ops->read_delay(&rand);
|
| 1016 | preempt_disable();
|
| 1017 | pipe_count = p->rtort_pipe_count;
|
| 1018 | if (pipe_count > RCU_TORTURE_PIPE_LEN) {
|
| 1019 |
|
| 1020 | pipe_count = RCU_TORTURE_PIPE_LEN;
|
| 1021 | }
|
| 1022 | __this_cpu_inc(rcu_torture_count[pipe_count]);
|
| 1023 | completed = cur_ops->completed() - completed;
|
| 1024 | if (completed > RCU_TORTURE_PIPE_LEN) {
|
| 1025 |
|
| 1026 | completed = RCU_TORTURE_PIPE_LEN;
|
| 1027 | }
|
| 1028 | __this_cpu_inc(rcu_torture_batch[completed]);
|
| 1029 | preempt_enable();
|
| 1030 | cur_ops->readunlock(idx);
|
| 1031 | schedule();
|
| 1032 | rcu_stutter_wait("rcu_torture_reader");
|
| 1033 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
|
| 1034 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
|
| 1035 | rcutorture_shutdown_absorb("rcu_torture_reader");
|
| 1036 | if (irqreader && cur_ops->irq_capable)
|
| 1037 | del_timer_sync(&t);
|
| 1038 | while (!kthread_should_stop())
|
| 1039 | schedule_timeout_uninterruptible(1);
|
| 1040 | return 0;
|
| 1041 | }
|
| 1042 |
|
| 1043 | |
| 1044 | * Create an RCU-torture statistics message in the specified buffer.
|
| 1045 |
|
| 1046 | static int
|
| 1047 | rcu_torture_printk(char *page)
|
| 1048 | {
|
| 1049 | int cnt = 0;
|
| 1050 | int cpu;
|
| 1051 | int i;
|
| 1052 | long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
|
| 1053 | long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
|
| 1054 |
|
| 1055 | for_each_possible_cpu(cpu) {
|
| 1056 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
|
| 1057 | pipesummary[i] += per_cpu(rcu_torture_count, cpu)[i];
|
| 1058 | batchsummary[i] += per_cpu(rcu_torture_batch, cpu)[i];
|
| 1059 | }
|
| 1060 | }
|
| 1061 | for (i = RCU_TORTURE_PIPE_LEN - 1; i >= 0; i--) {
|
| 1062 | if (pipesummary[i] != 0)
|
| 1063 | break;
|
| 1064 | }
|
| 1065 | cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
|
| 1066 | cnt += sprintf(&page[cnt],
|
| 1067 | "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d "
|
| 1068 | "rtmbe: %d rtbke: %ld rtbre: %ld "
|
| 1069 | "rtbf: %ld rtb: %ld nt: %ld",
|
| 1070 | rcu_torture_current,
|
| 1071 | rcu_torture_current_version,
|
| 1072 | list_empty(&rcu_torture_freelist),
|
| 1073 | atomic_read(&n_rcu_torture_alloc),
|
| 1074 | atomic_read(&n_rcu_torture_alloc_fail),
|
| 1075 | atomic_read(&n_rcu_torture_free),
|
| 1076 | atomic_read(&n_rcu_torture_mberror),
|
| 1077 | n_rcu_torture_boost_ktrerror,
|
| 1078 | n_rcu_torture_boost_rterror,
|
| 1079 | n_rcu_torture_boost_failure,
|
| 1080 | n_rcu_torture_boosts,
|
| 1081 | n_rcu_torture_timers);
|
| 1082 | if (atomic_read(&n_rcu_torture_mberror) != 0 ||
|
| 1083 | n_rcu_torture_boost_ktrerror != 0 ||
|
| 1084 | n_rcu_torture_boost_rterror != 0 ||
|
| 1085 | n_rcu_torture_boost_failure != 0)
|
| 1086 | cnt += sprintf(&page[cnt], " !!!");
|
| 1087 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
|
| 1088 | if (i > 1) {
|
| 1089 | cnt += sprintf(&page[cnt], "!!! ");
|
| 1090 | atomic_inc(&n_rcu_torture_error);
|
| 1091 | WARN_ON_ONCE(1);
|
| 1092 | }
|
| 1093 | cnt += sprintf(&page[cnt], "Reader Pipe: ");
|
| 1094 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
|
| 1095 | cnt += sprintf(&page[cnt], " %ld", pipesummary[i]);
|
| 1096 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
|
| 1097 | cnt += sprintf(&page[cnt], "Reader Batch: ");
|
| 1098 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
|
| 1099 | cnt += sprintf(&page[cnt], " %ld", batchsummary[i]);
|
| 1100 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
|
| 1101 | cnt += sprintf(&page[cnt], "Free-Block Circulation: ");
|
| 1102 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
|
| 1103 | cnt += sprintf(&page[cnt], " %d",
|
| 1104 | atomic_read(&rcu_torture_wcount[i]));
|
| 1105 | }
|
| 1106 | cnt += sprintf(&page[cnt], "\n");
|
| 1107 | if (cur_ops->stats)
|
| 1108 | cnt += cur_ops->stats(&page[cnt]);
|
| 1109 | return cnt;
|
| 1110 | }
|
| 1111 |
|
| 1112 | |
| 1113 | * Print torture statistics. Caller must ensure that there is only
|
| 1114 | * one call to this function at a given time!!! This is normally
|
| 1115 | * accomplished by relying on the module system to only have one copy
|
| 1116 | * of the module loaded, and then by giving the rcu_torture_stats
|
| 1117 | * kthread full control (or the init/cleanup functions when rcu_torture_stats
|
| 1118 | * thread is not running).
|
| 1119 |
|
| 1120 | static void
|
| 1121 | rcu_torture_stats_print(void)
|
| 1122 | {
|
| 1123 | int cnt;
|
| 1124 |
|
| 1125 | cnt = rcu_torture_printk(printk_buf);
|
| 1126 | printk(KERN_ALERT "%s", printk_buf);
|
| 1127 | }
|
| 1128 |
|
| 1129 | |
| 1130 | * Periodically prints torture statistics, if periodic statistics printing
|
| 1131 | * was specified via the stat_interval module parameter.
|
| 1132 | *
|
| 1133 | * No need to worry about fullstop here, since this one doesn't reference
|
| 1134 | * volatile state or register callbacks.
|
| 1135 |
|
| 1136 | static int
|
| 1137 | rcu_torture_stats(void *arg)
|
| 1138 | {
|
| 1139 | VERBOSE_PRINTK_STRING("rcu_torture_stats task started");
|
| 1140 | do {
|
| 1141 | schedule_timeout_interruptible(stat_interval * HZ);
|
| 1142 | rcu_torture_stats_print();
|
| 1143 | rcutorture_shutdown_absorb("rcu_torture_stats");
|
| 1144 | } while (!kthread_should_stop());
|
| 1145 | VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
|
| 1146 | return 0;
|
| 1147 | }
|
| 1148 |
|
| 1149 | static int rcu_idle_cpu;
|
| 1150 |
|
| 1151 | |
| 1152 | * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
|
| 1153 |
|
| 1154 | static void rcu_torture_shuffle_tasks(void)
|
| 1155 | {
|
| 1156 | int i;
|
| 1157 |
|
| 1158 | cpumask_setall(shuffle_tmp_mask);
|
| 1159 | get_online_cpus();
|
| 1160 |
|
| 1161 |
|
| 1162 | if (num_online_cpus() == 1) {
|
| 1163 | put_online_cpus();
|
| 1164 | return;
|
| 1165 | }
|
| 1166 |
|
| 1167 | if (rcu_idle_cpu != -1)
|
| 1168 | cpumask_clear_cpu(rcu_idle_cpu, shuffle_tmp_mask);
|
| 1169 |
|
| 1170 | set_cpus_allowed_ptr(current, shuffle_tmp_mask);
|
| 1171 |
|
| 1172 | if (reader_tasks) {
|
| 1173 | for (i = 0; i < nrealreaders; i++)
|
| 1174 | if (reader_tasks[i])
|
| 1175 | set_cpus_allowed_ptr(reader_tasks[i],
|
| 1176 | shuffle_tmp_mask);
|
| 1177 | }
|
| 1178 |
|
| 1179 | if (fakewriter_tasks) {
|
| 1180 | for (i = 0; i < nfakewriters; i++)
|
| 1181 | if (fakewriter_tasks[i])
|
| 1182 | set_cpus_allowed_ptr(fakewriter_tasks[i],
|
| 1183 | shuffle_tmp_mask);
|
| 1184 | }
|
| 1185 |
|
| 1186 | if (writer_task)
|
| 1187 | set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
|
| 1188 |
|
| 1189 | if (stats_task)
|
| 1190 | set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
|
| 1191 |
|
| 1192 | if (rcu_idle_cpu == -1)
|
| 1193 | rcu_idle_cpu = num_online_cpus() - 1;
|
| 1194 | else
|
| 1195 | rcu_idle_cpu--;
|
| 1196 |
|
| 1197 | put_online_cpus();
|
| 1198 | }
|
| 1199 |
|
| 1200 | |
| 1201 | * system to become idle at a time and cut off its timer ticks. This is meant
|
| 1202 | * to test the support for such tickless idle CPU in RCU.
|
| 1203 |
|
| 1204 | static int
|
| 1205 | rcu_torture_shuffle(void *arg)
|
| 1206 | {
|
| 1207 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started");
|
| 1208 | do {
|
| 1209 | schedule_timeout_interruptible(shuffle_interval * HZ);
|
| 1210 | rcu_torture_shuffle_tasks();
|
| 1211 | rcutorture_shutdown_absorb("rcu_torture_shuffle");
|
| 1212 | } while (!kthread_should_stop());
|
| 1213 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
|
| 1214 | return 0;
|
| 1215 | }
|
| 1216 |
|
| 1217 | |
| 1218 | * threads periodically.
|
| 1219 |
|
| 1220 | static int
|
| 1221 | rcu_torture_stutter(void *arg)
|
| 1222 | {
|
| 1223 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task started");
|
| 1224 | do {
|
| 1225 | schedule_timeout_interruptible(stutter * HZ);
|
| 1226 | stutter_pause_test = 1;
|
| 1227 | if (!kthread_should_stop())
|
| 1228 | schedule_timeout_interruptible(stutter * HZ);
|
| 1229 | stutter_pause_test = 0;
|
| 1230 | rcutorture_shutdown_absorb("rcu_torture_stutter");
|
| 1231 | } while (!kthread_should_stop());
|
| 1232 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
|
| 1233 | return 0;
|
| 1234 | }
|
| 1235 |
|
| 1236 | static inline void
|
| 1237 | rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, char *tag)
|
| 1238 | {
|
| 1239 | printk(KERN_ALERT "%s" TORTURE_FLAG
|
| 1240 | "--- %s: nreaders=%d nfakewriters=%d "
|
| 1241 | "stat_interval=%d verbose=%d test_no_idle_hz=%d "
|
| 1242 | "shuffle_interval=%d stutter=%d irqreader=%d "
|
| 1243 | "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d "
|
| 1244 | "test_boost=%d/%d test_boost_interval=%d "
|
| 1245 | "test_boost_duration=%d\n",
|
| 1246 | torture_type, tag, nrealreaders, nfakewriters,
|
| 1247 | stat_interval, verbose, test_no_idle_hz, shuffle_interval,
|
| 1248 | stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter,
|
| 1249 | test_boost, cur_ops->can_boost,
|
| 1250 | test_boost_interval, test_boost_duration);
|
| 1251 | }
|
| 1252 |
|
| 1253 | static struct notifier_block rcutorture_shutdown_nb = {
|
| 1254 | .notifier_call = rcutorture_shutdown_notify,
|
| 1255 | };
|
| 1256 |
|
| 1257 | static void rcutorture_booster_cleanup(int cpu)
|
| 1258 | {
|
| 1259 | struct task_struct *t;
|
| 1260 |
|
| 1261 | if (boost_tasks[cpu] == NULL)
|
| 1262 | return;
|
| 1263 | mutex_lock(&boost_mutex);
|
| 1264 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_boost task");
|
| 1265 | t = boost_tasks[cpu];
|
| 1266 | boost_tasks[cpu] = NULL;
|
| 1267 | mutex_unlock(&boost_mutex);
|
| 1268 |
|
| 1269 |
|
| 1270 | kthread_stop(t);
|
| 1271 | }
|
| 1272 |
|
| 1273 | static int rcutorture_booster_init(int cpu)
|
| 1274 | {
|
| 1275 | int retval;
|
| 1276 |
|
| 1277 | if (boost_tasks[cpu] != NULL)
|
| 1278 | return 0;
|
| 1279 |
|
| 1280 |
|
| 1281 | mutex_lock(&boost_mutex);
|
| 1282 | VERBOSE_PRINTK_STRING("Creating rcu_torture_boost task");
|
| 1283 | boost_tasks[cpu] = kthread_create(rcu_torture_boost, NULL,
|
| 1284 | "rcu_torture_boost");
|
| 1285 | if (IS_ERR(boost_tasks[cpu])) {
|
| 1286 | retval = PTR_ERR(boost_tasks[cpu]);
|
| 1287 | VERBOSE_PRINTK_STRING("rcu_torture_boost task create failed");
|
| 1288 | n_rcu_torture_boost_ktrerror++;
|
| 1289 | boost_tasks[cpu] = NULL;
|
| 1290 | mutex_unlock(&boost_mutex);
|
| 1291 | return retval;
|
| 1292 | }
|
| 1293 | kthread_bind(boost_tasks[cpu], cpu);
|
| 1294 | wake_up_process(boost_tasks[cpu]);
|
| 1295 | mutex_unlock(&boost_mutex);
|
| 1296 | return 0;
|
| 1297 | }
|
| 1298 |
|
| 1299 | static int rcutorture_cpu_notify(struct notifier_block *self,
|
| 1300 | unsigned long action, void *hcpu)
|
| 1301 | {
|
| 1302 | long cpu = (long)hcpu;
|
| 1303 |
|
| 1304 | switch (action) {
|
| 1305 | case CPU_ONLINE:
|
| 1306 | case CPU_DOWN_FAILED:
|
| 1307 | (void)rcutorture_booster_init(cpu);
|
| 1308 | break;
|
| 1309 | case CPU_DOWN_PREPARE:
|
| 1310 | rcutorture_booster_cleanup(cpu);
|
| 1311 | break;
|
| 1312 | default:
|
| 1313 | break;
|
| 1314 | }
|
| 1315 | return NOTIFY_OK;
|
| 1316 | }
|
| 1317 |
|
| 1318 | static struct notifier_block rcutorture_cpu_nb = {
|
| 1319 | .notifier_call = rcutorture_cpu_notify,
|
| 1320 | };
|
| 1321 |
|
| 1322 | static void
|
| 1323 | rcu_torture_cleanup(void)
|
| 1324 | {
|
| 1325 | int i;
|
| 1326 |
|
| 1327 | mutex_lock(&fullstop_mutex);
|
| 1328 | rcutorture_record_test_transition();
|
| 1329 | if (fullstop == FULLSTOP_SHUTDOWN) {
|
| 1330 | printk(KERN_WARNING
|
| 1331 | "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
|
| 1332 | mutex_unlock(&fullstop_mutex);
|
| 1333 | schedule_timeout_uninterruptible(10);
|
| 1334 | if (cur_ops->cb_barrier != NULL)
|
| 1335 | cur_ops->cb_barrier();
|
| 1336 | return;
|
| 1337 | }
|
| 1338 | fullstop = FULLSTOP_RMMOD;
|
| 1339 | mutex_unlock(&fullstop_mutex);
|
| 1340 | unregister_reboot_notifier(&rcutorture_shutdown_nb);
|
| 1341 | if (stutter_task) {
|
| 1342 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
|
| 1343 | kthread_stop(stutter_task);
|
| 1344 | }
|
| 1345 | stutter_task = NULL;
|
| 1346 | if (shuffler_task) {
|
| 1347 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
|
| 1348 | kthread_stop(shuffler_task);
|
| 1349 | free_cpumask_var(shuffle_tmp_mask);
|
| 1350 | }
|
| 1351 | shuffler_task = NULL;
|
| 1352 |
|
| 1353 | if (writer_task) {
|
| 1354 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
|
| 1355 | kthread_stop(writer_task);
|
| 1356 | }
|
| 1357 | writer_task = NULL;
|
| 1358 |
|
| 1359 | if (reader_tasks) {
|
| 1360 | for (i = 0; i < nrealreaders; i++) {
|
| 1361 | if (reader_tasks[i]) {
|
| 1362 | VERBOSE_PRINTK_STRING(
|
| 1363 | "Stopping rcu_torture_reader task");
|
| 1364 | kthread_stop(reader_tasks[i]);
|
| 1365 | }
|
| 1366 | reader_tasks[i] = NULL;
|
| 1367 | }
|
| 1368 | kfree(reader_tasks);
|
| 1369 | reader_tasks = NULL;
|
| 1370 | }
|
| 1371 | rcu_torture_current = NULL;
|
| 1372 |
|
| 1373 | if (fakewriter_tasks) {
|
| 1374 | for (i = 0; i < nfakewriters; i++) {
|
| 1375 | if (fakewriter_tasks[i]) {
|
| 1376 | VERBOSE_PRINTK_STRING(
|
| 1377 | "Stopping rcu_torture_fakewriter task");
|
| 1378 | kthread_stop(fakewriter_tasks[i]);
|
| 1379 | }
|
| 1380 | fakewriter_tasks[i] = NULL;
|
| 1381 | }
|
| 1382 | kfree(fakewriter_tasks);
|
| 1383 | fakewriter_tasks = NULL;
|
| 1384 | }
|
| 1385 |
|
| 1386 | if (stats_task) {
|
| 1387 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
|
| 1388 | kthread_stop(stats_task);
|
| 1389 | }
|
| 1390 | stats_task = NULL;
|
| 1391 |
|
| 1392 | if (fqs_task) {
|
| 1393 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_fqs task");
|
| 1394 | kthread_stop(fqs_task);
|
| 1395 | }
|
| 1396 | fqs_task = NULL;
|
| 1397 | if ((test_boost == 1 && cur_ops->can_boost) ||
|
| 1398 | test_boost == 2) {
|
| 1399 | unregister_cpu_notifier(&rcutorture_cpu_nb);
|
| 1400 | for_each_possible_cpu(i)
|
| 1401 | rcutorture_booster_cleanup(i);
|
| 1402 | }
|
| 1403 |
|
| 1404 |
|
| 1405 |
|
| 1406 | if (cur_ops->cb_barrier != NULL)
|
| 1407 | cur_ops->cb_barrier();
|
| 1408 |
|
| 1409 | rcu_torture_stats_print();
|
| 1410 |
|
| 1411 | if (cur_ops->cleanup)
|
| 1412 | cur_ops->cleanup();
|
| 1413 | if (atomic_read(&n_rcu_torture_error))
|
| 1414 | rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE");
|
| 1415 | else
|
| 1416 | rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
|
| 1417 | }
|
| 1418 |
|
| 1419 | static int __init
|
| 1420 | rcu_torture_init(void)
|
| 1421 | {
|
| 1422 | int i;
|
| 1423 | int cpu;
|
| 1424 | int firsterr = 0;
|
| 1425 | static struct rcu_torture_ops *torture_ops[] =
|
| 1426 | { &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
|
| 1427 | &rcu_bh_ops, &rcu_bh_sync_ops,
|
| 1428 | &srcu_ops, &srcu_expedited_ops,
|
| 1429 | &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
|
| 1430 |
|
| 1431 | mutex_lock(&fullstop_mutex);
|
| 1432 |
|
| 1433 |
|
| 1434 | for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
|
| 1435 | cur_ops = torture_ops[i];
|
| 1436 | if (strcmp(torture_type, cur_ops->name) == 0)
|
| 1437 | break;
|
| 1438 | }
|
| 1439 | if (i == ARRAY_SIZE(torture_ops)) {
|
| 1440 | printk(KERN_ALERT "rcu-torture: invalid torture type: \"%s\"\n",
|
| 1441 | torture_type);
|
| 1442 | printk(KERN_ALERT "rcu-torture types:");
|
| 1443 | for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
|
| 1444 | printk(KERN_ALERT " %s", torture_ops[i]->name);
|
| 1445 | printk(KERN_ALERT "\n");
|
| 1446 | mutex_unlock(&fullstop_mutex);
|
| 1447 | return -EINVAL;
|
| 1448 | }
|
| 1449 | if (cur_ops->fqs == NULL && fqs_duration != 0) {
|
| 1450 | printk(KERN_ALERT "rcu-torture: ->fqs NULL and non-zero "
|
| 1451 | "fqs_duration, fqs disabled.\n");
|
| 1452 | fqs_duration = 0;
|
| 1453 | }
|
| 1454 | if (cur_ops->init)
|
| 1455 | cur_ops->init();
|
| 1456 |
|
| 1457 | if (nreaders >= 0)
|
| 1458 | nrealreaders = nreaders;
|
| 1459 | else
|
| 1460 | nrealreaders = 2 * num_online_cpus();
|
| 1461 | rcu_torture_print_module_parms(cur_ops, "Start of test");
|
| 1462 | fullstop = FULLSTOP_DONTSTOP;
|
| 1463 |
|
| 1464 |
|
| 1465 |
|
| 1466 | INIT_LIST_HEAD(&rcu_torture_freelist);
|
| 1467 | for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) {
|
| 1468 | rcu_tortures[i].rtort_mbtest = 0;
|
| 1469 | list_add_tail(&rcu_tortures[i].rtort_free,
|
| 1470 | &rcu_torture_freelist);
|
| 1471 | }
|
| 1472 |
|
| 1473 |
|
| 1474 |
|
| 1475 | rcu_torture_current = NULL;
|
| 1476 | rcu_torture_current_version = 0;
|
| 1477 | atomic_set(&n_rcu_torture_alloc, 0);
|
| 1478 | atomic_set(&n_rcu_torture_alloc_fail, 0);
|
| 1479 | atomic_set(&n_rcu_torture_free, 0);
|
| 1480 | atomic_set(&n_rcu_torture_mberror, 0);
|
| 1481 | atomic_set(&n_rcu_torture_error, 0);
|
| 1482 | n_rcu_torture_boost_ktrerror = 0;
|
| 1483 | n_rcu_torture_boost_rterror = 0;
|
| 1484 | n_rcu_torture_boost_failure = 0;
|
| 1485 | n_rcu_torture_boosts = 0;
|
| 1486 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++)
|
| 1487 | atomic_set(&rcu_torture_wcount[i], 0);
|
| 1488 | for_each_possible_cpu(cpu) {
|
| 1489 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
|
| 1490 | per_cpu(rcu_torture_count, cpu)[i] = 0;
|
| 1491 | per_cpu(rcu_torture_batch, cpu)[i] = 0;
|
| 1492 | }
|
| 1493 | }
|
| 1494 |
|
| 1495 |
|
| 1496 |
|
| 1497 | VERBOSE_PRINTK_STRING("Creating rcu_torture_writer task");
|
| 1498 | writer_task = kthread_run(rcu_torture_writer, NULL,
|
| 1499 | "rcu_torture_writer");
|
| 1500 | if (IS_ERR(writer_task)) {
|
| 1501 | firsterr = PTR_ERR(writer_task);
|
| 1502 | VERBOSE_PRINTK_ERRSTRING("Failed to create writer");
|
| 1503 | writer_task = NULL;
|
| 1504 | goto unwind;
|
| 1505 | }
|
| 1506 | fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
|
| 1507 | GFP_KERNEL);
|
| 1508 | if (fakewriter_tasks == NULL) {
|
| 1509 | VERBOSE_PRINTK_ERRSTRING("out of memory");
|
| 1510 | firsterr = -ENOMEM;
|
| 1511 | goto unwind;
|
| 1512 | }
|
| 1513 | for (i = 0; i < nfakewriters; i++) {
|
| 1514 | VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
|
| 1515 | fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
|
| 1516 | "rcu_torture_fakewriter");
|
| 1517 | if (IS_ERR(fakewriter_tasks[i])) {
|
| 1518 | firsterr = PTR_ERR(fakewriter_tasks[i]);
|
| 1519 | VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
|
| 1520 | fakewriter_tasks[i] = NULL;
|
| 1521 | goto unwind;
|
| 1522 | }
|
| 1523 | }
|
| 1524 | reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
|
| 1525 | GFP_KERNEL);
|
| 1526 | if (reader_tasks == NULL) {
|
| 1527 | VERBOSE_PRINTK_ERRSTRING("out of memory");
|
| 1528 | firsterr = -ENOMEM;
|
| 1529 | goto unwind;
|
| 1530 | }
|
| 1531 | for (i = 0; i < nrealreaders; i++) {
|
| 1532 | VERBOSE_PRINTK_STRING("Creating rcu_torture_reader task");
|
| 1533 | reader_tasks[i] = kthread_run(rcu_torture_reader, NULL,
|
| 1534 | "rcu_torture_reader");
|
| 1535 | if (IS_ERR(reader_tasks[i])) {
|
| 1536 | firsterr = PTR_ERR(reader_tasks[i]);
|
| 1537 | VERBOSE_PRINTK_ERRSTRING("Failed to create reader");
|
| 1538 | reader_tasks[i] = NULL;
|
| 1539 | goto unwind;
|
| 1540 | }
|
| 1541 | }
|
| 1542 | if (stat_interval > 0) {
|
| 1543 | VERBOSE_PRINTK_STRING("Creating rcu_torture_stats task");
|
| 1544 | stats_task = kthread_run(rcu_torture_stats, NULL,
|
| 1545 | "rcu_torture_stats");
|
| 1546 | if (IS_ERR(stats_task)) {
|
| 1547 | firsterr = PTR_ERR(stats_task);
|
| 1548 | VERBOSE_PRINTK_ERRSTRING("Failed to create stats");
|
| 1549 | stats_task = NULL;
|
| 1550 | goto unwind;
|
| 1551 | }
|
| 1552 | }
|
| 1553 | if (test_no_idle_hz) {
|
| 1554 | rcu_idle_cpu = num_online_cpus() - 1;
|
| 1555 |
|
| 1556 | if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) {
|
| 1557 | firsterr = -ENOMEM;
|
| 1558 | VERBOSE_PRINTK_ERRSTRING("Failed to alloc mask");
|
| 1559 | goto unwind;
|
| 1560 | }
|
| 1561 |
|
| 1562 |
|
| 1563 | shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
|
| 1564 | "rcu_torture_shuffle");
|
| 1565 | if (IS_ERR(shuffler_task)) {
|
| 1566 | free_cpumask_var(shuffle_tmp_mask);
|
| 1567 | firsterr = PTR_ERR(shuffler_task);
|
| 1568 | VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
|
| 1569 | shuffler_task = NULL;
|
| 1570 | goto unwind;
|
| 1571 | }
|
| 1572 | }
|
| 1573 | if (stutter < 0)
|
| 1574 | stutter = 0;
|
| 1575 | if (stutter) {
|
| 1576 |
|
| 1577 | stutter_task = kthread_run(rcu_torture_stutter, NULL,
|
| 1578 | "rcu_torture_stutter");
|
| 1579 | if (IS_ERR(stutter_task)) {
|
| 1580 | firsterr = PTR_ERR(stutter_task);
|
| 1581 | VERBOSE_PRINTK_ERRSTRING("Failed to create stutter");
|
| 1582 | stutter_task = NULL;
|
| 1583 | goto unwind;
|
| 1584 | }
|
| 1585 | }
|
| 1586 | if (fqs_duration < 0)
|
| 1587 | fqs_duration = 0;
|
| 1588 | if (fqs_duration) {
|
| 1589 |
|
| 1590 | fqs_task = kthread_run(rcu_torture_fqs, NULL,
|
| 1591 | "rcu_torture_fqs");
|
| 1592 | if (IS_ERR(fqs_task)) {
|
| 1593 | firsterr = PTR_ERR(fqs_task);
|
| 1594 | VERBOSE_PRINTK_ERRSTRING("Failed to create fqs");
|
| 1595 | fqs_task = NULL;
|
| 1596 | goto unwind;
|
| 1597 | }
|
| 1598 | }
|
| 1599 | if (test_boost_interval < 1)
|
| 1600 | test_boost_interval = 1;
|
| 1601 | if (test_boost_duration < 2)
|
| 1602 | test_boost_duration = 2;
|
| 1603 | if ((test_boost == 1 && cur_ops->can_boost) ||
|
| 1604 | test_boost == 2) {
|
| 1605 | int retval;
|
| 1606 |
|
| 1607 | boost_starttime = jiffies + test_boost_interval * HZ;
|
| 1608 | register_cpu_notifier(&rcutorture_cpu_nb);
|
| 1609 | for_each_possible_cpu(i) {
|
| 1610 | if (cpu_is_offline(i))
|
| 1611 | continue;
|
| 1612 | retval = rcutorture_booster_init(i);
|
| 1613 | if (retval < 0) {
|
| 1614 | firsterr = retval;
|
| 1615 | goto unwind;
|
| 1616 | }
|
| 1617 | }
|
| 1618 | }
|
| 1619 | register_reboot_notifier(&rcutorture_shutdown_nb);
|
| 1620 | rcutorture_record_test_transition();
|
| 1621 | mutex_unlock(&fullstop_mutex);
|
| 1622 | return 0;
|
| 1623 |
|
| 1624 | unwind:
|
| 1625 | mutex_unlock(&fullstop_mutex);
|
| 1626 | rcu_torture_cleanup();
|
| 1627 | return firsterr;
|
| 1628 | }
|
| 1629 |
|
| 1630 | module_init(rcu_torture_init);
|
| 1631 | module_exit(rcu_torture_cleanup);
|