diff options
author | Paul E. McKenney <paulmck@us.ibm.com> | 2006-06-27 05:54:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-27 20:32:40 -0400 |
commit | 72e9bb549280b354311af30640c9433474f3a32c (patch) | |
tree | 5f35cb787f758f29f7853b9e1d96a9e5ab02eaed | |
parent | 29766f1eb3d8d6cfaf1d6623fb4c3f7e5a822fe4 (diff) |
[PATCH] rcutorture: add ops vector and Classic RCU ops
Add an ops vector to rcutorture, and add the ops for Classic RCU. Update
the rcutorture documentation to reflect slight change to the dmesg formats.
Signed-off-by: Paul E. McKenney <paulmck@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | Documentation/RCU/torture.txt | 22 | ||||
-rw-r--r-- | kernel/rcutorture.c | 163 |
2 files changed, 133 insertions, 52 deletions
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index d896685a9100..a4948591607d 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt | |||
@@ -7,7 +7,7 @@ The CONFIG_RCU_TORTURE_TEST config option is available for all RCU | |||
7 | implementations. It creates an rcutorture kernel module that can | 7 | implementations. It creates an rcutorture kernel module that can |
8 | be loaded to run a torture test. The test periodically outputs | 8 | be loaded to run a torture test. The test periodically outputs |
9 | status messages via printk(), which can be examined via the dmesg | 9 | status messages via printk(), which can be examined via the dmesg |
10 | command (perhaps grepping for "rcutorture"). The test is started | 10 | command (perhaps grepping for "torture"). The test is started |
11 | when the module is loaded, and stops when the module is unloaded. | 11 | when the module is loaded, and stops when the module is unloaded. |
12 | 12 | ||
13 | However, actually setting this config option to "y" results in the system | 13 | However, actually setting this config option to "y" results in the system |
@@ -44,6 +44,10 @@ test_no_idle_hz Whether or not to test the ability of RCU to operate in | |||
44 | a kernel that disables the scheduling-clock interrupt to | 44 | a kernel that disables the scheduling-clock interrupt to |
45 | idle CPUs. Boolean parameter, "1" to test, "0" otherwise. | 45 | idle CPUs. Boolean parameter, "1" to test, "0" otherwise. |
46 | 46 | ||
47 | torture_type The type of RCU to test: "rcu" for the rcu_read_lock() | ||
48 | API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu" | ||
49 | for the "srcu_read_lock()" API. | ||
50 | |||
47 | verbose Enable debug printk()s. Default is disabled. | 51 | verbose Enable debug printk()s. Default is disabled. |
48 | 52 | ||
49 | 53 | ||
@@ -51,14 +55,14 @@ OUTPUT | |||
51 | 55 | ||
52 | The statistics output is as follows: | 56 | The statistics output is as follows: |
53 | 57 | ||
54 | rcutorture: --- Start of test: nreaders=16 stat_interval=0 verbose=0 | 58 | rcu-torture: --- Start of test: nreaders=16 stat_interval=0 verbose=0 |
55 | rcutorture: rtc: 0000000000000000 ver: 1916 tfle: 0 rta: 1916 rtaf: 0 rtf: 1915 | 59 | rcu-torture: rtc: 0000000000000000 ver: 1916 tfle: 0 rta: 1916 rtaf: 0 rtf: 1915 |
56 | rcutorture: Reader Pipe: 1466408 9747 0 0 0 0 0 0 0 0 0 | 60 | rcu-torture: Reader Pipe: 1466408 9747 0 0 0 0 0 0 0 0 0 |
57 | rcutorture: Reader Batch: 1464477 11678 0 0 0 0 0 0 0 0 | 61 | rcu-torture: Reader Batch: 1464477 11678 0 0 0 0 0 0 0 0 |
58 | rcutorture: Free-Block Circulation: 1915 1915 1915 1915 1915 1915 1915 1915 1915 1915 0 | 62 | rcu-torture: Free-Block Circulation: 1915 1915 1915 1915 1915 1915 1915 1915 1915 1915 0 |
59 | rcutorture: --- End of test | 63 | rcu-torture: --- End of test |
60 | 64 | ||
61 | The command "dmesg | grep rcutorture:" will extract this information on | 65 | The command "dmesg | grep torture:" will extract this information on |
62 | most systems. On more esoteric configurations, it may be necessary to | 66 | most systems. On more esoteric configurations, it may be necessary to |
63 | use other commands to access the output of the printk()s used by | 67 | use other commands to access the output of the printk()s used by |
64 | the RCU torture test. The printk()s use KERN_ALERT, so they should | 68 | the RCU torture test. The printk()s use KERN_ALERT, so they should |
@@ -124,7 +128,7 @@ The following script may be used to torture RCU: | |||
124 | modprobe rcutorture | 128 | modprobe rcutorture |
125 | sleep 100 | 129 | sleep 100 |
126 | rmmod rcutorture | 130 | rmmod rcutorture |
127 | dmesg | grep rcutorture: | 131 | dmesg | grep torture: |
128 | 132 | ||
129 | The output can be manually inspected for the error flag of "!!!". | 133 | The output can be manually inspected for the error flag of "!!!". |
130 | One could of course create a more elaborate script that automatically | 134 | One could of course create a more elaborate script that automatically |
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 2a65bd8a3d10..c96b5edd6ed1 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -53,6 +53,7 @@ static int stat_interval; /* Interval between stats, in seconds. */ | |||
53 | static int verbose; /* Print more debug info. */ | 53 | static int verbose; /* Print more debug info. */ |
54 | static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ | 54 | static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ |
55 | static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ | 55 | static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ |
56 | static char *torture_type = "rcu"; /* What to torture. */ | ||
56 | 57 | ||
57 | module_param(nreaders, int, 0); | 58 | module_param(nreaders, int, 0); |
58 | MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); | 59 | MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); |
@@ -64,13 +65,16 @@ module_param(test_no_idle_hz, bool, 0); | |||
64 | MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); | 65 | MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); |
65 | module_param(shuffle_interval, int, 0); | 66 | module_param(shuffle_interval, int, 0); |
66 | MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); | 67 | MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); |
67 | #define TORTURE_FLAG "rcutorture: " | 68 | module_param(torture_type, charp, 0); |
69 | MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu)"); | ||
70 | |||
71 | #define TORTURE_FLAG "-torture:" | ||
68 | #define PRINTK_STRING(s) \ | 72 | #define PRINTK_STRING(s) \ |
69 | do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0) | 73 | do { printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0) |
70 | #define VERBOSE_PRINTK_STRING(s) \ | 74 | #define VERBOSE_PRINTK_STRING(s) \ |
71 | do { if (verbose) printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0) | 75 | do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG s "\n", torture_type); } while (0) |
72 | #define VERBOSE_PRINTK_ERRSTRING(s) \ | 76 | #define VERBOSE_PRINTK_ERRSTRING(s) \ |
73 | do { if (verbose) printk(KERN_ALERT TORTURE_FLAG "!!! " s "\n"); } while (0) | 77 | do { if (verbose) printk(KERN_ALERT "%s" TORTURE_FLAG "!!! " s "\n", torture_type); } while (0) |
74 | 78 | ||
75 | static char printk_buf[4096]; | 79 | static char printk_buf[4096]; |
76 | 80 | ||
@@ -139,28 +143,6 @@ rcu_torture_free(struct rcu_torture *p) | |||
139 | spin_unlock_bh(&rcu_torture_lock); | 143 | spin_unlock_bh(&rcu_torture_lock); |
140 | } | 144 | } |
141 | 145 | ||
142 | static void | ||
143 | rcu_torture_cb(struct rcu_head *p) | ||
144 | { | ||
145 | int i; | ||
146 | struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu); | ||
147 | |||
148 | if (fullstop) { | ||
149 | /* Test is ending, just drop callbacks on the floor. */ | ||
150 | /* The next initialization will pick up the pieces. */ | ||
151 | return; | ||
152 | } | ||
153 | i = rp->rtort_pipe_count; | ||
154 | if (i > RCU_TORTURE_PIPE_LEN) | ||
155 | i = RCU_TORTURE_PIPE_LEN; | ||
156 | atomic_inc(&rcu_torture_wcount[i]); | ||
157 | if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) { | ||
158 | rp->rtort_mbtest = 0; | ||
159 | rcu_torture_free(rp); | ||
160 | } else | ||
161 | call_rcu(p, rcu_torture_cb); | ||
162 | } | ||
163 | |||
164 | struct rcu_random_state { | 146 | struct rcu_random_state { |
165 | unsigned long rrs_state; | 147 | unsigned long rrs_state; |
166 | unsigned long rrs_count; | 148 | unsigned long rrs_count; |
@@ -191,6 +173,83 @@ rcu_random(struct rcu_random_state *rrsp) | |||
191 | } | 173 | } |
192 | 174 | ||
193 | /* | 175 | /* |
176 | * Operations vector for selecting different types of tests. | ||
177 | */ | ||
178 | |||
179 | struct rcu_torture_ops { | ||
180 | void (*init)(void); | ||
181 | void (*cleanup)(void); | ||
182 | int (*readlock)(void); | ||
183 | void (*readunlock)(int idx); | ||
184 | int (*completed)(void); | ||
185 | void (*deferredfree)(struct rcu_torture *p); | ||
186 | int (*stats)(char *page); | ||
187 | char *name; | ||
188 | }; | ||
189 | static struct rcu_torture_ops *cur_ops = NULL; | ||
190 | |||
191 | /* | ||
192 | * Definitions for rcu torture testing. | ||
193 | */ | ||
194 | |||
195 | static int rcu_torture_read_lock(void) | ||
196 | { | ||
197 | rcu_read_lock(); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void rcu_torture_read_unlock(int idx) | ||
202 | { | ||
203 | rcu_read_unlock(); | ||
204 | } | ||
205 | |||
206 | static int rcu_torture_completed(void) | ||
207 | { | ||
208 | return rcu_batches_completed(); | ||
209 | } | ||
210 | |||
211 | static void | ||
212 | rcu_torture_cb(struct rcu_head *p) | ||
213 | { | ||
214 | int i; | ||
215 | struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu); | ||
216 | |||
217 | if (fullstop) { | ||
218 | /* Test is ending, just drop callbacks on the floor. */ | ||
219 | /* The next initialization will pick up the pieces. */ | ||
220 | return; | ||
221 | } | ||
222 | i = rp->rtort_pipe_count; | ||
223 | if (i > RCU_TORTURE_PIPE_LEN) | ||
224 | i = RCU_TORTURE_PIPE_LEN; | ||
225 | atomic_inc(&rcu_torture_wcount[i]); | ||
226 | if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) { | ||
227 | rp->rtort_mbtest = 0; | ||
228 | rcu_torture_free(rp); | ||
229 | } else | ||
230 | cur_ops->deferredfree(rp); | ||
231 | } | ||
232 | |||
233 | static void rcu_torture_deferred_free(struct rcu_torture *p) | ||
234 | { | ||
235 | call_rcu(&p->rtort_rcu, rcu_torture_cb); | ||
236 | } | ||
237 | |||
238 | static struct rcu_torture_ops rcu_ops = { | ||
239 | .init = NULL, | ||
240 | .cleanup = NULL, | ||
241 | .readlock = rcu_torture_read_lock, | ||
242 | .readunlock = rcu_torture_read_unlock, | ||
243 | .completed = rcu_torture_completed, | ||
244 | .deferredfree = rcu_torture_deferred_free, | ||
245 | .stats = NULL, | ||
246 | .name = "rcu" | ||
247 | }; | ||
248 | |||
249 | static struct rcu_torture_ops *torture_ops[] = | ||
250 | { &rcu_ops, NULL }; | ||
251 | |||
252 | /* | ||
194 | * RCU torture writer kthread. Repeatedly substitutes a new structure | 253 | * RCU torture writer kthread. Repeatedly substitutes a new structure |
195 | * for that pointed to by rcu_torture_current, freeing the old structure | 254 | * for that pointed to by rcu_torture_current, freeing the old structure |
196 | * after a series of grace periods (the "pipeline"). | 255 | * after a series of grace periods (the "pipeline"). |
@@ -209,8 +268,6 @@ rcu_torture_writer(void *arg) | |||
209 | 268 | ||
210 | do { | 269 | do { |
211 | schedule_timeout_uninterruptible(1); | 270 | schedule_timeout_uninterruptible(1); |
212 | if (rcu_batches_completed() == oldbatch) | ||
213 | continue; | ||
214 | if ((rp = rcu_torture_alloc()) == NULL) | 271 | if ((rp = rcu_torture_alloc()) == NULL) |
215 | continue; | 272 | continue; |
216 | rp->rtort_pipe_count = 0; | 273 | rp->rtort_pipe_count = 0; |
@@ -225,10 +282,10 @@ rcu_torture_writer(void *arg) | |||
225 | i = RCU_TORTURE_PIPE_LEN; | 282 | i = RCU_TORTURE_PIPE_LEN; |
226 | atomic_inc(&rcu_torture_wcount[i]); | 283 | atomic_inc(&rcu_torture_wcount[i]); |
227 | old_rp->rtort_pipe_count++; | 284 | old_rp->rtort_pipe_count++; |
228 | call_rcu(&old_rp->rtort_rcu, rcu_torture_cb); | 285 | cur_ops->deferredfree(old_rp); |
229 | } | 286 | } |
230 | rcu_torture_current_version++; | 287 | rcu_torture_current_version++; |
231 | oldbatch = rcu_batches_completed(); | 288 | oldbatch = cur_ops->completed(); |
232 | } while (!kthread_should_stop() && !fullstop); | 289 | } while (!kthread_should_stop() && !fullstop); |
233 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); | 290 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); |
234 | while (!kthread_should_stop()) | 291 | while (!kthread_should_stop()) |
@@ -246,6 +303,7 @@ static int | |||
246 | rcu_torture_reader(void *arg) | 303 | rcu_torture_reader(void *arg) |
247 | { | 304 | { |
248 | int completed; | 305 | int completed; |
306 | int idx; | ||
249 | DEFINE_RCU_RANDOM(rand); | 307 | DEFINE_RCU_RANDOM(rand); |
250 | struct rcu_torture *p; | 308 | struct rcu_torture *p; |
251 | int pipe_count; | 309 | int pipe_count; |
@@ -254,12 +312,12 @@ rcu_torture_reader(void *arg) | |||
254 | set_user_nice(current, 19); | 312 | set_user_nice(current, 19); |
255 | 313 | ||
256 | do { | 314 | do { |
257 | rcu_read_lock(); | 315 | idx = cur_ops->readlock(); |
258 | completed = rcu_batches_completed(); | 316 | completed = cur_ops->completed(); |
259 | p = rcu_dereference(rcu_torture_current); | 317 | p = rcu_dereference(rcu_torture_current); |
260 | if (p == NULL) { | 318 | if (p == NULL) { |
261 | /* Wait for rcu_torture_writer to get underway */ | 319 | /* Wait for rcu_torture_writer to get underway */ |
262 | rcu_read_unlock(); | 320 | cur_ops->readunlock(idx); |
263 | schedule_timeout_interruptible(HZ); | 321 | schedule_timeout_interruptible(HZ); |
264 | continue; | 322 | continue; |
265 | } | 323 | } |
@@ -273,14 +331,14 @@ rcu_torture_reader(void *arg) | |||
273 | pipe_count = RCU_TORTURE_PIPE_LEN; | 331 | pipe_count = RCU_TORTURE_PIPE_LEN; |
274 | } | 332 | } |
275 | ++__get_cpu_var(rcu_torture_count)[pipe_count]; | 333 | ++__get_cpu_var(rcu_torture_count)[pipe_count]; |
276 | completed = rcu_batches_completed() - completed; | 334 | completed = cur_ops->completed() - completed; |
277 | if (completed > RCU_TORTURE_PIPE_LEN) { | 335 | if (completed > RCU_TORTURE_PIPE_LEN) { |
278 | /* Should not happen, but... */ | 336 | /* Should not happen, but... */ |
279 | completed = RCU_TORTURE_PIPE_LEN; | 337 | completed = RCU_TORTURE_PIPE_LEN; |
280 | } | 338 | } |
281 | ++__get_cpu_var(rcu_torture_batch)[completed]; | 339 | ++__get_cpu_var(rcu_torture_batch)[completed]; |
282 | preempt_enable(); | 340 | preempt_enable(); |
283 | rcu_read_unlock(); | 341 | cur_ops->readunlock(idx); |
284 | schedule(); | 342 | schedule(); |
285 | } while (!kthread_should_stop() && !fullstop); | 343 | } while (!kthread_should_stop() && !fullstop); |
286 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); | 344 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); |
@@ -311,7 +369,7 @@ rcu_torture_printk(char *page) | |||
311 | if (pipesummary[i] != 0) | 369 | if (pipesummary[i] != 0) |
312 | break; | 370 | break; |
313 | } | 371 | } |
314 | cnt += sprintf(&page[cnt], "rcutorture: "); | 372 | cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); |
315 | cnt += sprintf(&page[cnt], | 373 | cnt += sprintf(&page[cnt], |
316 | "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " | 374 | "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " |
317 | "rtmbe: %d", | 375 | "rtmbe: %d", |
@@ -324,7 +382,7 @@ rcu_torture_printk(char *page) | |||
324 | atomic_read(&n_rcu_torture_mberror)); | 382 | atomic_read(&n_rcu_torture_mberror)); |
325 | if (atomic_read(&n_rcu_torture_mberror) != 0) | 383 | if (atomic_read(&n_rcu_torture_mberror) != 0) |
326 | cnt += sprintf(&page[cnt], " !!!"); | 384 | cnt += sprintf(&page[cnt], " !!!"); |
327 | cnt += sprintf(&page[cnt], "\nrcutorture: "); | 385 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); |
328 | if (i > 1) { | 386 | if (i > 1) { |
329 | cnt += sprintf(&page[cnt], "!!! "); | 387 | cnt += sprintf(&page[cnt], "!!! "); |
330 | atomic_inc(&n_rcu_torture_error); | 388 | atomic_inc(&n_rcu_torture_error); |
@@ -332,17 +390,19 @@ rcu_torture_printk(char *page) | |||
332 | cnt += sprintf(&page[cnt], "Reader Pipe: "); | 390 | cnt += sprintf(&page[cnt], "Reader Pipe: "); |
333 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) | 391 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) |
334 | cnt += sprintf(&page[cnt], " %ld", pipesummary[i]); | 392 | cnt += sprintf(&page[cnt], " %ld", pipesummary[i]); |
335 | cnt += sprintf(&page[cnt], "\nrcutorture: "); | 393 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); |
336 | cnt += sprintf(&page[cnt], "Reader Batch: "); | 394 | cnt += sprintf(&page[cnt], "Reader Batch: "); |
337 | for (i = 0; i < RCU_TORTURE_PIPE_LEN; i++) | 395 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) |
338 | cnt += sprintf(&page[cnt], " %ld", batchsummary[i]); | 396 | cnt += sprintf(&page[cnt], " %ld", batchsummary[i]); |
339 | cnt += sprintf(&page[cnt], "\nrcutorture: "); | 397 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); |
340 | cnt += sprintf(&page[cnt], "Free-Block Circulation: "); | 398 | cnt += sprintf(&page[cnt], "Free-Block Circulation: "); |
341 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) { | 399 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) { |
342 | cnt += sprintf(&page[cnt], " %d", | 400 | cnt += sprintf(&page[cnt], " %d", |
343 | atomic_read(&rcu_torture_wcount[i])); | 401 | atomic_read(&rcu_torture_wcount[i])); |
344 | } | 402 | } |
345 | cnt += sprintf(&page[cnt], "\n"); | 403 | cnt += sprintf(&page[cnt], "\n"); |
404 | if (cur_ops->stats != NULL) | ||
405 | cnt += cur_ops->stats(&page[cnt]); | ||
346 | return cnt; | 406 | return cnt; |
347 | } | 407 | } |
348 | 408 | ||
@@ -444,11 +504,11 @@ rcu_torture_shuffle(void *arg) | |||
444 | static inline void | 504 | static inline void |
445 | rcu_torture_print_module_parms(char *tag) | 505 | rcu_torture_print_module_parms(char *tag) |
446 | { | 506 | { |
447 | printk(KERN_ALERT TORTURE_FLAG "--- %s: nreaders=%d " | 507 | printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d " |
448 | "stat_interval=%d verbose=%d test_no_idle_hz=%d " | 508 | "stat_interval=%d verbose=%d test_no_idle_hz=%d " |
449 | "shuffle_interval = %d\n", | 509 | "shuffle_interval = %d\n", |
450 | tag, nrealreaders, stat_interval, verbose, test_no_idle_hz, | 510 | torture_type, tag, nrealreaders, stat_interval, verbose, |
451 | shuffle_interval); | 511 | test_no_idle_hz, shuffle_interval); |
452 | } | 512 | } |
453 | 513 | ||
454 | static void | 514 | static void |
@@ -493,6 +553,9 @@ rcu_torture_cleanup(void) | |||
493 | rcu_barrier(); | 553 | rcu_barrier(); |
494 | 554 | ||
495 | rcu_torture_stats_print(); /* -After- the stats thread is stopped! */ | 555 | rcu_torture_stats_print(); /* -After- the stats thread is stopped! */ |
556 | |||
557 | if (cur_ops->cleanup != NULL) | ||
558 | cur_ops->cleanup(); | ||
496 | if (atomic_read(&n_rcu_torture_error)) | 559 | if (atomic_read(&n_rcu_torture_error)) |
497 | rcu_torture_print_module_parms("End of test: FAILURE"); | 560 | rcu_torture_print_module_parms("End of test: FAILURE"); |
498 | else | 561 | else |
@@ -508,6 +571,20 @@ rcu_torture_init(void) | |||
508 | 571 | ||
509 | /* Process args and tell the world that the torturer is on the job. */ | 572 | /* Process args and tell the world that the torturer is on the job. */ |
510 | 573 | ||
574 | for (i = 0; cur_ops = torture_ops[i], cur_ops != NULL; i++) { | ||
575 | cur_ops = torture_ops[i]; | ||
576 | if (strcmp(torture_type, cur_ops->name) == 0) { | ||
577 | break; | ||
578 | } | ||
579 | } | ||
580 | if (cur_ops == NULL) { | ||
581 | printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n", | ||
582 | torture_type); | ||
583 | return (-EINVAL); | ||
584 | } | ||
585 | if (cur_ops->init != NULL) | ||
586 | cur_ops->init(); /* no "goto unwind" prior to this point!!! */ | ||
587 | |||
511 | if (nreaders >= 0) | 588 | if (nreaders >= 0) |
512 | nrealreaders = nreaders; | 589 | nrealreaders = nreaders; |
513 | else | 590 | else |