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