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