Path: blob/main/sys/contrib/openzfs/cmd/raidz_test/raidz_test.c
107787 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* 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.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright (C) 2016 Gvozden Nešković. All rights reserved.24*/2526#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 <libzpool.h>36#include "raidz_test.h"3738static int *rand_data;39raidz_test_opts_t rto_opts;4041static char pid_s[16];4243static void sig_handler(int signo)44{45int old_errno = errno;46struct sigaction action;47/*48* Restore default action and re-raise signal so SIGSEGV and49* SIGABRT can trigger a core dump.50*/51action.sa_handler = SIG_DFL;52sigemptyset(&action.sa_mask);53action.sa_flags = 0;54(void) sigaction(signo, &action, NULL);5556if (rto_opts.rto_gdb) {57pid_t pid = fork();58if (pid == 0) {59execlp("gdb", "gdb", "-ex", "set pagination 0",60"-p", pid_s, NULL);61_exit(-1);62} else if (pid > 0)63while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)64;65}6667raise(signo);68errno = old_errno;69}7071static void print_opts(raidz_test_opts_t *opts, boolean_t force)72{73const char *verbose;74switch (opts->rto_v) {75case D_ALL:76verbose = "no";77break;78case D_INFO:79verbose = "info";80break;81case D_DEBUG:82default:83verbose = "debug";84break;85}8687if (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",97opts->rto_ashift, /* -a */98ilog2(opts->rto_offset), /* -o */99opts->rto_expand ? "yes" : "no", /* -e */100(u_longlong_t)opts->rto_expand_offset, /* -r */101opts->rto_dcols, /* -d */102ilog2(opts->rto_dsize), /* -s */103opts->rto_sweep ? "yes" : "no", /* -S */104verbose); /* -v */105}106}107108static void usage(boolean_t requested)109{110const raidz_test_opts_t *o = &rto_opts_defaults;111112FILE *fp = requested ? stdout : stderr;113114(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"",129o->rto_ashift, /* -a */130ilog2(o->rto_offset), /* -o */131o->rto_dcols, /* -d */132ilog2(o->rto_dsize), /* -s */133rto_opts.rto_sweep ? "yes" : "no", /* -S */134rto_opts.rto_expand ? "yes" : "no", /* -e */135(u_longlong_t)o->rto_expand_offset, /* -r */136o->rto_v); /* -v */137138exit(requested ? 0 : 1);139}140141static void process_options(int argc, char **argv)142{143size_t value;144int opt;145raidz_test_opts_t *o = &rto_opts;146147memcpy(o, &rto_opts_defaults, sizeof (*o));148149while ((opt = getopt(argc, argv, "TDBSvha:er:o:d:s:t:")) != -1) {150switch (opt) {151case 'a':152value = strtoull(optarg, NULL, 0);153o->rto_ashift = MIN(13, MAX(9, value));154break;155case 'e':156o->rto_expand = 1;157break;158case 'r':159o->rto_expand_offset = strtoull(optarg, NULL, 0);160break;161case 'o':162value = strtoull(optarg, NULL, 0);163o->rto_offset = ((1ULL << MIN(12, value)) >> 9) << 9;164break;165case 'd':166value = strtoull(optarg, NULL, 0);167o->rto_dcols = MIN(255, MAX(1, value));168break;169case 's':170value = strtoull(optarg, NULL, 0);171o->rto_dsize = 1ULL << MIN(SPA_MAXBLOCKSHIFT,172MAX(SPA_MINBLOCKSHIFT, value));173break;174case 't':175value = strtoull(optarg, NULL, 0);176o->rto_sweep_timeout = value;177break;178case 'v':179o->rto_v++;180break;181case 'S':182o->rto_sweep = 1;183break;184case 'B':185o->rto_benchmark = 1;186break;187case 'D':188o->rto_gdb = 1;189break;190case 'T':191o->rto_sanity = 1;192break;193case 'h':194usage(B_TRUE);195break;196case '?':197default:198usage(B_FALSE);199break;200}201}202}203204#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)206207#define CODE_COL(rr, i) ((rr)->rr_col[(i)].rc_abd)208#define CODE_COL_SIZE(rr, i) ((rr)->rr_col[(i)].rc_size)209210static int211cmp_code(raidz_test_opts_t *opts, const raidz_map_t *rm, const int parity)212{213int r, i, ret = 0;214215VERIFY(parity >= 1 && parity <= 3);216217for (r = 0; r < rm->rm_nrows; r++) {218raidz_row_t * const rr = rm->rm_row[r];219raidz_row_t * const rrg = opts->rm_golden->rm_row[r];220for (i = 0; i < parity; i++) {221if (CODE_COL_SIZE(rrg, i) == 0) {222VERIFY0(CODE_COL_SIZE(rr, i));223continue;224}225226if (abd_cmp(CODE_COL(rr, i),227CODE_COL(rrg, i)) != 0) {228ret++;229LOG_OPT(D_DEBUG, opts,230"\nParity block [%d] different!\n", i);231}232}233}234return (ret);235}236237static int238cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)239{240int r, i, dcols, ret = 0;241242for (r = 0; r < rm->rm_nrows; r++) {243raidz_row_t *rr = rm->rm_row[r];244raidz_row_t *rrg = opts->rm_golden->rm_row[r];245dcols = opts->rm_golden->rm_row[0]->rr_cols -246raidz_parity(opts->rm_golden);247for (i = 0; i < dcols; i++) {248if (DATA_COL_SIZE(rrg, i) == 0) {249VERIFY0(DATA_COL_SIZE(rr, i));250continue;251}252253if (abd_cmp(DATA_COL(rrg, i),254DATA_COL(rr, i)) != 0) {255ret++;256257LOG_OPT(D_DEBUG, opts,258"\nData block [%d] different!\n", i);259}260}261}262return (ret);263}264265static int266init_rand(void *data, size_t size, void *private)267{268size_t *offsetp = (size_t *)private;269size_t offset = *offsetp;270271VERIFY3U(offset + size, <=, SPA_MAXBLOCKSIZE);272memcpy(data, (char *)rand_data + offset, size);273*offsetp = offset + size;274return (0);275}276277static int278corrupt_rand_fill(void *data, size_t size, void *private)279{280(void) private;281memset(data, 0xAA, size);282return (0);283}284285static void286corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)287{288for (int r = 0; r < rm->rm_nrows; r++) {289raidz_row_t *rr = rm->rm_row[r];290for (int i = 0; i < cnt; i++) {291raidz_col_t *col = &rr->rr_col[tgts[i]];292abd_iterate_func(col->rc_abd, 0, col->rc_size,293corrupt_rand_fill, NULL);294}295}296}297298void299init_zio_abd(zio_t *zio)300{301size_t offset = 0;302abd_iterate_func(zio->io_abd, 0, zio->io_size, init_rand, &offset);303}304305static void306fini_raidz_map(zio_t **zio, raidz_map_t **rm)307{308vdev_raidz_map_free(*rm);309raidz_free((*zio)->io_abd, (*zio)->io_size);310umem_free(*zio, sizeof (zio_t));311312*zio = NULL;313*rm = NULL;314}315316static int317init_raidz_golden_map(raidz_test_opts_t *opts, const int parity)318{319int err = 0;320zio_t *zio_test;321raidz_map_t *rm_test;322const size_t total_ncols = opts->rto_dcols + parity;323324if (opts->rm_golden) {325fini_raidz_map(&opts->zio_golden, &opts->rm_golden);326}327328opts->zio_golden = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);329zio_test = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);330331opts->zio_golden->io_offset = zio_test->io_offset = opts->rto_offset;332opts->zio_golden->io_size = zio_test->io_size = opts->rto_dsize;333334opts->zio_golden->io_abd = raidz_alloc(opts->rto_dsize);335zio_test->io_abd = raidz_alloc(opts->rto_dsize);336337init_zio_abd(opts->zio_golden);338init_zio_abd(zio_test);339340VERIFY0(vdev_raidz_impl_set("original"));341342if (opts->rto_expand) {343opts->rm_golden =344vdev_raidz_map_alloc_expanded(opts->zio_golden,345opts->rto_ashift, total_ncols+1, total_ncols,346parity, opts->rto_expand_offset, 0, B_FALSE);347rm_test = vdev_raidz_map_alloc_expanded(zio_test,348opts->rto_ashift, total_ncols+1, total_ncols,349parity, opts->rto_expand_offset, 0, B_FALSE);350} else {351opts->rm_golden = vdev_raidz_map_alloc(opts->zio_golden,352opts->rto_ashift, total_ncols, parity);353rm_test = vdev_raidz_map_alloc(zio_test,354opts->rto_ashift, total_ncols, parity);355}356357VERIFY(opts->zio_golden);358VERIFY(opts->rm_golden);359360vdev_raidz_generate_parity(opts->rm_golden);361vdev_raidz_generate_parity(rm_test);362363/* sanity check */364err |= cmp_data(opts, rm_test);365err |= cmp_code(opts, rm_test, parity);366367if (err)368ERR("initializing the golden copy ... [FAIL]!\n");369370/* tear down raidz_map of test zio */371fini_raidz_map(&zio_test, &rm_test);372373return (err);374}375376static raidz_map_t *377init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)378{379raidz_map_t *rm = NULL;380const size_t alloc_dsize = opts->rto_dsize;381const size_t total_ncols = opts->rto_dcols + parity;382const int ccols[] = { 0, 1, 2 };383384VERIFY(zio);385VERIFY(parity <= 3 && parity >= 1);386387*zio = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);388389(*zio)->io_offset = opts->rto_offset;390(*zio)->io_size = alloc_dsize;391(*zio)->io_abd = raidz_alloc(alloc_dsize);392init_zio_abd(*zio);393394if (opts->rto_expand) {395rm = vdev_raidz_map_alloc_expanded(*zio,396opts->rto_ashift, total_ncols+1, total_ncols,397parity, opts->rto_expand_offset, 0, B_FALSE);398} else {399rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,400total_ncols, parity);401}402VERIFY(rm);403404/* Make sure code columns are destroyed */405corrupt_colums(rm, ccols, parity);406407return (rm);408}409410static int411run_gen_check(raidz_test_opts_t *opts)412{413char **impl_name;414int fn, err = 0;415zio_t *zio_test;416raidz_map_t *rm_test;417418err = init_raidz_golden_map(opts, PARITY_PQR);419if (0 != err)420return (err);421422LOG(D_INFO, DBLSEP);423LOG(D_INFO, "Testing parity generation...\n");424425for (impl_name = (char **)raidz_impl_names+1; *impl_name != NULL;426impl_name++) {427428LOG(D_INFO, SEP);429LOG(D_INFO, "\tTesting [%s] implementation...", *impl_name);430431if (0 != vdev_raidz_impl_set(*impl_name)) {432LOG(D_INFO, "[SKIP]\n");433continue;434} else {435LOG(D_INFO, "[SUPPORTED]\n");436}437438for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) {439440/* Check if should stop */441if (rto_opts.rto_should_stop)442return (err);443444/* create suitable raidz_map */445rm_test = init_raidz_map(opts, &zio_test, fn+1);446VERIFY(rm_test);447448LOG(D_INFO, "\t\tTesting method [%s] ...",449raidz_gen_name[fn]);450451if (!opts->rto_sanity)452vdev_raidz_generate_parity(rm_test);453454if (cmp_code(opts, rm_test, fn+1) != 0) {455LOG(D_INFO, "[FAIL]\n");456err++;457} else458LOG(D_INFO, "[PASS]\n");459460fini_raidz_map(&zio_test, &rm_test);461}462}463464fini_raidz_map(&opts->zio_golden, &opts->rm_golden);465466return (err);467}468469static int470run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)471{472int x0, x1, x2;473int tgtidx[3];474int err = 0;475static const int rec_tgts[7][3] = {476{1, 2, 3}, /* rec_p: bad QR & D[0] */477{0, 2, 3}, /* rec_q: bad PR & D[0] */478{0, 1, 3}, /* rec_r: bad PQ & D[0] */479{2, 3, 4}, /* rec_pq: bad R & D[0][1] */480{1, 3, 4}, /* rec_pr: bad Q & D[0][1] */481{0, 3, 4}, /* rec_qr: bad P & D[0][1] */482{3, 4, 5} /* rec_pqr: bad & D[0][1][2] */483};484485memcpy(tgtidx, rec_tgts[fn], sizeof (tgtidx));486487if (fn < RAIDZ_REC_PQ) {488/* can reconstruct 1 failed data disk */489for (x0 = 0; x0 < opts->rto_dcols; x0++) {490if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))491continue;492493/* Check if should stop */494if (rto_opts.rto_should_stop)495return (err);496497LOG(D_DEBUG, "[%d] ", x0);498499tgtidx[2] = x0 + raidz_parity(rm);500501corrupt_colums(rm, tgtidx+2, 1);502503if (!opts->rto_sanity)504vdev_raidz_reconstruct(rm, tgtidx, 3);505506if (cmp_data(opts, rm) != 0) {507err++;508LOG(D_DEBUG, "\nREC D[%d]... [FAIL]\n", x0);509}510}511512} else if (fn < RAIDZ_REC_PQR) {513/* can reconstruct 2 failed data disk */514for (x0 = 0; x0 < opts->rto_dcols; x0++) {515if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))516continue;517for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {518if (x1 >= rm->rm_row[0]->rr_cols -519raidz_parity(rm))520continue;521522/* Check if should stop */523if (rto_opts.rto_should_stop)524return (err);525526LOG(D_DEBUG, "[%d %d] ", x0, x1);527528tgtidx[1] = x0 + raidz_parity(rm);529tgtidx[2] = x1 + raidz_parity(rm);530531corrupt_colums(rm, tgtidx+1, 2);532533if (!opts->rto_sanity)534vdev_raidz_reconstruct(rm, tgtidx, 3);535536if (cmp_data(opts, rm) != 0) {537err++;538LOG(D_DEBUG, "\nREC D[%d %d]... "539"[FAIL]\n", x0, x1);540}541}542}543} else {544/* can reconstruct 3 failed data disk */545for (x0 = 0; x0 < opts->rto_dcols; x0++) {546if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))547continue;548for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {549if (x1 >= rm->rm_row[0]->rr_cols -550raidz_parity(rm))551continue;552for (x2 = x1 + 1; x2 < opts->rto_dcols; x2++) {553if (x2 >= rm->rm_row[0]->rr_cols -554raidz_parity(rm))555continue;556557/* Check if should stop */558if (rto_opts.rto_should_stop)559return (err);560561LOG(D_DEBUG, "[%d %d %d]", x0, x1, x2);562563tgtidx[0] = x0 + raidz_parity(rm);564tgtidx[1] = x1 + raidz_parity(rm);565tgtidx[2] = x2 + raidz_parity(rm);566567corrupt_colums(rm, tgtidx, 3);568569if (!opts->rto_sanity)570vdev_raidz_reconstruct(rm,571tgtidx, 3);572573if (cmp_data(opts, rm) != 0) {574err++;575LOG(D_DEBUG,576"\nREC D[%d %d %d]... "577"[FAIL]\n", x0, x1, x2);578}579}580}581}582}583return (err);584}585586static int587run_rec_check(raidz_test_opts_t *opts)588{589char **impl_name;590unsigned fn, err = 0;591zio_t *zio_test;592raidz_map_t *rm_test;593594err = init_raidz_golden_map(opts, PARITY_PQR);595if (0 != err)596return (err);597598LOG(D_INFO, DBLSEP);599LOG(D_INFO, "Testing data reconstruction...\n");600601for (impl_name = (char **)raidz_impl_names+1; *impl_name != NULL;602impl_name++) {603604LOG(D_INFO, SEP);605LOG(D_INFO, "\tTesting [%s] implementation...", *impl_name);606607if (vdev_raidz_impl_set(*impl_name) != 0) {608LOG(D_INFO, "[SKIP]\n");609continue;610} else611LOG(D_INFO, "[SUPPORTED]\n");612613614/* create suitable raidz_map */615rm_test = init_raidz_map(opts, &zio_test, PARITY_PQR);616/* generate parity */617vdev_raidz_generate_parity(rm_test);618619for (fn = 0; fn < RAIDZ_REC_NUM; fn++) {620621LOG(D_INFO, "\t\tTesting method [%s] ...",622raidz_rec_name[fn]);623624if (run_rec_check_impl(opts, rm_test, fn) != 0) {625LOG(D_INFO, "[FAIL]\n");626err++;627628} else629LOG(D_INFO, "[PASS]\n");630631}632/* tear down test raidz_map */633fini_raidz_map(&zio_test, &rm_test);634}635636fini_raidz_map(&opts->zio_golden, &opts->rm_golden);637638return (err);639}640641static int642run_test(raidz_test_opts_t *opts)643{644int err = 0;645646if (opts == NULL)647opts = &rto_opts;648649print_opts(opts, B_FALSE);650651err |= run_gen_check(opts);652err |= run_rec_check(opts);653654return (err);655}656657#define SWEEP_RUNNING 0658#define SWEEP_FINISHED 1659#define SWEEP_ERROR 2660#define SWEEP_TIMEOUT 3661662static int sweep_state = 0;663static raidz_test_opts_t failed_opts;664665static kmutex_t sem_mtx;666static kcondvar_t sem_cv;667static int max_free_slots;668static int free_slots;669670static __attribute__((noreturn)) void671sweep_thread(void *arg)672{673int err = 0;674raidz_test_opts_t *opts = (raidz_test_opts_t *)arg;675VERIFY(opts != NULL);676677err = run_test(opts);678679if (rto_opts.rto_sanity) {680/* 25% chance that a sweep test fails */681if (rand() < (RAND_MAX/4))682err = 1;683}684685if (0 != err) {686mutex_enter(&sem_mtx);687memcpy(&failed_opts, opts, sizeof (raidz_test_opts_t));688sweep_state = SWEEP_ERROR;689mutex_exit(&sem_mtx);690}691692umem_free(opts, sizeof (raidz_test_opts_t));693694/* signal the next thread */695mutex_enter(&sem_mtx);696free_slots++;697cv_signal(&sem_cv);698mutex_exit(&sem_mtx);699700thread_exit();701}702703static int704run_sweep(void)705{706static const size_t dcols_v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 12, 15, 16 };707static const size_t ashift_v[] = { 9, 12, 14 };708static const size_t size_v[] = { 1 << 9, 21 * (1 << 9), 13 * (1 << 12),7091 << 17, (1 << 20) - (1 << 12), SPA_MAXBLOCKSIZE };710711(void) setvbuf(stdout, NULL, _IONBF, 0);712713ulong_t total_comb = ARRAY_SIZE(size_v) * ARRAY_SIZE(ashift_v) *714ARRAY_SIZE(dcols_v);715ulong_t tried_comb = 0;716hrtime_t time_diff, start_time = gethrtime();717raidz_test_opts_t *opts;718int a, d, s;719720max_free_slots = free_slots = MAX(2, boot_ncpus);721722mutex_init(&sem_mtx, NULL, MUTEX_DEFAULT, NULL);723cv_init(&sem_cv, NULL, CV_DEFAULT, NULL);724725for (s = 0; s < ARRAY_SIZE(size_v); s++)726for (a = 0; a < ARRAY_SIZE(ashift_v); a++)727for (d = 0; d < ARRAY_SIZE(dcols_v); d++) {728729if (size_v[s] < (1 << ashift_v[a])) {730total_comb--;731continue;732}733734if (++tried_comb % 20 == 0)735LOG(D_ALL, "%lu/%lu... ", tried_comb, total_comb);736737/* wait for signal to start new thread */738mutex_enter(&sem_mtx);739while (cv_timedwait_sig(&sem_cv, &sem_mtx,740ddi_get_lbolt() + hz)) {741742/* check if should stop the test (timeout) */743time_diff = (gethrtime() - start_time) / NANOSEC;744if (rto_opts.rto_sweep_timeout > 0 &&745time_diff >= rto_opts.rto_sweep_timeout) {746sweep_state = SWEEP_TIMEOUT;747rto_opts.rto_should_stop = B_TRUE;748mutex_exit(&sem_mtx);749goto exit;750}751752/* check if should stop the test (error) */753if (sweep_state != SWEEP_RUNNING) {754mutex_exit(&sem_mtx);755goto exit;756}757758/* exit loop if a slot is available */759if (free_slots > 0) {760break;761}762}763764free_slots--;765mutex_exit(&sem_mtx);766767opts = umem_zalloc(sizeof (raidz_test_opts_t), UMEM_NOFAIL);768opts->rto_ashift = ashift_v[a];769opts->rto_dcols = dcols_v[d];770opts->rto_offset = (1ULL << ashift_v[a]) * rand();771opts->rto_dsize = size_v[s];772opts->rto_expand = rto_opts.rto_expand;773opts->rto_expand_offset = rto_opts.rto_expand_offset;774opts->rto_v = 0; /* be quiet */775776VERIFY3P(thread_create(NULL, 0, sweep_thread, (void *) opts,7770, NULL, TS_RUN, defclsyspri), !=, NULL);778}779780exit:781LOG(D_ALL, "\nWaiting for test threads to finish...\n");782mutex_enter(&sem_mtx);783VERIFY(free_slots <= max_free_slots);784while (free_slots < max_free_slots) {785(void) cv_wait(&sem_cv, &sem_mtx);786}787mutex_exit(&sem_mtx);788789if (sweep_state == SWEEP_ERROR) {790ERR("Sweep test failed! Failed option: \n");791print_opts(&failed_opts, B_TRUE);792} else {793if (sweep_state == SWEEP_TIMEOUT)794LOG(D_ALL, "Test timeout (%lus). Stopping...\n",795(ulong_t)rto_opts.rto_sweep_timeout);796797LOG(D_ALL, "Sweep test succeeded on %lu raidz maps!\n",798(ulong_t)tried_comb);799}800801mutex_destroy(&sem_mtx);802803return (sweep_state == SWEEP_ERROR ? SWEEP_ERROR : 0);804}805806807int808main(int argc, char **argv)809{810size_t i;811struct sigaction action;812int err = 0;813814/* init gdb pid string early */815(void) sprintf(pid_s, "%d", getpid());816817action.sa_handler = sig_handler;818sigemptyset(&action.sa_mask);819action.sa_flags = 0;820821if (sigaction(SIGSEGV, &action, NULL) < 0) {822ERR("raidz_test: cannot catch SIGSEGV: %s.\n", strerror(errno));823exit(EXIT_FAILURE);824}825826(void) setvbuf(stdout, NULL, _IOLBF, 0);827828dprintf_setup(&argc, argv);829830process_options(argc, argv);831832kernel_init(SPA_MODE_READ);833834/* setup random data because rand() is not reentrant */835rand_data = (int *)umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);836srand((unsigned)time(NULL) * getpid());837for (i = 0; i < SPA_MAXBLOCKSIZE / sizeof (int); i++)838rand_data[i] = rand();839840mprotect(rand_data, SPA_MAXBLOCKSIZE, PROT_READ);841842if (rto_opts.rto_benchmark) {843run_raidz_benchmark();844} else if (rto_opts.rto_sweep) {845err = run_sweep();846} else {847err = run_test(NULL);848}849850mprotect(rand_data, SPA_MAXBLOCKSIZE, PROT_READ | PROT_WRITE);851852umem_free(rand_data, SPA_MAXBLOCKSIZE);853kernel_fini();854855return (err);856}857858859