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