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