xref: /freebsd/sys/contrib/openzfs/cmd/raidz_test/raidz_test.c (revision e2eeea75eb8b6dd50c1298067a0655880d186734)
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 
37 static int *rand_data;
38 raidz_test_opts_t rto_opts;
39 
40 static char gdb[256];
41 static const char gdb_tmpl[] = "gdb -ex \"set pagination 0\" -p %d";
42 
43 static 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 
61 static 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 static 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"
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 */
118 
119 	exit(requested ? 0 : 1);
120 }
121 
122 static 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 
182 #define	DATA_COL(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_abd)
183 #define	DATA_COL_SIZE(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_size)
184 
185 #define	CODE_COL(rm, i) ((rm)->rm_col[(i)].rc_abd)
186 #define	CODE_COL_SIZE(rm, i) ((rm)->rm_col[(i)].rc_size)
187 
188 static int
189 cmp_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++) {
196 		if (abd_cmp(CODE_COL(rm, i), CODE_COL(opts->rm_golden, i))
197 		    != 0) {
198 			ret++;
199 			LOG_OPT(D_DEBUG, opts,
200 			    "\nParity block [%d] different!\n", i);
201 		}
202 	}
203 	return (ret);
204 }
205 
206 static int
207 cmp_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++) {
213 		if (abd_cmp(DATA_COL(opts->rm_golden, i), DATA_COL(rm, i))
214 		    != 0) {
215 			ret++;
216 
217 			LOG_OPT(D_DEBUG, opts,
218 			    "\nData block [%d] different!\n", i);
219 		}
220 	}
221 	return (ret);
222 }
223 
224 static int
225 init_rand(void *data, size_t size, void *private)
226 {
227 	int i;
228 	int *dst = (int *)data;
229 
230 	for (i = 0; i < size / sizeof (int); i++)
231 		dst[i] = rand_data[i];
232 
233 	return (0);
234 }
235 
236 static void
237 corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)
238 {
239 	int i;
240 	raidz_col_t *col;
241 
242 	for (i = 0; i < cnt; i++) {
243 		col = &rm->rm_col[tgts[i]];
244 		abd_iterate_func(col->rc_abd, 0, col->rc_size, init_rand, NULL);
245 	}
246 }
247 
248 void
249 init_zio_abd(zio_t *zio)
250 {
251 	abd_iterate_func(zio->io_abd, 0, zio->io_size, init_rand, NULL);
252 }
253 
254 static void
255 fini_raidz_map(zio_t **zio, raidz_map_t **rm)
256 {
257 	vdev_raidz_map_free(*rm);
258 	raidz_free((*zio)->io_abd, (*zio)->io_size);
259 	umem_free(*zio, sizeof (zio_t));
260 
261 	*zio = NULL;
262 	*rm = NULL;
263 }
264 
265 static int
266 init_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 
283 	opts->zio_golden->io_abd = raidz_alloc(opts->rto_dsize);
284 	zio_test->io_abd = raidz_alloc(opts->rto_dsize);
285 
286 	init_zio_abd(opts->zio_golden);
287 	init_zio_abd(zio_test);
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 
315 static raidz_map_t *
316 init_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;
330 	(*zio)->io_abd = raidz_alloc(alloc_dsize);
331 	init_zio_abd(*zio);
332 
333 	rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,
334 	    total_ncols, parity);
335 	VERIFY(rm);
336 
337 	/* Make sure code columns are destroyed */
338 	corrupt_colums(rm, ccols, parity);
339 
340 	return (rm);
341 }
342 
343 static int
344 run_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 
373 			/* Check if should stop */
374 			if (rto_opts.rto_should_stop)
375 				return (err);
376 
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 
402 static int
403 run_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 
426 			/* Check if should stop */
427 			if (rto_opts.rto_should_stop)
428 				return (err);
429 
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 
454 				/* Check if should stop */
455 				if (rto_opts.rto_should_stop)
456 					return (err);
457 
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 */
477 		for (x0 = 0; x0 < opts->rto_dcols; x0++) {
478 			if (x0 >= rm->rm_cols - raidz_parity(rm))
479 				continue;
480 			for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
481 				if (x1 >= rm->rm_cols - raidz_parity(rm))
482 					continue;
483 				for (x2 = x1 + 1; x2 < opts->rto_dcols; x2++) {
484 					if (x2 >=
485 					    rm->rm_cols - raidz_parity(rm))
486 						continue;
487 
488 					/* Check if should stop */
489 					if (rto_opts.rto_should_stop)
490 						return (err);
491 
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,
502 						    tgtidx, 3);
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 
517 static int
518 run_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] ...",
553 			    raidz_rec_name[fn]);
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 
572 static int
573 run_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 
593 static int sweep_state = 0;
594 static raidz_test_opts_t failed_opts;
595 
596 static kmutex_t sem_mtx;
597 static kcondvar_t sem_cv;
598 static int max_free_slots;
599 static int free_slots;
600 
601 static void
602 sweep_thread(void *arg)
603 {
604 	int err = 0;
605 	raidz_test_opts_t *opts = (raidz_test_opts_t *)arg;
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 
634 static int
635 run_sweep(void)
636 {
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 };
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) *
645 	    ARRAY_SIZE(dcols_v);
646 	ulong_t tried_comb = 0;
647 	hrtime_t time_diff, start_time = gethrtime();
648 	raidz_test_opts_t *opts;
649 	int a, d, s;
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++)
658 	for (d = 0; d < ARRAY_SIZE(dcols_v); d++) {
659 
660 		if (size_v[s] < (1 << ashift_v[a])) {
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;
678 				rto_opts.rto_should_stop = B_TRUE;
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];
701 		opts->rto_offset = (1 << ashift_v[a]) * rand();
702 		opts->rto_dsize = size_v[s];
703 		opts->rto_v = 0; /* be quiet */
704 
705 		VERIFY3P(thread_create(NULL, 0, sweep_thread, (void *) opts,
706 		    0, NULL, TS_RUN, defclsyspri), !=, NULL);
707 	}
708 
709 exit:
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 
730 	mutex_destroy(&sem_mtx);
731 
732 	return (sweep_state == SWEEP_ERROR ? SWEEP_ERROR : 0);
733 }
734 
735 int
736 main(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(SPA_MODE_READ);
761 
762 	/* setup random data because rand() is not reentrant */
763 	rand_data = (int *)umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
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 }
783