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