X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=cmd%2Fztest%2Fztest.c;h=93a5f1ecf54a68ae71272ae57aa51b9951375c55;hb=refs%2Fheads%2Frertzinger%2Ffeature-zpool-get--p;hp=8655b237cd996d92a96b456bfa50ec3b0c4885b8;hpb=c242c188fd7df8ecdb793a3d12ed584cbe3ff424;p=zfs.git diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index 8655b23..93a5f1e 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -109,6 +109,7 @@ #include #include #include +#include #include #include #include @@ -121,8 +122,8 @@ #include #include -#define ZTEST_FD_DATA 3 -#define ZTEST_FD_RAND 4 +static int ztest_fd_data = -1; +static int ztest_fd_rand = -1; typedef struct ztest_shared_hdr { uint64_t zh_hdr_size; @@ -330,6 +331,7 @@ ztest_func_t ztest_vdev_add_remove; ztest_func_t ztest_vdev_aux_add_remove; ztest_func_t ztest_split_pool; ztest_func_t ztest_reguid; +ztest_func_t ztest_spa_upgrade; uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */ uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */ @@ -360,17 +362,12 @@ ztest_info_t ztest_info[] = { { ztest_fault_inject, 1, &zopt_sometimes }, { ztest_ddt_repair, 1, &zopt_sometimes }, { ztest_dmu_snapshot_hold, 1, &zopt_sometimes }, - /* - * The reguid test is currently broken. Disable it until - * we get around to fixing it. - */ -#if 0 { ztest_reguid, 1, &zopt_sometimes }, -#endif { ztest_spa_rename, 1, &zopt_rarely }, { ztest_scrub, 1, &zopt_rarely }, + { ztest_spa_upgrade, 1, &zopt_rarely }, { ztest_dsl_dataset_promote_busy, 1, &zopt_rarely }, - { ztest_vdev_attach_detach, 1, &zopt_rarely }, + { ztest_vdev_attach_detach, 1, &zopt_rarely }, { ztest_vdev_LUN_growth, 1, &zopt_rarely }, { ztest_vdev_add_remove, 1, &ztest_opts.zo_vdevtime }, @@ -421,6 +418,13 @@ static spa_t *ztest_spa = NULL; static ztest_ds_t *ztest_ds; static kmutex_t ztest_vdev_lock; + +/* + * The ztest_name_lock protects the pool and dataset namespace used by + * the individual tests. To modify the namespace, consumers must grab + * this lock as writer. Grabbing the lock as reader will ensure that the + * namespace does not change while the lock is held. + */ static krwlock_t ztest_name_lock; static boolean_t ztest_dump_core = B_TRUE; @@ -729,14 +733,17 @@ process_options(int argc, char **argv) UINT64_MAX >> 2); if (strlen(altdir) > 0) { - char cmd[MAXNAMELEN]; - char realaltdir[MAXNAMELEN]; + char *cmd; + char *realaltdir; char *bin; char *ztest; char *isa; int isalen; - (void) realpath(getexecname(), cmd); + cmd = umem_alloc(MAXPATHLEN, UMEM_NOFAIL); + realaltdir = umem_alloc(MAXPATHLEN, UMEM_NOFAIL); + + VERIFY(NULL != realpath(getexecname(), cmd)); if (0 != access(altdir, F_OK)) { ztest_dump_core = B_FALSE; fatal(B_TRUE, "invalid alternate ztest path: %s", @@ -767,6 +774,9 @@ process_options(int argc, char **argv) fatal(B_TRUE, "invalid alternate lib directory %s", zo->zo_alt_libpath); } + + umem_free(cmd, MAXPATHLEN); + umem_free(realaltdir, MAXPATHLEN); } } @@ -783,10 +793,12 @@ ztest_random(uint64_t range) { uint64_t r; + ASSERT3S(ztest_fd_rand, >=, 0); + if (range == 0) return (0); - if (read(ZTEST_FD_RAND, &r, sizeof (r)) != sizeof (r)) + if (read(ztest_fd_rand, &r, sizeof (r)) != sizeof (r)) fatal(1, "short read from /dev/urandom"); return (r % range); @@ -808,7 +820,7 @@ ztest_get_ashift(void) } static nvlist_t * -make_vdev_file(char *path, char *aux, size_t size, uint64_t ashift) +make_vdev_file(char *path, char *aux, char *pool, size_t size, uint64_t ashift) { char *pathbuf; uint64_t vdev; @@ -826,12 +838,13 @@ make_vdev_file(char *path, char *aux, size_t size, uint64_t ashift) vdev = ztest_shared->zs_vdev_aux; (void) snprintf(path, MAXPATHLEN, ztest_aux_template, ztest_opts.zo_dir, - ztest_opts.zo_pool, aux, vdev); + pool == NULL ? ztest_opts.zo_pool : pool, + aux, vdev); } else { vdev = ztest_shared->zs_vdev_next_leaf++; (void) snprintf(path, MAXPATHLEN, ztest_dev_template, ztest_opts.zo_dir, - ztest_opts.zo_pool, vdev); + pool == NULL ? ztest_opts.zo_pool : pool, vdev); } } @@ -854,17 +867,18 @@ make_vdev_file(char *path, char *aux, size_t size, uint64_t ashift) } static nvlist_t * -make_vdev_raidz(char *path, char *aux, size_t size, uint64_t ashift, int r) +make_vdev_raidz(char *path, char *aux, char *pool, size_t size, + uint64_t ashift, int r) { nvlist_t *raidz, **child; int c; if (r < 2) - return (make_vdev_file(path, aux, size, ashift)); + return (make_vdev_file(path, aux, pool, size, ashift)); child = umem_alloc(r * sizeof (nvlist_t *), UMEM_NOFAIL); for (c = 0; c < r; c++) - child[c] = make_vdev_file(path, aux, size, ashift); + child[c] = make_vdev_file(path, aux, pool, size, ashift); VERIFY(nvlist_alloc(&raidz, NV_UNIQUE_NAME, 0) == 0); VERIFY(nvlist_add_string(raidz, ZPOOL_CONFIG_TYPE, @@ -883,19 +897,19 @@ make_vdev_raidz(char *path, char *aux, size_t size, uint64_t ashift, int r) } static nvlist_t * -make_vdev_mirror(char *path, char *aux, size_t size, uint64_t ashift, - int r, int m) +make_vdev_mirror(char *path, char *aux, char *pool, size_t size, + uint64_t ashift, int r, int m) { nvlist_t *mirror, **child; int c; if (m < 1) - return (make_vdev_raidz(path, aux, size, ashift, r)); + return (make_vdev_raidz(path, aux, pool, size, ashift, r)); child = umem_alloc(m * sizeof (nvlist_t *), UMEM_NOFAIL); for (c = 0; c < m; c++) - child[c] = make_vdev_raidz(path, aux, size, ashift, r); + child[c] = make_vdev_raidz(path, aux, pool, size, ashift, r); VERIFY(nvlist_alloc(&mirror, NV_UNIQUE_NAME, 0) == 0); VERIFY(nvlist_add_string(mirror, ZPOOL_CONFIG_TYPE, @@ -912,8 +926,8 @@ make_vdev_mirror(char *path, char *aux, size_t size, uint64_t ashift, } static nvlist_t * -make_vdev_root(char *path, char *aux, size_t size, uint64_t ashift, - int log, int r, int m, int t) +make_vdev_root(char *path, char *aux, char *pool, size_t size, uint64_t ashift, + int log, int r, int m, int t) { nvlist_t *root, **child; int c; @@ -923,7 +937,8 @@ make_vdev_root(char *path, char *aux, size_t size, uint64_t ashift, child = umem_alloc(t * sizeof (nvlist_t *), UMEM_NOFAIL); for (c = 0; c < t; c++) { - child[c] = make_vdev_mirror(path, aux, size, ashift, r, m); + child[c] = make_vdev_mirror(path, aux, pool, size, ashift, + r, m); VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_IS_LOG, log) == 0); } @@ -941,6 +956,27 @@ make_vdev_root(char *path, char *aux, size_t size, uint64_t ashift, return (root); } +/* + * Find a random spa version. Returns back a random spa version in the + * range [initial_version, SPA_VERSION_FEATURES]. + */ +static uint64_t +ztest_random_spa_version(uint64_t initial_version) +{ + uint64_t version = initial_version; + + if (version <= SPA_VERSION_BEFORE_FEATURES) { + version = version + + ztest_random(SPA_VERSION_BEFORE_FEATURES - version + 1); + } + + if (version > SPA_VERSION_BEFORE_FEATURES) + version = SPA_VERSION_FEATURES; + + ASSERT(SPA_VERSION_IS_SUPPORTED(version)); + return (version); +} + static int ztest_random_blocksize(void) { @@ -1003,7 +1039,7 @@ ztest_dsl_prop_set_uint64(char *osname, zfs_prop_t prop, uint64_t value, ztest_record_enospc(FTAG); return (error); } - ASSERT3U(error, ==, 0); + ASSERT0(error); setpoint = umem_alloc(MAXPATHLEN, UMEM_NOFAIL); VERIFY3U(dsl_prop_get(osname, propname, sizeof (curval), @@ -1037,7 +1073,7 @@ ztest_spa_prop_set_uint64(zpool_prop_t prop, uint64_t value) ztest_record_enospc(FTAG); return (error); } - ASSERT3U(error, ==, 0); + ASSERT0(error); return (error); } @@ -1740,7 +1776,7 @@ ztest_replay_setattr(ztest_ds_t *zd, lr_setattr_t *lr, boolean_t byteswap) ASSERT3U(lr->lr_size, >=, sizeof (*bbt)); ASSERT3U(lr->lr_size, <=, db->db_size); - VERIFY3U(dmu_set_bonus(db, lr->lr_size, tx), ==, 0); + VERIFY0(dmu_set_bonus(db, lr->lr_size, tx)); bbt = ztest_bt_bonus(db); ztest_bt_generate(bbt, os, lr->lr_foid, -1ULL, lr->lr_mode, txg, crtxg); @@ -1756,19 +1792,19 @@ ztest_replay_setattr(ztest_ds_t *zd, lr_setattr_t *lr, boolean_t byteswap) return (0); } -zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = { +zil_replay_func_t ztest_replay_vector[TX_MAX_TYPE] = { NULL, /* 0 no such transaction type */ - (zil_replay_func_t *)ztest_replay_create, /* TX_CREATE */ + (zil_replay_func_t)ztest_replay_create, /* TX_CREATE */ NULL, /* TX_MKDIR */ NULL, /* TX_MKXATTR */ NULL, /* TX_SYMLINK */ - (zil_replay_func_t *)ztest_replay_remove, /* TX_REMOVE */ + (zil_replay_func_t)ztest_replay_remove, /* TX_REMOVE */ NULL, /* TX_RMDIR */ NULL, /* TX_LINK */ NULL, /* TX_RENAME */ - (zil_replay_func_t *)ztest_replay_write, /* TX_WRITE */ - (zil_replay_func_t *)ztest_replay_truncate, /* TX_TRUNCATE */ - (zil_replay_func_t *)ztest_replay_setattr, /* TX_SETATTR */ + (zil_replay_func_t)ztest_replay_write, /* TX_WRITE */ + (zil_replay_func_t)ztest_replay_truncate, /* TX_TRUNCATE */ + (zil_replay_func_t)ztest_replay_setattr, /* TX_SETATTR */ NULL, /* TX_ACL */ NULL, /* TX_CREATE_ACL */ NULL, /* TX_CREATE_ATTR */ @@ -2267,6 +2303,7 @@ ztest_zil_remount(ztest_ds_t *zd, uint64_t id) { objset_t *os = zd->zd_os; + mutex_enter(&zd->zd_dirobj_lock); (void) rw_enter(&zd->zd_zilog_lock, RW_WRITER); /* zfs_sb_teardown() */ @@ -2277,6 +2314,7 @@ ztest_zil_remount(ztest_ds_t *zd, uint64_t id) zil_replay(os, zd, ztest_replay_vector); (void) rw_exit(&zd->zd_zilog_lock); + mutex_exit(&zd->zd_dirobj_lock); } /* @@ -2294,7 +2332,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id) /* * Attempt to create using a bad file. */ - nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1); + nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1); VERIFY3U(ENOENT, ==, spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL)); nvlist_free(nvroot); @@ -2302,7 +2340,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id) /* * Attempt to create using a bad mirror. */ - nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 2, 1); + nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 2, 1); VERIFY3U(ENOENT, ==, spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL)); nvlist_free(nvroot); @@ -2312,7 +2350,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id) * what's in the nvroot; we should fail with EEXIST. */ (void) rw_enter(&ztest_name_lock, RW_READER); - nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1); + nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1); VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL)); nvlist_free(nvroot); VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG)); @@ -2322,6 +2360,78 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id) (void) rw_exit(&ztest_name_lock); } +/* ARGSUSED */ +void +ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id) +{ + spa_t *spa; + uint64_t initial_version = SPA_VERSION_INITIAL; + uint64_t version, newversion; + nvlist_t *nvroot, *props; + char *name; + + mutex_enter(&ztest_vdev_lock); + name = kmem_asprintf("%s_upgrade", ztest_opts.zo_pool); + + /* + * Clean up from previous runs. + */ + (void) spa_destroy(name); + + nvroot = make_vdev_root(NULL, NULL, name, ztest_opts.zo_vdev_size, 0, + 0, ztest_opts.zo_raidz, ztest_opts.zo_mirrors, 1); + + /* + * If we're configuring a RAIDZ device then make sure that the + * the initial version is capable of supporting that feature. + */ + switch (ztest_opts.zo_raidz_parity) { + case 0: + case 1: + initial_version = SPA_VERSION_INITIAL; + break; + case 2: + initial_version = SPA_VERSION_RAIDZ2; + break; + case 3: + initial_version = SPA_VERSION_RAIDZ3; + break; + } + + /* + * Create a pool with a spa version that can be upgraded. Pick + * a value between initial_version and SPA_VERSION_BEFORE_FEATURES. + */ + do { + version = ztest_random_spa_version(initial_version); + } while (version > SPA_VERSION_BEFORE_FEATURES); + + props = fnvlist_alloc(); + fnvlist_add_uint64(props, + zpool_prop_to_name(ZPOOL_PROP_VERSION), version); + VERIFY3S(spa_create(name, nvroot, props, NULL, NULL), ==, 0); + fnvlist_free(nvroot); + fnvlist_free(props); + + VERIFY3S(spa_open(name, &spa, FTAG), ==, 0); + VERIFY3U(spa_version(spa), ==, version); + newversion = ztest_random_spa_version(version + 1); + + if (ztest_opts.zo_verbose >= 4) { + (void) printf("upgrading spa version from %llu to %llu\n", + (u_longlong_t)version, (u_longlong_t)newversion); + } + + spa_upgrade(spa, newversion); + VERIFY3U(spa_version(spa), >, version); + VERIFY3U(spa_version(spa), ==, fnvlist_lookup_uint64(spa->spa_config, + zpool_prop_to_name(ZPOOL_PROP_VERSION))); + spa_close(spa, FTAG); + + strfree(name); + mutex_exit(&ztest_vdev_lock); +} + static vdev_t * vdev_lookup_by_path(vdev_t *vd, const char *path) { @@ -2412,7 +2522,7 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id) /* * Make 1/4 of the devices be log devices. */ - nvroot = make_vdev_root(NULL, NULL, + nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0, ztest_random(4) == 0, ztest_opts.zo_raidz, zs->zs_mirrors, 1); @@ -2471,7 +2581,7 @@ ztest_vdev_aux_add_remove(ztest_ds_t *zd, uint64_t id) zs->zs_vdev_aux = 0; for (;;) { int c; - (void) snprintf(path, sizeof (path), ztest_aux_template, + (void) snprintf(path, MAXPATHLEN, ztest_aux_template, ztest_opts.zo_dir, ztest_opts.zo_pool, aux, zs->zs_vdev_aux); for (c = 0; c < sav->sav_count; c++) @@ -2491,7 +2601,7 @@ ztest_vdev_aux_add_remove(ztest_ds_t *zd, uint64_t id) /* * Add a new device. */ - nvlist_t *nvroot = make_vdev_root(NULL, aux, + nvlist_t *nvroot = make_vdev_root(NULL, aux, NULL, (ztest_opts.zo_vdev_size * 5) / 4, 0, 0, 0, 0, 1); error = spa_vdev_add(spa, nvroot); if (error != 0) @@ -2764,7 +2874,7 @@ ztest_vdev_attach_detach(ztest_ds_t *zd, uint64_t id) /* * Build the nvlist describing newpath. */ - root = make_vdev_root(newpath, NULL, newvd == NULL ? newsize : 0, + root = make_vdev_root(newpath, NULL, NULL, newvd == NULL ? newsize : 0, ashift, 0, 0, 0, 1); error = spa_vdev_attach(spa, oldguid, root, replacing); @@ -3090,7 +3200,7 @@ ztest_objset_destroy_cb(const char *name, void *arg) error = dmu_object_info(os, ZTEST_DIROBJ, &doi); if (error != ENOENT) { /* We could have crashed in the middle of destroying it */ - ASSERT3U(error, ==, 0); + ASSERT0(error); ASSERT3U(doi.doi_type, ==, DMU_OT_ZAP_OTHER); ASSERT3S(doi.doi_physical_blocks_512, >=, 0); } @@ -3563,10 +3673,10 @@ ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id) */ error = dmu_read(os, packobj, packoff, packsize, packbuf, DMU_READ_PREFETCH); - ASSERT3U(error, ==, 0); + ASSERT0(error); error = dmu_read(os, bigobj, bigoff, bigsize, bigbuf, DMU_READ_PREFETCH); - ASSERT3U(error, ==, 0); + ASSERT0(error); /* * Get a tx for the mods to both packobj and bigobj. @@ -3889,10 +3999,10 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id) if (i != 0 || ztest_random(2) != 0) { error = dmu_read(os, packobj, packoff, packsize, packbuf, DMU_READ_PREFETCH); - ASSERT3U(error, ==, 0); + ASSERT0(error); error = dmu_read(os, bigobj, bigoff, bigsize, bigbuf, DMU_READ_PREFETCH); - ASSERT3U(error, ==, 0); + ASSERT0(error); } compare_and_update_pbbufs(s, packbuf, bigbuf, bigsize, n, chunksize, txg); @@ -4177,7 +4287,7 @@ ztest_zap(ztest_ds_t *zd, uint64_t id) if (error == ENOENT) goto out; - ASSERT3U(error, ==, 0); + ASSERT0(error); tx = dmu_tx_create(os); dmu_tx_hold_zap(tx, object, B_TRUE, NULL); @@ -4384,7 +4494,7 @@ ztest_commit_callback(void *arg, int error) data->zcd_called = B_TRUE; if (error == ECANCELED) { - ASSERT3U(data->zcd_txg, ==, 0); + ASSERT0(data->zcd_txg); ASSERT(!data->zcd_added); /* @@ -4594,7 +4704,7 @@ ztest_spa_prop_get_set(ztest_ds_t *zd, uint64_t id) (void) ztest_spa_prop_set_uint64(ZPOOL_PROP_DEDUPDITTO, ZIO_DEDUPDITTO_MIN + ztest_random(ZIO_DEDUPDITTO_MIN)); - VERIFY3U(spa_prop_get(ztest_spa, &props), ==, 0); + VERIFY0(spa_prop_get(ztest_spa, &props)); if (ztest_opts.zo_verbose >= 6) dump_nvlist(props, 4); @@ -4855,7 +4965,18 @@ ztest_fault_inject(ztest_ds_t *zd, uint64_t id) if (islog) (void) rw_exit(&ztest_name_lock); } else { + /* + * Ideally we would like to be able to randomly + * call vdev_[on|off]line without holding locks + * to force unpredictable failures but the side + * effects of vdev_[on|off]line prevent us from + * doing so. We grab the ztest_vdev_lock here to + * prevent a race between injection testing and + * aux_vdev removal. + */ + mutex_enter(&ztest_vdev_lock); (void) vdev_online(spa, guid0, 0, NULL); + mutex_exit(&ztest_vdev_lock); } } @@ -5031,13 +5152,19 @@ ztest_reguid(ztest_ds_t *zd, uint64_t id) { spa_t *spa = ztest_spa; uint64_t orig, load; + int error; orig = spa_guid(spa); load = spa_load_guid(spa); - if (spa_change_guid(spa) != 0) + + (void) rw_enter(&ztest_name_lock, RW_WRITER); + error = spa_change_guid(spa); + (void) rw_exit(&ztest_name_lock); + + if (error != 0) return; - if (ztest_opts.zo_verbose >= 3) { + if (ztest_opts.zo_verbose >= 4) { (void) printf("Changed guid old %llu -> %llu\n", (u_longlong_t)orig, (u_longlong_t)spa_guid(spa)); } @@ -5281,11 +5408,13 @@ ztest_resume_thread(void *arg) #define GRACE 300 +#if 0 static void ztest_deadman_alarm(int sig) { fatal(0, "failed to complete within %d seconds of deadline", GRACE); } +#endif static void ztest_execute(int test, ztest_info_t *zi, uint64_t id) @@ -5428,7 +5557,7 @@ ztest_dataset_open(int d) } ASSERT(error == 0 || error == EEXIST); - VERIFY3U(dmu_objset_hold(name, zd, &os), ==, 0); + VERIFY0(dmu_objset_hold(name, zd, &os)); (void) rw_exit(&ztest_name_lock); ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os); @@ -5542,11 +5671,13 @@ ztest_run(ztest_shared_t *zs) (thread_func_t)ztest_resume_thread, spa, TS_RUN, NULL, 0, 0, PTHREAD_CREATE_JOINABLE)), !=, NULL); +#if 0 /* * Set a deadman alarm to abort() if we hang. */ signal(SIGALRM, ztest_deadman_alarm); alarm((zs->zs_thread_stop - zs->zs_thread_start) / NANOSEC + GRACE); +#endif /* * Verify that we can safely inquire about about any object, @@ -5626,7 +5757,7 @@ ztest_run(ztest_shared_t *zs) /* Verify that at least one commit cb was called in a timely fashion */ if (zc_cb_counter >= ZTEST_COMMIT_CB_MIN_REG) - VERIFY3U(zc_min_txg_delay, ==, 0); + VERIFY0(zc_min_txg_delay); spa_close(spa, FTAG); @@ -5723,8 +5854,15 @@ ztest_freeze(void) */ kernel_init(FREAD | FWRITE); VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG)); + ASSERT(spa_freeze_txg(spa) == UINT64_MAX); VERIFY3U(0, ==, ztest_dataset_open(0)); ztest_dataset_close(0); + + spa->spa_debug = B_TRUE; + ztest_spa = spa; + txg_wait_synced(spa_get_dsl(spa), 0); + ztest_reguid(NULL, 0); + spa_close(spa, FTAG); kernel_fini(); } @@ -5759,10 +5897,9 @@ make_random_props(void) { nvlist_t *props; - if (ztest_random(2) == 0) - return (NULL); - VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0); + if (ztest_random(2) == 0) + return (props); VERIFY(nvlist_add_uint64(props, "autoreplace", 1) == 0); return (props); @@ -5777,6 +5914,7 @@ ztest_init(ztest_shared_t *zs) { spa_t *spa; nvlist_t *nvroot, *props; + int i; mutex_init(&ztest_vdev_lock, NULL, MUTEX_DEFAULT, NULL); rw_init(&ztest_name_lock, NULL, RW_DEFAULT, NULL); @@ -5790,9 +5928,16 @@ ztest_init(ztest_shared_t *zs) ztest_shared->zs_vdev_next_leaf = 0; zs->zs_splits = 0; zs->zs_mirrors = ztest_opts.zo_mirrors; - nvroot = make_vdev_root(NULL, NULL, ztest_opts.zo_vdev_size, 0, + nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0, 0, ztest_opts.zo_raidz, zs->zs_mirrors, 1); props = make_random_props(); + for (i = 0; i < SPA_FEATURES; i++) { + char *buf; + VERIFY3S(-1, !=, asprintf(&buf, "feature@%s", + spa_feature_table[i].fi_uname)); + VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0)); + free(buf); + } VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props, NULL, NULL)); nvlist_free(nvroot); @@ -5815,38 +5960,41 @@ ztest_init(ztest_shared_t *zs) } static void -setup_fds(void) +setup_data_fd(void) { - int fd; + static char ztest_name_data[] = "/tmp/ztest.data.XXXXXX"; - char *tmp = tempnam(NULL, NULL); - fd = open(tmp, O_RDWR | O_CREAT, 0700); - ASSERT3S(fd, >=, 0); - VERIFY3S(ftruncate(fd, sizeof (ztest_shared_hdr_t)), ==, 0); - if (fd != ZTEST_FD_DATA) { - VERIFY3S(dup2(fd, ZTEST_FD_DATA), ==, ZTEST_FD_DATA); - close(fd); - } - (void) unlink(tmp); - free(tmp); + ztest_fd_data = mkstemp(ztest_name_data); + ASSERT3S(ztest_fd_data, >=, 0); + (void) unlink(ztest_name_data); +} - fd = open("/dev/urandom", O_RDONLY); - ASSERT3S(fd, >=, 0); - if (fd != ZTEST_FD_RAND) { - VERIFY3S(dup2(fd, ZTEST_FD_RAND), ==, ZTEST_FD_RAND); - close(fd); - } +static int +shared_data_size(ztest_shared_hdr_t *hdr) +{ + int size; + + size = hdr->zh_hdr_size; + size += hdr->zh_opts_size; + size += hdr->zh_size; + size += hdr->zh_stats_size * hdr->zh_stats_count; + size += hdr->zh_ds_size * hdr->zh_ds_count; + + return (size); } static void setup_hdr(void) { + int size; ztest_shared_hdr_t *hdr; hdr = (void *)mmap(0, P2ROUNDUP(sizeof (*hdr), getpagesize()), - PROT_READ | PROT_WRITE, MAP_SHARED, ZTEST_FD_DATA, 0); + PROT_READ | PROT_WRITE, MAP_SHARED, ztest_fd_data, 0); ASSERT(hdr != MAP_FAILED); + VERIFY3U(0, ==, ftruncate(ztest_fd_data, sizeof (ztest_shared_hdr_t))); + hdr->zh_hdr_size = sizeof (ztest_shared_hdr_t); hdr->zh_opts_size = sizeof (ztest_shared_opts_t); hdr->zh_size = sizeof (ztest_shared_t); @@ -5855,6 +6003,9 @@ setup_hdr(void) hdr->zh_ds_size = sizeof (ztest_shared_ds_t); hdr->zh_ds_count = ztest_opts.zo_datasets; + size = shared_data_size(hdr); + VERIFY3U(0, ==, ftruncate(ztest_fd_data, size)); + (void) munmap((caddr_t)hdr, P2ROUNDUP(sizeof (*hdr), getpagesize())); } @@ -5866,18 +6017,14 @@ setup_data(void) uint8_t *buf; hdr = (void *)mmap(0, P2ROUNDUP(sizeof (*hdr), getpagesize()), - PROT_READ, MAP_SHARED, ZTEST_FD_DATA, 0); + PROT_READ, MAP_SHARED, ztest_fd_data, 0); ASSERT(hdr != MAP_FAILED); - size = hdr->zh_hdr_size; - size += hdr->zh_opts_size; - size += hdr->zh_size; - size += hdr->zh_stats_size * hdr->zh_stats_count; - size += hdr->zh_ds_size * hdr->zh_ds_count; + size = shared_data_size(hdr); (void) munmap((caddr_t)hdr, P2ROUNDUP(sizeof (*hdr), getpagesize())); hdr = ztest_shared_hdr = (void *)mmap(0, P2ROUNDUP(size, getpagesize()), - PROT_READ | PROT_WRITE, MAP_SHARED, ZTEST_FD_DATA, 0); + PROT_READ | PROT_WRITE, MAP_SHARED, ztest_fd_data, 0); ASSERT(hdr != MAP_FAILED); buf = (uint8_t *)hdr; @@ -5896,12 +6043,13 @@ exec_child(char *cmd, char *libpath, boolean_t ignorekill, int *statusp) { pid_t pid; int status; - char cmdbuf[MAXPATHLEN]; + char *cmdbuf = NULL; pid = fork(); if (cmd == NULL) { - (void) strlcpy(cmdbuf, getexecname(), sizeof (cmdbuf)); + cmdbuf = umem_alloc(MAXPATHLEN, UMEM_NOFAIL); + (void) strlcpy(cmdbuf, getexecname(), MAXPATHLEN); cmd = cmdbuf; } @@ -5910,9 +6058,15 @@ exec_child(char *cmd, char *libpath, boolean_t ignorekill, int *statusp) if (pid == 0) { /* child */ char *emptyargv[2] = { cmd, NULL }; + char fd_data_str[12]; struct rlimit rl = { 1024, 1024 }; (void) setrlimit(RLIMIT_NOFILE, &rl); + + (void) close(ztest_fd_rand); + VERIFY(11 >= snprintf(fd_data_str, 12, "%d", ztest_fd_data)); + VERIFY(0 == setenv("ZTEST_FD_DATA", fd_data_str, 1)); + (void) enable_extended_FILE_stdio(-1, -1); if (libpath != NULL) VERIFY(0 == setenv("LD_LIBRARY_PATH", libpath, 1)); @@ -5921,6 +6075,11 @@ exec_child(char *cmd, char *libpath, boolean_t ignorekill, int *statusp) fatal(B_TRUE, "exec failed: %s", cmd); } + if (cmdbuf != NULL) { + umem_free(cmdbuf, MAXPATHLEN); + cmd = NULL; + } + while (waitpid(pid, &status, 0) != pid) continue; if (statusp != NULL) @@ -5987,39 +6146,41 @@ main(int argc, char **argv) char timebuf[100]; char numbuf[6]; spa_t *spa; - char cmd[MAXNAMELEN]; + char *cmd; boolean_t hasalt; int f; - boolean_t ischild = (0 == lseek(ZTEST_FD_DATA, 0, SEEK_CUR)); - - ASSERT(ischild || errno == EBADF || errno == ESPIPE); + char *fd_data_str = getenv("ZTEST_FD_DATA"); (void) setvbuf(stdout, NULL, _IOLBF, 0); - if (!ischild) { + ztest_fd_rand = open("/dev/urandom", O_RDONLY); + ASSERT3S(ztest_fd_rand, >=, 0); + + if (!fd_data_str) { dprintf_setup(&argc, argv); process_options(argc, argv); - setup_fds(); + setup_data_fd(); setup_hdr(); setup_data(); bcopy(&ztest_opts, ztest_shared_opts, sizeof (*ztest_shared_opts)); } else { + ztest_fd_data = atoi(fd_data_str); setup_data(); bcopy(ztest_shared_opts, &ztest_opts, sizeof (ztest_opts)); } ASSERT3U(ztest_opts.zo_datasets, ==, ztest_shared_hdr->zh_ds_count); /* Override location of zpool.cache */ - (void) asprintf((char **)&spa_config_path, "%s/zpool.cache", - ztest_opts.zo_dir); - + VERIFY(asprintf((char **)&spa_config_path, "%s/zpool.cache", + ztest_opts.zo_dir) != -1); + ztest_ds = umem_alloc(ztest_opts.zo_datasets * sizeof (ztest_ds_t), UMEM_NOFAIL); zs = ztest_shared; - if (ischild) { + if (fd_data_str) { metaslab_gang_bang = ztest_opts.zo_metaslab_gang_bang; metaslab_df_alloc_threshold = zs->zs_metaslab_df_alloc_threshold; @@ -6042,7 +6203,8 @@ main(int argc, char **argv) (u_longlong_t)ztest_opts.zo_time); } - (void) strlcpy(cmd, getexecname(), sizeof (cmd)); + cmd = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); + (void) strlcpy(cmd, getexecname(), MAXNAMELEN); zs->zs_do_init = B_TRUE; if (strlen(ztest_opts.zo_alt_ztest) != 0) { @@ -6183,5 +6345,7 @@ main(int argc, char **argv) kills, iters - kills, (100.0 * kills) / MAX(1, iters)); } + umem_free(cmd, MAXNAMELEN); + return (0); }