diff options
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r-- | kernel/rcutorture.c | 47 |
1 files changed, 25 insertions, 22 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index b33db539a8ad..697c0a0229d4 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -18,7 +18,7 @@ | |||
18 | * Copyright (C) IBM Corporation, 2005, 2006 | 18 | * Copyright (C) IBM Corporation, 2005, 2006 |
19 | * | 19 | * |
20 | * Authors: Paul E. McKenney <paulmck@us.ibm.com> | 20 | * Authors: Paul E. McKenney <paulmck@us.ibm.com> |
21 | * Josh Triplett <josh@freedesktop.org> | 21 | * Josh Triplett <josh@freedesktop.org> |
22 | * | 22 | * |
23 | * See also: Documentation/RCU/torture.txt | 23 | * See also: Documentation/RCU/torture.txt |
24 | */ | 24 | */ |
@@ -50,7 +50,7 @@ | |||
50 | 50 | ||
51 | MODULE_LICENSE("GPL"); | 51 | MODULE_LICENSE("GPL"); |
52 | MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and " | 52 | MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and " |
53 | "Josh Triplett <josh@freedesktop.org>"); | 53 | "Josh Triplett <josh@freedesktop.org>"); |
54 | 54 | ||
55 | static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */ | 55 | static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */ |
56 | static int nfakewriters = 4; /* # fake writer threads */ | 56 | static int nfakewriters = 4; /* # fake writer threads */ |
@@ -110,8 +110,8 @@ struct rcu_torture { | |||
110 | }; | 110 | }; |
111 | 111 | ||
112 | static LIST_HEAD(rcu_torture_freelist); | 112 | static LIST_HEAD(rcu_torture_freelist); |
113 | static struct rcu_torture *rcu_torture_current = NULL; | 113 | static struct rcu_torture *rcu_torture_current; |
114 | static long rcu_torture_current_version = 0; | 114 | static long rcu_torture_current_version; |
115 | static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN]; | 115 | static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN]; |
116 | static DEFINE_SPINLOCK(rcu_torture_lock); | 116 | static DEFINE_SPINLOCK(rcu_torture_lock); |
117 | static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) = | 117 | static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) = |
@@ -124,11 +124,11 @@ static atomic_t n_rcu_torture_alloc_fail; | |||
124 | static atomic_t n_rcu_torture_free; | 124 | static atomic_t n_rcu_torture_free; |
125 | static atomic_t n_rcu_torture_mberror; | 125 | static atomic_t n_rcu_torture_mberror; |
126 | static atomic_t n_rcu_torture_error; | 126 | static atomic_t n_rcu_torture_error; |
127 | static long n_rcu_torture_timers = 0; | 127 | static long n_rcu_torture_timers; |
128 | static struct list_head rcu_torture_removed; | 128 | static struct list_head rcu_torture_removed; |
129 | static cpumask_var_t shuffle_tmp_mask; | 129 | static cpumask_var_t shuffle_tmp_mask; |
130 | 130 | ||
131 | static int stutter_pause_test = 0; | 131 | static int stutter_pause_test; |
132 | 132 | ||
133 | #if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE) | 133 | #if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE) |
134 | #define RCUTORTURE_RUNNABLE_INIT 1 | 134 | #define RCUTORTURE_RUNNABLE_INIT 1 |
@@ -267,7 +267,8 @@ struct rcu_torture_ops { | |||
267 | int irq_capable; | 267 | int irq_capable; |
268 | char *name; | 268 | char *name; |
269 | }; | 269 | }; |
270 | static struct rcu_torture_ops *cur_ops = NULL; | 270 | |
271 | static struct rcu_torture_ops *cur_ops; | ||
271 | 272 | ||
272 | /* | 273 | /* |
273 | * Definitions for rcu torture testing. | 274 | * Definitions for rcu torture testing. |
@@ -281,14 +282,17 @@ static int rcu_torture_read_lock(void) __acquires(RCU) | |||
281 | 282 | ||
282 | static void rcu_read_delay(struct rcu_random_state *rrsp) | 283 | static void rcu_read_delay(struct rcu_random_state *rrsp) |
283 | { | 284 | { |
284 | long delay; | 285 | const unsigned long shortdelay_us = 200; |
285 | const long longdelay = 200; | 286 | const unsigned long longdelay_ms = 50; |
286 | 287 | ||
287 | /* We want there to be long-running readers, but not all the time. */ | 288 | /* We want a short delay sometimes to make a reader delay the grace |
289 | * period, and we want a long delay occasionally to trigger | ||
290 | * force_quiescent_state. */ | ||
288 | 291 | ||
289 | delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay); | 292 | if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms))) |
290 | if (!delay) | 293 | mdelay(longdelay_ms); |
291 | udelay(longdelay); | 294 | if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us))) |
295 | udelay(shortdelay_us); | ||
292 | } | 296 | } |
293 | 297 | ||
294 | static void rcu_torture_read_unlock(int idx) __releases(RCU) | 298 | static void rcu_torture_read_unlock(int idx) __releases(RCU) |
@@ -339,8 +343,8 @@ static struct rcu_torture_ops rcu_ops = { | |||
339 | .sync = synchronize_rcu, | 343 | .sync = synchronize_rcu, |
340 | .cb_barrier = rcu_barrier, | 344 | .cb_barrier = rcu_barrier, |
341 | .stats = NULL, | 345 | .stats = NULL, |
342 | .irq_capable = 1, | 346 | .irq_capable = 1, |
343 | .name = "rcu" | 347 | .name = "rcu" |
344 | }; | 348 | }; |
345 | 349 | ||
346 | static void rcu_sync_torture_deferred_free(struct rcu_torture *p) | 350 | static void rcu_sync_torture_deferred_free(struct rcu_torture *p) |
@@ -602,8 +606,6 @@ static struct rcu_torture_ops sched_ops_sync = { | |||
602 | .name = "sched_sync" | 606 | .name = "sched_sync" |
603 | }; | 607 | }; |
604 | 608 | ||
605 | extern int rcu_expedited_torture_stats(char *page); | ||
606 | |||
607 | static struct rcu_torture_ops sched_expedited_ops = { | 609 | static struct rcu_torture_ops sched_expedited_ops = { |
608 | .init = rcu_sync_torture_init, | 610 | .init = rcu_sync_torture_init, |
609 | .cleanup = NULL, | 611 | .cleanup = NULL, |
@@ -638,14 +640,15 @@ rcu_torture_writer(void *arg) | |||
638 | 640 | ||
639 | do { | 641 | do { |
640 | schedule_timeout_uninterruptible(1); | 642 | schedule_timeout_uninterruptible(1); |
641 | if ((rp = rcu_torture_alloc()) == NULL) | 643 | rp = rcu_torture_alloc(); |
644 | if (rp == NULL) | ||
642 | continue; | 645 | continue; |
643 | rp->rtort_pipe_count = 0; | 646 | rp->rtort_pipe_count = 0; |
644 | udelay(rcu_random(&rand) & 0x3ff); | 647 | udelay(rcu_random(&rand) & 0x3ff); |
645 | old_rp = rcu_torture_current; | 648 | old_rp = rcu_torture_current; |
646 | rp->rtort_mbtest = 1; | 649 | rp->rtort_mbtest = 1; |
647 | rcu_assign_pointer(rcu_torture_current, rp); | 650 | rcu_assign_pointer(rcu_torture_current, rp); |
648 | smp_wmb(); | 651 | smp_wmb(); /* Mods to old_rp must follow rcu_assign_pointer() */ |
649 | if (old_rp) { | 652 | if (old_rp) { |
650 | i = old_rp->rtort_pipe_count; | 653 | i = old_rp->rtort_pipe_count; |
651 | if (i > RCU_TORTURE_PIPE_LEN) | 654 | if (i > RCU_TORTURE_PIPE_LEN) |
@@ -1110,7 +1113,7 @@ rcu_torture_init(void) | |||
1110 | printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n", | 1113 | printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n", |
1111 | torture_type); | 1114 | torture_type); |
1112 | mutex_unlock(&fullstop_mutex); | 1115 | mutex_unlock(&fullstop_mutex); |
1113 | return (-EINVAL); | 1116 | return -EINVAL; |
1114 | } | 1117 | } |
1115 | if (cur_ops->init) | 1118 | if (cur_ops->init) |
1116 | cur_ops->init(); /* no "goto unwind" prior to this point!!! */ | 1119 | cur_ops->init(); /* no "goto unwind" prior to this point!!! */ |
@@ -1161,7 +1164,7 @@ rcu_torture_init(void) | |||
1161 | goto unwind; | 1164 | goto unwind; |
1162 | } | 1165 | } |
1163 | fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]), | 1166 | fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]), |
1164 | GFP_KERNEL); | 1167 | GFP_KERNEL); |
1165 | if (fakewriter_tasks == NULL) { | 1168 | if (fakewriter_tasks == NULL) { |
1166 | VERBOSE_PRINTK_ERRSTRING("out of memory"); | 1169 | VERBOSE_PRINTK_ERRSTRING("out of memory"); |
1167 | firsterr = -ENOMEM; | 1170 | firsterr = -ENOMEM; |
@@ -1170,7 +1173,7 @@ rcu_torture_init(void) | |||
1170 | for (i = 0; i < nfakewriters; i++) { | 1173 | for (i = 0; i < nfakewriters; i++) { |
1171 | VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task"); | 1174 | VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task"); |
1172 | fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL, | 1175 | fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL, |
1173 | "rcu_torture_fakewriter"); | 1176 | "rcu_torture_fakewriter"); |
1174 | if (IS_ERR(fakewriter_tasks[i])) { | 1177 | if (IS_ERR(fakewriter_tasks[i])) { |
1175 | firsterr = PTR_ERR(fakewriter_tasks[i]); | 1178 | firsterr = PTR_ERR(fakewriter_tasks[i]); |
1176 | VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter"); | 1179 | VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter"); |