]> git.proxmox.com Git - mirror_zfs.git/blame - cmd/raidz_test/raidz_test.c
Add CONTRIBUTING information and templates
[mirror_zfs.git] / cmd / raidz_test / raidz_test.c
CommitLineData
ab9f4b0b
GN
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (C) 2016 Gvozden Nešković. All rights reserved.
24 */
25
26#include <sys/zfs_context.h>
27#include <sys/time.h>
28#include <sys/wait.h>
29#include <sys/zio.h>
30#include <umem.h>
31#include <sys/vdev_raidz.h>
32#include <sys/vdev_raidz_impl.h>
33#include <assert.h>
34#include <stdio.h>
35#include "raidz_test.h"
36
37static int *rand_data;
38raidz_test_opts_t rto_opts;
39
40static char gdb[256];
41static const char gdb_tmpl[] = "gdb -ex \"set pagination 0\" -p %d";
42
43static void sig_handler(int signo)
44{
45 struct sigaction action;
46 /*
47 * Restore default action and re-raise signal so SIGSEGV and
48 * SIGABRT can trigger a core dump.
49 */
50 action.sa_handler = SIG_DFL;
51 sigemptyset(&action.sa_mask);
52 action.sa_flags = 0;
53 (void) sigaction(signo, &action, NULL);
54
55 if (rto_opts.rto_gdb)
56 if (system(gdb));
57
58 raise(signo);
59}
60
61static void print_opts(raidz_test_opts_t *opts, boolean_t force)
62{
63 char *verbose;
64 switch (opts->rto_v) {
65 case 0:
66 verbose = "no";
67 break;
68 case 1:
69 verbose = "info";
70 break;
71 default:
72 verbose = "debug";
73 break;
74 }
75
76 if (force || opts->rto_v >= D_INFO) {
77 (void) fprintf(stdout, DBLSEP "Running with options:\n"
78 " (-a) zio ashift : %zu\n"
79 " (-o) zio offset : 1 << %zu\n"
80 " (-d) number of raidz data columns : %zu\n"
81 " (-s) size of DATA : 1 << %zu\n"
82 " (-S) sweep parameters : %s \n"
83 " (-v) verbose : %s \n\n",
84 opts->rto_ashift, /* -a */
85 ilog2(opts->rto_offset), /* -o */
86 opts->rto_dcols, /* -d */
87 ilog2(opts->rto_dsize), /* -s */
88 opts->rto_sweep ? "yes" : "no", /* -S */
89 verbose /* -v */
90 );
91 }
92}
93
94static void usage(boolean_t requested)
95{
96 const raidz_test_opts_t *o = &rto_opts_defaults;
97
98 FILE *fp = requested ? stdout : stderr;
99
100 (void) fprintf(fp, "Usage:\n"
101 "\t[-a zio ashift (default: %zu)]\n"
102 "\t[-o zio offset, exponent radix 2 (default: %zu)]\n"
103 "\t[-d number of raidz data columns (default: %zu)]\n"
104 "\t[-s zio size, exponent radix 2 (default: %zu)]\n"
105 "\t[-S parameter sweep (default: %s)]\n"
106 "\t[-t timeout for parameter sweep test]\n"
107 "\t[-B benchmark all raidz implementations]\n"
108 "\t[-v increase verbosity (default: %zu)]\n"
109 "\t[-h (print help)]\n"
110 "\t[-T test the test, see if failure would be detected]\n"
111 "\t[-D debug (attach gdb on SIGSEGV)]\n"
112 "",
113 o->rto_ashift, /* -a */
114 ilog2(o->rto_offset), /* -o */
115 o->rto_dcols, /* -d */
116 ilog2(o->rto_dsize), /* -s */
117 rto_opts.rto_sweep ? "yes" : "no", /* -S */
118 o->rto_v /* -d */
119 );
120
121 exit(requested ? 0 : 1);
122}
123
124static void process_options(int argc, char **argv)
125{
126 size_t value;
127 int opt;
128
129 raidz_test_opts_t *o = &rto_opts;
130
131 bcopy(&rto_opts_defaults, o, sizeof (*o));
132
133 while ((opt = getopt(argc, argv, "TDBSvha:o:d:s:t:")) != -1) {
134 value = 0;
135
136 switch (opt) {
137 case 'a':
138 value = strtoull(optarg, NULL, 0);
139 o->rto_ashift = MIN(13, MAX(9, value));
140 break;
141 case 'o':
142 value = strtoull(optarg, NULL, 0);
143 o->rto_offset = ((1ULL << MIN(12, value)) >> 9) << 9;
144 break;
145 case 'd':
146 value = strtoull(optarg, NULL, 0);
147 o->rto_dcols = MIN(255, MAX(1, value));
148 break;
149 case 's':
150 value = strtoull(optarg, NULL, 0);
151 o->rto_dsize = 1ULL << MIN(SPA_MAXBLOCKSHIFT,
152 MAX(SPA_MINBLOCKSHIFT, value));
153 break;
154 case 't':
155 value = strtoull(optarg, NULL, 0);
156 o->rto_sweep_timeout = value;
157 break;
158 case 'v':
159 o->rto_v++;
160 break;
161 case 'S':
162 o->rto_sweep = 1;
163 break;
164 case 'B':
165 o->rto_benchmark = 1;
166 break;
167 case 'D':
168 o->rto_gdb = 1;
169 break;
170 case 'T':
171 o->rto_sanity = 1;
172 break;
173 case 'h':
174 usage(B_TRUE);
175 break;
176 case '?':
177 default:
178 usage(B_FALSE);
179 break;
180 }
181 }
182}
183
cbf484f8 184#define DATA_COL(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_abd)
ab9f4b0b
GN
185#define DATA_COL_SIZE(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_size)
186
cbf484f8 187#define CODE_COL(rm, i) ((rm)->rm_col[(i)].rc_abd)
ab9f4b0b
GN
188#define CODE_COL_SIZE(rm, i) ((rm)->rm_col[(i)].rc_size)
189
190static int
191cmp_code(raidz_test_opts_t *opts, const raidz_map_t *rm, const int parity)
192{
193 int i, ret = 0;
194
195 VERIFY(parity >= 1 && parity <= 3);
196
197 for (i = 0; i < parity; i++) {
cbf484f8
GN
198 if (abd_cmp(CODE_COL(rm, i), CODE_COL(opts->rm_golden, i))
199 != 0) {
ab9f4b0b 200 ret++;
ab9f4b0b
GN
201 LOG_OPT(D_DEBUG, opts,
202 "\nParity block [%d] different!\n", i);
203 }
204 }
205 return (ret);
206}
207
208static int
209cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)
210{
211 int i, ret = 0;
212 int dcols = opts->rm_golden->rm_cols - raidz_parity(opts->rm_golden);
213
214 for (i = 0; i < dcols; i++) {
cbf484f8
GN
215 if (abd_cmp(DATA_COL(opts->rm_golden, i), DATA_COL(rm, i))
216 != 0) {
ab9f4b0b
GN
217 ret++;
218
219 LOG_OPT(D_DEBUG, opts,
220 "\nData block [%d] different!\n", i);
221 }
222 }
223 return (ret);
224}
225
cbf484f8
GN
226static int
227init_rand(void *data, size_t size, void *private)
228{
229 int i;
230 int *dst = (int *) data;
231
232 for (i = 0; i < size / sizeof (int); i++)
233 dst[i] = rand_data[i];
234
235 return (0);
236}
237
ab9f4b0b
GN
238static void
239corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)
240{
241 int i;
ab9f4b0b
GN
242 raidz_col_t *col;
243
244 for (i = 0; i < cnt; i++) {
245 col = &rm->rm_col[tgts[i]];
65d71d42 246 abd_iterate_func(col->rc_abd, 0, col->rc_size, init_rand, NULL);
ab9f4b0b
GN
247 }
248}
249
250void
cbf484f8 251init_zio_abd(zio_t *zio)
ab9f4b0b 252{
cbf484f8 253 abd_iterate_func(zio->io_abd, 0, zio->io_size, init_rand, NULL);
ab9f4b0b
GN
254}
255
256static void
257fini_raidz_map(zio_t **zio, raidz_map_t **rm)
258{
259 vdev_raidz_map_free(*rm);
cbf484f8 260 raidz_free((*zio)->io_abd, (*zio)->io_size);
ab9f4b0b
GN
261 umem_free(*zio, sizeof (zio_t));
262
263 *zio = NULL;
264 *rm = NULL;
265}
266
267static int
268init_raidz_golden_map(raidz_test_opts_t *opts, const int parity)
269{
270 int err = 0;
271 zio_t *zio_test;
272 raidz_map_t *rm_test;
273 const size_t total_ncols = opts->rto_dcols + parity;
274
275 if (opts->rm_golden) {
276 fini_raidz_map(&opts->zio_golden, &opts->rm_golden);
277 }
278
279 opts->zio_golden = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
280 zio_test = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
281
282 opts->zio_golden->io_offset = zio_test->io_offset = opts->rto_offset;
283 opts->zio_golden->io_size = zio_test->io_size = opts->rto_dsize;
284
cbf484f8
GN
285 opts->zio_golden->io_abd = raidz_alloc(opts->rto_dsize);
286 zio_test->io_abd = raidz_alloc(opts->rto_dsize);
ab9f4b0b 287
cbf484f8
GN
288 init_zio_abd(opts->zio_golden);
289 init_zio_abd(zio_test);
ab9f4b0b
GN
290
291 VERIFY0(vdev_raidz_impl_set("original"));
292
293 opts->rm_golden = vdev_raidz_map_alloc(opts->zio_golden,
294 opts->rto_ashift, total_ncols, parity);
295 rm_test = vdev_raidz_map_alloc(zio_test,
296 opts->rto_ashift, total_ncols, parity);
297
298 VERIFY(opts->zio_golden);
299 VERIFY(opts->rm_golden);
300
301 vdev_raidz_generate_parity(opts->rm_golden);
302 vdev_raidz_generate_parity(rm_test);
303
304 /* sanity check */
305 err |= cmp_data(opts, rm_test);
306 err |= cmp_code(opts, rm_test, parity);
307
308 if (err)
309 ERR("initializing the golden copy ... [FAIL]!\n");
310
311 /* tear down raidz_map of test zio */
312 fini_raidz_map(&zio_test, &rm_test);
313
314 return (err);
315}
316
317static raidz_map_t *
318init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
319{
320 raidz_map_t *rm = NULL;
321 const size_t alloc_dsize = opts->rto_dsize;
322 const size_t total_ncols = opts->rto_dcols + parity;
323 const int ccols[] = { 0, 1, 2 };
324
325 VERIFY(zio);
326 VERIFY(parity <= 3 && parity >= 1);
327
328 *zio = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
329
330 (*zio)->io_offset = 0;
331 (*zio)->io_size = alloc_dsize;
cbf484f8
GN
332 (*zio)->io_abd = raidz_alloc(alloc_dsize);
333 init_zio_abd(*zio);
ab9f4b0b
GN
334
335 rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,
336 total_ncols, parity);
337 VERIFY(rm);
338
339 /* Make sure code columns are destroyed */
340 corrupt_colums(rm, ccols, parity);
341
342 return (rm);
343}
344
345static int
346run_gen_check(raidz_test_opts_t *opts)
347{
348 char **impl_name;
349 int fn, err = 0;
350 zio_t *zio_test;
351 raidz_map_t *rm_test;
352
353 err = init_raidz_golden_map(opts, PARITY_PQR);
354 if (0 != err)
355 return (err);
356
357 LOG(D_INFO, DBLSEP);
358 LOG(D_INFO, "Testing parity generation...\n");
359
360 for (impl_name = (char **)raidz_impl_names+1; *impl_name != NULL;
361 impl_name++) {
362
363 LOG(D_INFO, SEP);
364 LOG(D_INFO, "\tTesting [%s] implementation...", *impl_name);
365
366 if (0 != vdev_raidz_impl_set(*impl_name)) {
367 LOG(D_INFO, "[SKIP]\n");
368 continue;
369 } else {
370 LOG(D_INFO, "[SUPPORTED]\n");
371 }
372
373 for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) {
374
292d573e
GN
375 /* Check if should stop */
376 if (rto_opts.rto_should_stop)
377 return (err);
378
ab9f4b0b
GN
379 /* create suitable raidz_map */
380 rm_test = init_raidz_map(opts, &zio_test, fn+1);
381 VERIFY(rm_test);
382
383 LOG(D_INFO, "\t\tTesting method [%s] ...",
384 raidz_gen_name[fn]);
385
386 if (!opts->rto_sanity)
387 vdev_raidz_generate_parity(rm_test);
388
389 if (cmp_code(opts, rm_test, fn+1) != 0) {
390 LOG(D_INFO, "[FAIL]\n");
391 err++;
392 } else
393 LOG(D_INFO, "[PASS]\n");
394
395 fini_raidz_map(&zio_test, &rm_test);
396 }
397 }
398
399 fini_raidz_map(&opts->zio_golden, &opts->rm_golden);
400
401 return (err);
402}
403
404static int
405run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)
406{
407 int x0, x1, x2;
408 int tgtidx[3];
409 int err = 0;
410 static const int rec_tgts[7][3] = {
411 {1, 2, 3}, /* rec_p: bad QR & D[0] */
412 {0, 2, 3}, /* rec_q: bad PR & D[0] */
413 {0, 1, 3}, /* rec_r: bad PQ & D[0] */
414 {2, 3, 4}, /* rec_pq: bad R & D[0][1] */
415 {1, 3, 4}, /* rec_pr: bad Q & D[0][1] */
416 {0, 3, 4}, /* rec_qr: bad P & D[0][1] */
417 {3, 4, 5} /* rec_pqr: bad & D[0][1][2] */
418 };
419
420 memcpy(tgtidx, rec_tgts[fn], sizeof (tgtidx));
421
422 if (fn < RAIDZ_REC_PQ) {
423 /* can reconstruct 1 failed data disk */
424 for (x0 = 0; x0 < opts->rto_dcols; x0++) {
425 if (x0 >= rm->rm_cols - raidz_parity(rm))
426 continue;
427
292d573e
GN
428 /* Check if should stop */
429 if (rto_opts.rto_should_stop)
430 return (err);
431
ab9f4b0b
GN
432 LOG(D_DEBUG, "[%d] ", x0);
433
434 tgtidx[2] = x0 + raidz_parity(rm);
435
436 corrupt_colums(rm, tgtidx+2, 1);
437
438 if (!opts->rto_sanity)
439 vdev_raidz_reconstruct(rm, tgtidx, 3);
440
441 if (cmp_data(opts, rm) != 0) {
442 err++;
443 LOG(D_DEBUG, "\nREC D[%d]... [FAIL]\n", x0);
444 }
445 }
446
447 } else if (fn < RAIDZ_REC_PQR) {
448 /* can reconstruct 2 failed data disk */
449 for (x0 = 0; x0 < opts->rto_dcols; x0++) {
450 if (x0 >= rm->rm_cols - raidz_parity(rm))
451 continue;
452 for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
453 if (x1 >= rm->rm_cols - raidz_parity(rm))
454 continue;
455
292d573e
GN
456 /* Check if should stop */
457 if (rto_opts.rto_should_stop)
458 return (err);
459
ab9f4b0b
GN
460 LOG(D_DEBUG, "[%d %d] ", x0, x1);
461
462 tgtidx[1] = x0 + raidz_parity(rm);
463 tgtidx[2] = x1 + raidz_parity(rm);
464
465 corrupt_colums(rm, tgtidx+1, 2);
466
467 if (!opts->rto_sanity)
468 vdev_raidz_reconstruct(rm, tgtidx, 3);
469
470 if (cmp_data(opts, rm) != 0) {
471 err++;
472 LOG(D_DEBUG, "\nREC D[%d %d]... "
473 "[FAIL]\n", x0, x1);
474 }
475 }
476 }
477 } else {
478 /* can reconstruct 3 failed data disk */
479 for (x0 = 0;
480 x0 < opts->rto_dcols; x0++) {
481 if (x0 >= rm->rm_cols - raidz_parity(rm))
482 continue;
483 for (x1 = x0 + 1;
484 x1 < opts->rto_dcols; x1++) {
485 if (x1 >= rm->rm_cols - raidz_parity(rm))
486 continue;
487 for (x2 = x1 + 1;
488 x2 < opts->rto_dcols; x2++) {
489 if (x2 >=
490 rm->rm_cols - raidz_parity(rm))
491 continue;
492
292d573e
GN
493 /* Check if should stop */
494 if (rto_opts.rto_should_stop)
495 return (err);
496
ab9f4b0b
GN
497 LOG(D_DEBUG, "[%d %d %d]", x0, x1, x2);
498
499 tgtidx[0] = x0 + raidz_parity(rm);
500 tgtidx[1] = x1 + raidz_parity(rm);
501 tgtidx[2] = x2 + raidz_parity(rm);
502
503 corrupt_colums(rm, tgtidx, 3);
504
505 if (!opts->rto_sanity)
506 vdev_raidz_reconstruct(rm,
507 tgtidx, 3);
508
509 if (cmp_data(opts, rm) != 0) {
510 err++;
511 LOG(D_DEBUG,
512 "\nREC D[%d %d %d]... "
513 "[FAIL]\n", x0, x1, x2);
514 }
515 }
516 }
517 }
518 }
519 return (err);
520}
521
522static int
523run_rec_check(raidz_test_opts_t *opts)
524{
525 char **impl_name;
526 unsigned fn, err = 0;
527 zio_t *zio_test;
528 raidz_map_t *rm_test;
529
530 err = init_raidz_golden_map(opts, PARITY_PQR);
531 if (0 != err)
532 return (err);
533
534 LOG(D_INFO, DBLSEP);
535 LOG(D_INFO, "Testing data reconstruction...\n");
536
537 for (impl_name = (char **)raidz_impl_names+1; *impl_name != NULL;
538 impl_name++) {
539
540 LOG(D_INFO, SEP);
541 LOG(D_INFO, "\tTesting [%s] implementation...", *impl_name);
542
543 if (vdev_raidz_impl_set(*impl_name) != 0) {
544 LOG(D_INFO, "[SKIP]\n");
545 continue;
546 } else
547 LOG(D_INFO, "[SUPPORTED]\n");
548
549
550 /* create suitable raidz_map */
551 rm_test = init_raidz_map(opts, &zio_test, PARITY_PQR);
552 /* generate parity */
553 vdev_raidz_generate_parity(rm_test);
554
555 for (fn = 0; fn < RAIDZ_REC_NUM; fn++) {
556
557 LOG(D_INFO, "\t\tTesting method [%s] ...",
558 raidz_rec_name[fn]);
559
560 if (run_rec_check_impl(opts, rm_test, fn) != 0) {
561 LOG(D_INFO, "[FAIL]\n");
562 err++;
563
564 } else
565 LOG(D_INFO, "[PASS]\n");
566
567 }
568 /* tear down test raidz_map */
569 fini_raidz_map(&zio_test, &rm_test);
570 }
571
572 fini_raidz_map(&opts->zio_golden, &opts->rm_golden);
573
574 return (err);
575}
576
577static int
578run_test(raidz_test_opts_t *opts)
579{
580 int err = 0;
581
582 if (opts == NULL)
583 opts = &rto_opts;
584
585 print_opts(opts, B_FALSE);
586
587 err |= run_gen_check(opts);
588 err |= run_rec_check(opts);
589
590 return (err);
591}
592
593#define SWEEP_RUNNING 0
594#define SWEEP_FINISHED 1
595#define SWEEP_ERROR 2
596#define SWEEP_TIMEOUT 3
597
598static int sweep_state = 0;
599static raidz_test_opts_t failed_opts;
600
601static kmutex_t sem_mtx;
602static kcondvar_t sem_cv;
603static int max_free_slots;
604static int free_slots;
605
606static void
607sweep_thread(void *arg)
608{
609 int err = 0;
610 raidz_test_opts_t *opts = (raidz_test_opts_t *) arg;
611 VERIFY(opts != NULL);
612
613 err = run_test(opts);
614
615 if (rto_opts.rto_sanity) {
616 /* 25% chance that a sweep test fails */
617 if (rand() < (RAND_MAX/4))
618 err = 1;
619 }
620
621 if (0 != err) {
622 mutex_enter(&sem_mtx);
623 memcpy(&failed_opts, opts, sizeof (raidz_test_opts_t));
624 sweep_state = SWEEP_ERROR;
625 mutex_exit(&sem_mtx);
626 }
627
628 umem_free(opts, sizeof (raidz_test_opts_t));
629
630 /* signal the next thread */
631 mutex_enter(&sem_mtx);
632 free_slots++;
633 cv_signal(&sem_cv);
634 mutex_exit(&sem_mtx);
635
636 thread_exit();
637}
638
639static int
640run_sweep(void)
641{
292d573e
GN
642 static const size_t dcols_v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 12, 15, 16 };
643 static const size_t ashift_v[] = { 9, 12, 14 };
ab9f4b0b
GN
644 static const size_t size_v[] = { 1 << 9, 21 * (1 << 9), 13 * (1 << 12),
645 1 << 17, (1 << 20) - (1 << 12), SPA_MAXBLOCKSIZE };
646
647 (void) setvbuf(stdout, NULL, _IONBF, 0);
648
649 ulong_t total_comb = ARRAY_SIZE(size_v) * ARRAY_SIZE(ashift_v) *
292d573e 650 ARRAY_SIZE(dcols_v);
ab9f4b0b
GN
651 ulong_t tried_comb = 0;
652 hrtime_t time_diff, start_time = gethrtime();
653 raidz_test_opts_t *opts;
292d573e 654 int a, d, s;
ab9f4b0b
GN
655
656 max_free_slots = free_slots = MAX(2, boot_ncpus);
657
658 mutex_init(&sem_mtx, NULL, MUTEX_DEFAULT, NULL);
659 cv_init(&sem_cv, NULL, CV_DEFAULT, NULL);
660
661 for (s = 0; s < ARRAY_SIZE(size_v); s++)
662 for (a = 0; a < ARRAY_SIZE(ashift_v); a++)
ab9f4b0b
GN
663 for (d = 0; d < ARRAY_SIZE(dcols_v); d++) {
664
292d573e 665 if (size_v[s] < (1 << ashift_v[a])) {
ab9f4b0b
GN
666 total_comb--;
667 continue;
668 }
669
670 if (++tried_comb % 20 == 0)
671 LOG(D_ALL, "%lu/%lu... ", tried_comb, total_comb);
672
673 /* wait for signal to start new thread */
674 mutex_enter(&sem_mtx);
675 while (cv_timedwait_sig(&sem_cv, &sem_mtx,
676 ddi_get_lbolt() + hz)) {
677
678 /* check if should stop the test (timeout) */
679 time_diff = (gethrtime() - start_time) / NANOSEC;
680 if (rto_opts.rto_sweep_timeout > 0 &&
681 time_diff >= rto_opts.rto_sweep_timeout) {
682 sweep_state = SWEEP_TIMEOUT;
292d573e 683 rto_opts.rto_should_stop = B_TRUE;
ab9f4b0b
GN
684 mutex_exit(&sem_mtx);
685 goto exit;
686 }
687
688 /* check if should stop the test (error) */
689 if (sweep_state != SWEEP_RUNNING) {
690 mutex_exit(&sem_mtx);
691 goto exit;
692 }
693
694 /* exit loop if a slot is available */
695 if (free_slots > 0) {
696 break;
697 }
698 }
699
700 free_slots--;
701 mutex_exit(&sem_mtx);
702
703 opts = umem_zalloc(sizeof (raidz_test_opts_t), UMEM_NOFAIL);
704 opts->rto_ashift = ashift_v[a];
705 opts->rto_dcols = dcols_v[d];
292d573e 706 opts->rto_offset = (1 << ashift_v[a]) * rand();
ab9f4b0b
GN
707 opts->rto_dsize = size_v[s];
708 opts->rto_v = 0; /* be quiet */
709
710 VERIFY3P(zk_thread_create(NULL, 0,
711 (thread_func_t) sweep_thread,
712 (void *) opts, TS_RUN, NULL, 0, 0,
713 PTHREAD_CREATE_JOINABLE), !=, NULL);
714 }
715
716exit:
717 LOG(D_ALL, "\nWaiting for test threads to finish...\n");
718 mutex_enter(&sem_mtx);
719 VERIFY(free_slots <= max_free_slots);
720 while (free_slots < max_free_slots) {
721 (void) cv_wait(&sem_cv, &sem_mtx);
722 }
723 mutex_exit(&sem_mtx);
724
725 if (sweep_state == SWEEP_ERROR) {
726 ERR("Sweep test failed! Failed option: \n");
727 print_opts(&failed_opts, B_TRUE);
728 } else {
729 if (sweep_state == SWEEP_TIMEOUT)
730 LOG(D_ALL, "Test timeout (%lus). Stopping...\n",
731 (ulong_t)rto_opts.rto_sweep_timeout);
732
733 LOG(D_ALL, "Sweep test succeeded on %lu raidz maps!\n",
734 (ulong_t)tried_comb);
735 }
736
737 return (sweep_state == SWEEP_ERROR ? SWEEP_ERROR : 0);
738}
739
740int
741main(int argc, char **argv)
742{
743 size_t i;
744 struct sigaction action;
745 int err = 0;
746
747 /* init gdb string early */
748 (void) sprintf(gdb, gdb_tmpl, getpid());
749
750 action.sa_handler = sig_handler;
751 sigemptyset(&action.sa_mask);
752 action.sa_flags = 0;
753
754 if (sigaction(SIGSEGV, &action, NULL) < 0) {
755 ERR("raidz_test: cannot catch SIGSEGV: %s.\n", strerror(errno));
756 exit(EXIT_FAILURE);
757 }
758
759 (void) setvbuf(stdout, NULL, _IOLBF, 0);
760
761 dprintf_setup(&argc, argv);
762
763 process_options(argc, argv);
764
765 kernel_init(FREAD);
766
767 /* setup random data because rand() is not reentrant */
768 rand_data = (int *) umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
769 srand((unsigned)time(NULL) * getpid());
770 for (i = 0; i < SPA_MAXBLOCKSIZE / sizeof (int); i++)
771 rand_data[i] = rand();
772
773 mprotect(rand_data, SPA_MAXBLOCKSIZE, PROT_READ);
774
775 if (rto_opts.rto_benchmark) {
776 run_raidz_benchmark();
777 } else if (rto_opts.rto_sweep) {
778 err = run_sweep();
779 } else {
780 err = run_test(NULL);
781 }
782
783 umem_free(rand_data, SPA_MAXBLOCKSIZE);
784 kernel_fini();
785
786 return (err);
787}