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