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