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