Path: blob/main/sys/contrib/openzfs/cmd/raidz_test/raidz_test.c
48380 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 "raidz_test.h"3637static int *rand_data;38raidz_test_opts_t rto_opts;3940static char pid_s[16];4142static void sig_handler(int signo)43{44int old_errno = errno;45struct sigaction action;46/*47* Restore default action and re-raise signal so SIGSEGV and48* SIGABRT can trigger a core dump.49*/50action.sa_handler = SIG_DFL;51sigemptyset(&action.sa_mask);52action.sa_flags = 0;53(void) sigaction(signo, &action, NULL);5455if (rto_opts.rto_gdb) {56pid_t pid = fork();57if (pid == 0) {58execlp("gdb", "gdb", "-ex", "set pagination 0",59"-p", pid_s, NULL);60_exit(-1);61} else if (pid > 0)62while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)63;64}6566raise(signo);67errno = old_errno;68}6970static void print_opts(raidz_test_opts_t *opts, boolean_t force)71{72const char *verbose;73switch (opts->rto_v) {74case D_ALL:75verbose = "no";76break;77case D_INFO:78verbose = "info";79break;80case D_DEBUG:81default:82verbose = "debug";83break;84}8586if (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",96opts->rto_ashift, /* -a */97ilog2(opts->rto_offset), /* -o */98opts->rto_expand ? "yes" : "no", /* -e */99(u_longlong_t)opts->rto_expand_offset, /* -r */100opts->rto_dcols, /* -d */101ilog2(opts->rto_dsize), /* -s */102opts->rto_sweep ? "yes" : "no", /* -S */103verbose); /* -v */104}105}106107static void usage(boolean_t requested)108{109const raidz_test_opts_t *o = &rto_opts_defaults;110111FILE *fp = requested ? stdout : stderr;112113(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"",128o->rto_ashift, /* -a */129ilog2(o->rto_offset), /* -o */130o->rto_dcols, /* -d */131ilog2(o->rto_dsize), /* -s */132rto_opts.rto_sweep ? "yes" : "no", /* -S */133rto_opts.rto_expand ? "yes" : "no", /* -e */134(u_longlong_t)o->rto_expand_offset, /* -r */135o->rto_v); /* -v */136137exit(requested ? 0 : 1);138}139140static void process_options(int argc, char **argv)141{142size_t value;143int opt;144raidz_test_opts_t *o = &rto_opts;145146memcpy(o, &rto_opts_defaults, sizeof (*o));147148while ((opt = getopt(argc, argv, "TDBSvha:er:o:d:s:t:")) != -1) {149switch (opt) {150case 'a':151value = strtoull(optarg, NULL, 0);152o->rto_ashift = MIN(13, MAX(9, value));153break;154case 'e':155o->rto_expand = 1;156break;157case 'r':158o->rto_expand_offset = strtoull(optarg, NULL, 0);159break;160case 'o':161value = strtoull(optarg, NULL, 0);162o->rto_offset = ((1ULL << MIN(12, value)) >> 9) << 9;163break;164case 'd':165value = strtoull(optarg, NULL, 0);166o->rto_dcols = MIN(255, MAX(1, value));167break;168case 's':169value = strtoull(optarg, NULL, 0);170o->rto_dsize = 1ULL << MIN(SPA_MAXBLOCKSHIFT,171MAX(SPA_MINBLOCKSHIFT, value));172break;173case 't':174value = strtoull(optarg, NULL, 0);175o->rto_sweep_timeout = value;176break;177case 'v':178o->rto_v++;179break;180case 'S':181o->rto_sweep = 1;182break;183case 'B':184o->rto_benchmark = 1;185break;186case 'D':187o->rto_gdb = 1;188break;189case 'T':190o->rto_sanity = 1;191break;192case 'h':193usage(B_TRUE);194break;195case '?':196default:197usage(B_FALSE);198break;199}200}201}202203#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)205206#define CODE_COL(rr, i) ((rr)->rr_col[(i)].rc_abd)207#define CODE_COL_SIZE(rr, i) ((rr)->rr_col[(i)].rc_size)208209static int210cmp_code(raidz_test_opts_t *opts, const raidz_map_t *rm, const int parity)211{212int r, i, ret = 0;213214VERIFY(parity >= 1 && parity <= 3);215216for (r = 0; r < rm->rm_nrows; r++) {217raidz_row_t * const rr = rm->rm_row[r];218raidz_row_t * const rrg = opts->rm_golden->rm_row[r];219for (i = 0; i < parity; i++) {220if (CODE_COL_SIZE(rrg, i) == 0) {221VERIFY0(CODE_COL_SIZE(rr, i));222continue;223}224225if (abd_cmp(CODE_COL(rr, i),226CODE_COL(rrg, i)) != 0) {227ret++;228LOG_OPT(D_DEBUG, opts,229"\nParity block [%d] different!\n", i);230}231}232}233return (ret);234}235236static int237cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)238{239int r, i, dcols, ret = 0;240241for (r = 0; r < rm->rm_nrows; r++) {242raidz_row_t *rr = rm->rm_row[r];243raidz_row_t *rrg = opts->rm_golden->rm_row[r];244dcols = opts->rm_golden->rm_row[0]->rr_cols -245raidz_parity(opts->rm_golden);246for (i = 0; i < dcols; i++) {247if (DATA_COL_SIZE(rrg, i) == 0) {248VERIFY0(DATA_COL_SIZE(rr, i));249continue;250}251252if (abd_cmp(DATA_COL(rrg, i),253DATA_COL(rr, i)) != 0) {254ret++;255256LOG_OPT(D_DEBUG, opts,257"\nData block [%d] different!\n", i);258}259}260}261return (ret);262}263264static int265init_rand(void *data, size_t size, void *private)266{267(void) private;268memcpy(data, rand_data, size);269return (0);270}271272static void273corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)274{275for (int r = 0; r < rm->rm_nrows; r++) {276raidz_row_t *rr = rm->rm_row[r];277for (int i = 0; i < cnt; i++) {278raidz_col_t *col = &rr->rr_col[tgts[i]];279abd_iterate_func(col->rc_abd, 0, col->rc_size,280init_rand, NULL);281}282}283}284285void286init_zio_abd(zio_t *zio)287{288abd_iterate_func(zio->io_abd, 0, zio->io_size, init_rand, NULL);289}290291static void292fini_raidz_map(zio_t **zio, raidz_map_t **rm)293{294vdev_raidz_map_free(*rm);295raidz_free((*zio)->io_abd, (*zio)->io_size);296umem_free(*zio, sizeof (zio_t));297298*zio = NULL;299*rm = NULL;300}301302static int303init_raidz_golden_map(raidz_test_opts_t *opts, const int parity)304{305int err = 0;306zio_t *zio_test;307raidz_map_t *rm_test;308const size_t total_ncols = opts->rto_dcols + parity;309310if (opts->rm_golden) {311fini_raidz_map(&opts->zio_golden, &opts->rm_golden);312}313314opts->zio_golden = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);315zio_test = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);316317opts->zio_golden->io_offset = zio_test->io_offset = opts->rto_offset;318opts->zio_golden->io_size = zio_test->io_size = opts->rto_dsize;319320opts->zio_golden->io_abd = raidz_alloc(opts->rto_dsize);321zio_test->io_abd = raidz_alloc(opts->rto_dsize);322323init_zio_abd(opts->zio_golden);324init_zio_abd(zio_test);325326VERIFY0(vdev_raidz_impl_set("original"));327328if (opts->rto_expand) {329opts->rm_golden =330vdev_raidz_map_alloc_expanded(opts->zio_golden,331opts->rto_ashift, total_ncols+1, total_ncols,332parity, opts->rto_expand_offset, 0, B_FALSE);333rm_test = vdev_raidz_map_alloc_expanded(zio_test,334opts->rto_ashift, total_ncols+1, total_ncols,335parity, opts->rto_expand_offset, 0, B_FALSE);336} else {337opts->rm_golden = vdev_raidz_map_alloc(opts->zio_golden,338opts->rto_ashift, total_ncols, parity);339rm_test = vdev_raidz_map_alloc(zio_test,340opts->rto_ashift, total_ncols, parity);341}342343VERIFY(opts->zio_golden);344VERIFY(opts->rm_golden);345346vdev_raidz_generate_parity(opts->rm_golden);347vdev_raidz_generate_parity(rm_test);348349/* sanity check */350err |= cmp_data(opts, rm_test);351err |= cmp_code(opts, rm_test, parity);352353if (err)354ERR("initializing the golden copy ... [FAIL]!\n");355356/* tear down raidz_map of test zio */357fini_raidz_map(&zio_test, &rm_test);358359return (err);360}361362static raidz_map_t *363init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)364{365raidz_map_t *rm = NULL;366const size_t alloc_dsize = opts->rto_dsize;367const size_t total_ncols = opts->rto_dcols + parity;368const int ccols[] = { 0, 1, 2 };369370VERIFY(zio);371VERIFY(parity <= 3 && parity >= 1);372373*zio = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);374375(*zio)->io_offset = 0;376(*zio)->io_size = alloc_dsize;377(*zio)->io_abd = raidz_alloc(alloc_dsize);378init_zio_abd(*zio);379380if (opts->rto_expand) {381rm = vdev_raidz_map_alloc_expanded(*zio,382opts->rto_ashift, total_ncols+1, total_ncols,383parity, opts->rto_expand_offset, 0, B_FALSE);384} else {385rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,386total_ncols, parity);387}388VERIFY(rm);389390/* Make sure code columns are destroyed */391corrupt_colums(rm, ccols, parity);392393return (rm);394}395396static int397run_gen_check(raidz_test_opts_t *opts)398{399char **impl_name;400int fn, err = 0;401zio_t *zio_test;402raidz_map_t *rm_test;403404err = init_raidz_golden_map(opts, PARITY_PQR);405if (0 != err)406return (err);407408LOG(D_INFO, DBLSEP);409LOG(D_INFO, "Testing parity generation...\n");410411for (impl_name = (char **)raidz_impl_names+1; *impl_name != NULL;412impl_name++) {413414LOG(D_INFO, SEP);415LOG(D_INFO, "\tTesting [%s] implementation...", *impl_name);416417if (0 != vdev_raidz_impl_set(*impl_name)) {418LOG(D_INFO, "[SKIP]\n");419continue;420} else {421LOG(D_INFO, "[SUPPORTED]\n");422}423424for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) {425426/* Check if should stop */427if (rto_opts.rto_should_stop)428return (err);429430/* create suitable raidz_map */431rm_test = init_raidz_map(opts, &zio_test, fn+1);432VERIFY(rm_test);433434LOG(D_INFO, "\t\tTesting method [%s] ...",435raidz_gen_name[fn]);436437if (!opts->rto_sanity)438vdev_raidz_generate_parity(rm_test);439440if (cmp_code(opts, rm_test, fn+1) != 0) {441LOG(D_INFO, "[FAIL]\n");442err++;443} else444LOG(D_INFO, "[PASS]\n");445446fini_raidz_map(&zio_test, &rm_test);447}448}449450fini_raidz_map(&opts->zio_golden, &opts->rm_golden);451452return (err);453}454455static int456run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)457{458int x0, x1, x2;459int tgtidx[3];460int err = 0;461static 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};470471memcpy(tgtidx, rec_tgts[fn], sizeof (tgtidx));472473if (fn < RAIDZ_REC_PQ) {474/* can reconstruct 1 failed data disk */475for (x0 = 0; x0 < opts->rto_dcols; x0++) {476if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))477continue;478479/* Check if should stop */480if (rto_opts.rto_should_stop)481return (err);482483LOG(D_DEBUG, "[%d] ", x0);484485tgtidx[2] = x0 + raidz_parity(rm);486487corrupt_colums(rm, tgtidx+2, 1);488489if (!opts->rto_sanity)490vdev_raidz_reconstruct(rm, tgtidx, 3);491492if (cmp_data(opts, rm) != 0) {493err++;494LOG(D_DEBUG, "\nREC D[%d]... [FAIL]\n", x0);495}496}497498} else if (fn < RAIDZ_REC_PQR) {499/* can reconstruct 2 failed data disk */500for (x0 = 0; x0 < opts->rto_dcols; x0++) {501if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))502continue;503for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {504if (x1 >= rm->rm_row[0]->rr_cols -505raidz_parity(rm))506continue;507508/* Check if should stop */509if (rto_opts.rto_should_stop)510return (err);511512LOG(D_DEBUG, "[%d %d] ", x0, x1);513514tgtidx[1] = x0 + raidz_parity(rm);515tgtidx[2] = x1 + raidz_parity(rm);516517corrupt_colums(rm, tgtidx+1, 2);518519if (!opts->rto_sanity)520vdev_raidz_reconstruct(rm, tgtidx, 3);521522if (cmp_data(opts, rm) != 0) {523err++;524LOG(D_DEBUG, "\nREC D[%d %d]... "525"[FAIL]\n", x0, x1);526}527}528}529} else {530/* can reconstruct 3 failed data disk */531for (x0 = 0; x0 < opts->rto_dcols; x0++) {532if (x0 >= rm->rm_row[0]->rr_cols - raidz_parity(rm))533continue;534for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {535if (x1 >= rm->rm_row[0]->rr_cols -536raidz_parity(rm))537continue;538for (x2 = x1 + 1; x2 < opts->rto_dcols; x2++) {539if (x2 >= rm->rm_row[0]->rr_cols -540raidz_parity(rm))541continue;542543/* Check if should stop */544if (rto_opts.rto_should_stop)545return (err);546547LOG(D_DEBUG, "[%d %d %d]", x0, x1, x2);548549tgtidx[0] = x0 + raidz_parity(rm);550tgtidx[1] = x1 + raidz_parity(rm);551tgtidx[2] = x2 + raidz_parity(rm);552553corrupt_colums(rm, tgtidx, 3);554555if (!opts->rto_sanity)556vdev_raidz_reconstruct(rm,557tgtidx, 3);558559if (cmp_data(opts, rm) != 0) {560err++;561LOG(D_DEBUG,562"\nREC D[%d %d %d]... "563"[FAIL]\n", x0, x1, x2);564}565}566}567}568}569return (err);570}571572static int573run_rec_check(raidz_test_opts_t *opts)574{575char **impl_name;576unsigned fn, err = 0;577zio_t *zio_test;578raidz_map_t *rm_test;579580err = init_raidz_golden_map(opts, PARITY_PQR);581if (0 != err)582return (err);583584LOG(D_INFO, DBLSEP);585LOG(D_INFO, "Testing data reconstruction...\n");586587for (impl_name = (char **)raidz_impl_names+1; *impl_name != NULL;588impl_name++) {589590LOG(D_INFO, SEP);591LOG(D_INFO, "\tTesting [%s] implementation...", *impl_name);592593if (vdev_raidz_impl_set(*impl_name) != 0) {594LOG(D_INFO, "[SKIP]\n");595continue;596} else597LOG(D_INFO, "[SUPPORTED]\n");598599600/* create suitable raidz_map */601rm_test = init_raidz_map(opts, &zio_test, PARITY_PQR);602/* generate parity */603vdev_raidz_generate_parity(rm_test);604605for (fn = 0; fn < RAIDZ_REC_NUM; fn++) {606607LOG(D_INFO, "\t\tTesting method [%s] ...",608raidz_rec_name[fn]);609610if (run_rec_check_impl(opts, rm_test, fn) != 0) {611LOG(D_INFO, "[FAIL]\n");612err++;613614} else615LOG(D_INFO, "[PASS]\n");616617}618/* tear down test raidz_map */619fini_raidz_map(&zio_test, &rm_test);620}621622fini_raidz_map(&opts->zio_golden, &opts->rm_golden);623624return (err);625}626627static int628run_test(raidz_test_opts_t *opts)629{630int err = 0;631632if (opts == NULL)633opts = &rto_opts;634635print_opts(opts, B_FALSE);636637err |= run_gen_check(opts);638err |= run_rec_check(opts);639640return (err);641}642643#define SWEEP_RUNNING 0644#define SWEEP_FINISHED 1645#define SWEEP_ERROR 2646#define SWEEP_TIMEOUT 3647648static int sweep_state = 0;649static raidz_test_opts_t failed_opts;650651static kmutex_t sem_mtx;652static kcondvar_t sem_cv;653static int max_free_slots;654static int free_slots;655656static __attribute__((noreturn)) void657sweep_thread(void *arg)658{659int err = 0;660raidz_test_opts_t *opts = (raidz_test_opts_t *)arg;661VERIFY(opts != NULL);662663err = run_test(opts);664665if (rto_opts.rto_sanity) {666/* 25% chance that a sweep test fails */667if (rand() < (RAND_MAX/4))668err = 1;669}670671if (0 != err) {672mutex_enter(&sem_mtx);673memcpy(&failed_opts, opts, sizeof (raidz_test_opts_t));674sweep_state = SWEEP_ERROR;675mutex_exit(&sem_mtx);676}677678umem_free(opts, sizeof (raidz_test_opts_t));679680/* signal the next thread */681mutex_enter(&sem_mtx);682free_slots++;683cv_signal(&sem_cv);684mutex_exit(&sem_mtx);685686thread_exit();687}688689static int690run_sweep(void)691{692static const size_t dcols_v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 12, 15, 16 };693static const size_t ashift_v[] = { 9, 12, 14 };694static const size_t size_v[] = { 1 << 9, 21 * (1 << 9), 13 * (1 << 12),6951 << 17, (1 << 20) - (1 << 12), SPA_MAXBLOCKSIZE };696697(void) setvbuf(stdout, NULL, _IONBF, 0);698699ulong_t total_comb = ARRAY_SIZE(size_v) * ARRAY_SIZE(ashift_v) *700ARRAY_SIZE(dcols_v);701ulong_t tried_comb = 0;702hrtime_t time_diff, start_time = gethrtime();703raidz_test_opts_t *opts;704int a, d, s;705706max_free_slots = free_slots = MAX(2, boot_ncpus);707708mutex_init(&sem_mtx, NULL, MUTEX_DEFAULT, NULL);709cv_init(&sem_cv, NULL, CV_DEFAULT, NULL);710711for (s = 0; s < ARRAY_SIZE(size_v); s++)712for (a = 0; a < ARRAY_SIZE(ashift_v); a++)713for (d = 0; d < ARRAY_SIZE(dcols_v); d++) {714715if (size_v[s] < (1 << ashift_v[a])) {716total_comb--;717continue;718}719720if (++tried_comb % 20 == 0)721LOG(D_ALL, "%lu/%lu... ", tried_comb, total_comb);722723/* wait for signal to start new thread */724mutex_enter(&sem_mtx);725while (cv_timedwait_sig(&sem_cv, &sem_mtx,726ddi_get_lbolt() + hz)) {727728/* check if should stop the test (timeout) */729time_diff = (gethrtime() - start_time) / NANOSEC;730if (rto_opts.rto_sweep_timeout > 0 &&731time_diff >= rto_opts.rto_sweep_timeout) {732sweep_state = SWEEP_TIMEOUT;733rto_opts.rto_should_stop = B_TRUE;734mutex_exit(&sem_mtx);735goto exit;736}737738/* check if should stop the test (error) */739if (sweep_state != SWEEP_RUNNING) {740mutex_exit(&sem_mtx);741goto exit;742}743744/* exit loop if a slot is available */745if (free_slots > 0) {746break;747}748}749750free_slots--;751mutex_exit(&sem_mtx);752753opts = umem_zalloc(sizeof (raidz_test_opts_t), UMEM_NOFAIL);754opts->rto_ashift = ashift_v[a];755opts->rto_dcols = dcols_v[d];756opts->rto_offset = (1ULL << ashift_v[a]) * rand();757opts->rto_dsize = size_v[s];758opts->rto_expand = rto_opts.rto_expand;759opts->rto_expand_offset = rto_opts.rto_expand_offset;760opts->rto_v = 0; /* be quiet */761762VERIFY3P(thread_create(NULL, 0, sweep_thread, (void *) opts,7630, NULL, TS_RUN, defclsyspri), !=, NULL);764}765766exit:767LOG(D_ALL, "\nWaiting for test threads to finish...\n");768mutex_enter(&sem_mtx);769VERIFY(free_slots <= max_free_slots);770while (free_slots < max_free_slots) {771(void) cv_wait(&sem_cv, &sem_mtx);772}773mutex_exit(&sem_mtx);774775if (sweep_state == SWEEP_ERROR) {776ERR("Sweep test failed! Failed option: \n");777print_opts(&failed_opts, B_TRUE);778} else {779if (sweep_state == SWEEP_TIMEOUT)780LOG(D_ALL, "Test timeout (%lus). Stopping...\n",781(ulong_t)rto_opts.rto_sweep_timeout);782783LOG(D_ALL, "Sweep test succeeded on %lu raidz maps!\n",784(ulong_t)tried_comb);785}786787mutex_destroy(&sem_mtx);788789return (sweep_state == SWEEP_ERROR ? SWEEP_ERROR : 0);790}791792793int794main(int argc, char **argv)795{796size_t i;797struct sigaction action;798int err = 0;799800/* init gdb pid string early */801(void) sprintf(pid_s, "%d", getpid());802803action.sa_handler = sig_handler;804sigemptyset(&action.sa_mask);805action.sa_flags = 0;806807if (sigaction(SIGSEGV, &action, NULL) < 0) {808ERR("raidz_test: cannot catch SIGSEGV: %s.\n", strerror(errno));809exit(EXIT_FAILURE);810}811812(void) setvbuf(stdout, NULL, _IOLBF, 0);813814dprintf_setup(&argc, argv);815816process_options(argc, argv);817818kernel_init(SPA_MODE_READ);819820/* setup random data because rand() is not reentrant */821rand_data = (int *)umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);822srand((unsigned)time(NULL) * getpid());823for (i = 0; i < SPA_MAXBLOCKSIZE / sizeof (int); i++)824rand_data[i] = rand();825826mprotect(rand_data, SPA_MAXBLOCKSIZE, PROT_READ);827828if (rto_opts.rto_benchmark) {829run_raidz_benchmark();830} else if (rto_opts.rto_sweep) {831err = run_sweep();832} else {833err = run_test(NULL);834}835836umem_free(rand_data, SPA_MAXBLOCKSIZE);837kernel_fini();838839return (err);840}841842843