X-Git-Url: https://git.proxmox.com/?p=mirror_zfs.git;a=blobdiff_plain;f=cmd%2Fztest%2Fztest.c;h=678e29ff6681e45f9583bf502d07f515f2510066;hp=14e8a5e27af3b2278b85bdde1fbdc8e3151ad00a;hb=6e91a72fe3ff8bb282490773bd687632f3e8c79d;hpb=7d658d29cf4b6b037156dfc29d298a7abb8afc86 diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index 14e8a5e27..678e29ff6 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -106,6 +106,7 @@ #include #include #include +#include #include #include #include @@ -128,7 +129,7 @@ #include #include #include -#include +#include #include #ifdef __GLIBC__ #include /* for backtrace() */ @@ -201,7 +202,7 @@ static const ztest_shared_opts_t ztest_opts_defaults = { .zo_init = 1, .zo_time = 300, /* 5 minutes */ .zo_maxloops = 50, /* max loops during spa_freeze() */ - .zo_metaslab_force_ganging = 32 << 10, + .zo_metaslab_force_ganging = 64 << 10, .zo_special_vdevs = ZTEST_VDEV_CLASS_RND, }; @@ -216,6 +217,7 @@ extern boolean_t zfs_force_some_double_word_sm_entries; extern unsigned long zio_decompress_fail_fraction; extern unsigned long zfs_reconstruct_indirect_damage_fraction; + static ztest_shared_opts_t *ztest_shared_opts; static ztest_shared_opts_t ztest_opts; static char *ztest_wkeydata = "abcdefghijklmnopqrstuvwxyz012345"; @@ -370,8 +372,8 @@ ztest_func_t ztest_split_pool; ztest_func_t ztest_reguid; ztest_func_t ztest_spa_upgrade; ztest_func_t ztest_device_removal; -ztest_func_t ztest_remap_blocks; ztest_func_t ztest_spa_checkpoint_create_discard; +ztest_func_t ztest_initialize; ztest_func_t ztest_fletcher; ztest_func_t ztest_fletcher_incr; ztest_func_t ztest_verify_dnode_bt; @@ -423,8 +425,8 @@ ztest_info_t ztest_info[] = { ZTI_INIT(ztest_vdev_class_add, 1, &ztest_opts.zo_vdevtime), ZTI_INIT(ztest_vdev_aux_add_remove, 1, &ztest_opts.zo_vdevtime), ZTI_INIT(ztest_device_removal, 1, &zopt_sometimes), - ZTI_INIT(ztest_remap_blocks, 1, &zopt_sometimes), ZTI_INIT(ztest_spa_checkpoint_create_discard, 1, &zopt_rarely), + ZTI_INIT(ztest_initialize, 1, &zopt_sometimes), ZTI_INIT(ztest_fletcher, 1, &zopt_rarely), ZTI_INIT(ztest_fletcher_incr, 1, &zopt_rarely), ZTI_INIT(ztest_verify_dnode_bt, 1, &zopt_sometimes), @@ -1304,19 +1306,18 @@ ztest_dmu_objset_own(const char *name, dmu_objset_type_t type, boolean_t readonly, boolean_t decrypt, void *tag, objset_t **osp) { int err; + char *cp = NULL; + char ddname[ZFS_MAX_DATASET_NAME_LEN]; + + strcpy(ddname, name); + cp = strchr(ddname, '@'); + if (cp != NULL) + *cp = '\0'; err = dmu_objset_own(name, type, readonly, decrypt, tag, osp); - if (decrypt && err == EACCES) { - char ddname[ZFS_MAX_DATASET_NAME_LEN]; + while (decrypt && err == EACCES) { dsl_crypto_params_t *dcp; nvlist_t *crypto_args = fnvlist_alloc(); - char *cp = NULL; - - /* spa_keystore_load_wkey() expects a dsl dir name */ - strcpy(ddname, name); - cp = strchr(ddname, '@'); - if (cp != NULL) - *cp = '\0'; fnvlist_add_uint8_array(crypto_args, "wkeydata", (uint8_t *)ztest_wkeydata, WRAPPING_KEY_LEN); @@ -1326,10 +1327,26 @@ ztest_dmu_objset_own(const char *name, dmu_objset_type_t type, dsl_crypto_params_free(dcp, B_FALSE); fnvlist_free(crypto_args); - if (err != 0) - return (err); + if (err == EINVAL) { + /* + * We couldn't load a key for this dataset so try + * the parent. This loop will eventually hit the + * encryption root since ztest only makes clones + * as children of their origin datasets. + */ + cp = strrchr(ddname, '/'); + if (cp == NULL) + return (err); + + *cp = '\0'; + err = EACCES; + continue; + } else if (err != 0) { + break; + } err = dmu_objset_own(name, type, readonly, decrypt, tag, osp); + break; } return (err); @@ -2142,6 +2159,7 @@ zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = { * ZIL get_data callbacks */ +/* ARGSUSED */ static void ztest_get_done(zgd_t *zgd, int error) { @@ -2154,9 +2172,6 @@ ztest_get_done(zgd_t *zgd, int error) ztest_range_unlock((rl_t *)zgd->zgd_lr); ztest_object_unlock(zd, object); - if (error == 0 && zgd->zgd_bp) - zil_lwb_add_block(zgd->zgd_lwb, zgd->zgd_bp); - umem_free(zgd, sizeof (*zgd)); } @@ -2658,6 +2673,13 @@ ztest_zil_remount(ztest_ds_t *zd, uint64_t id) { objset_t *os = zd->zd_os; + /* + * We hold the ztest_vdev_lock so we don't cause problems with + * other threads that wish to remove a log device, such as + * ztest_device_removal(). + */ + mutex_enter(&ztest_vdev_lock); + /* * We grab the zd_dirobj_lock to ensure that no other thread is * updating the zil (i.e. adding in-memory log records) and the @@ -2675,6 +2697,7 @@ ztest_zil_remount(ztest_ds_t *zd, uint64_t id) (void) pthread_rwlock_unlock(&zd->zd_zilog_lock); mutex_exit(&zd->zd_dirobj_lock); + mutex_exit(&ztest_vdev_lock); } /* @@ -2793,7 +2816,7 @@ ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id) /* * If we're configuring a RAIDZ device then make sure that the - * the initial version is capable of supporting that feature. + * initial version is capable of supporting that feature. */ switch (ztest_opts.zo_raidz_parity) { case 0: @@ -3225,7 +3248,7 @@ ztest_split_pool(ztest_ds_t *zd, uint64_t id) mutex_enter(&ztest_vdev_lock); - /* ensure we have a useable config; mirrors of raidz aren't supported */ + /* ensure we have a usable config; mirrors of raidz aren't supported */ if (zs->zs_mirrors < 3 || ztest_opts.zo_raidz > 1) { mutex_exit(&ztest_vdev_lock); return; @@ -3558,7 +3581,7 @@ ztest_device_removal(ztest_ds_t *zd, uint64_t id) */ txg_wait_synced(spa_get_dsl(spa), 0); - while (spa->spa_vdev_removal != NULL) + while (spa->spa_removing_phys.sr_state == DSS_SCANNING) txg_wait_synced(spa_get_dsl(spa), 0); } else { mutex_exit(&ztest_vdev_lock); @@ -3959,9 +3982,13 @@ ztest_objset_destroy_cb(const char *name, void *arg) VERIFY0(dsl_destroy_snapshot(name, B_TRUE)); } else { error = dsl_destroy_head(name); - /* There could be a hold on this dataset */ - if (error != EBUSY) + if (error == ENOSPC) { + /* There could be checkpoint or insufficient slop */ + ztest_record_enospc(FTAG); + } else if (error != EBUSY) { + /* There could be a hold on this dataset */ ASSERT0(error); + } } return (0); } @@ -4994,7 +5021,7 @@ ztest_zap(ztest_ds_t *zd, uint64_t id) dmu_tx_commit(tx); /* - * Generate a buch of random entries. + * Generate a bunch of random entries. */ ints = MAX(ZTEST_ZAP_MIN_INTS, object % ZTEST_ZAP_MAX_INTS); @@ -5084,7 +5111,7 @@ out: } /* - * Testcase to test the upgrading of a microzap to fatzap. + * Test case to test the upgrading of a microzap to fatzap. */ void ztest_fzap(ztest_ds_t *zd, uint64_t id) @@ -5520,20 +5547,6 @@ ztest_dsl_prop_get_set(ztest_ds_t *zd, uint64_t id) (void) pthread_rwlock_unlock(&ztest_name_lock); } -/* ARGSUSED */ -void -ztest_remap_blocks(ztest_ds_t *zd, uint64_t id) -{ - (void) pthread_rwlock_rdlock(&ztest_name_lock); - - int error = dmu_objset_remap_indirects(zd->zd_name); - if (error == ENOSPC) - error = 0; - ASSERT0(error); - - (void) pthread_rwlock_unlock(&ztest_name_lock); -} - /* ARGSUSED */ void ztest_spa_prop_get_set(ztest_ds_t *zd, uint64_t id) @@ -6316,6 +6329,104 @@ ztest_get_zdb_bin(char *bin, int len) strcpy(bin, "zdb"); } +static vdev_t * +ztest_random_concrete_vdev_leaf(vdev_t *vd) +{ + if (vd == NULL) + return (NULL); + + if (vd->vdev_children == 0) + return (vd); + + vdev_t *eligible[vd->vdev_children]; + int eligible_idx = 0, i; + for (i = 0; i < vd->vdev_children; i++) { + vdev_t *cvd = vd->vdev_child[i]; + if (cvd->vdev_top->vdev_removing) + continue; + if (cvd->vdev_children > 0 || + (vdev_is_concrete(cvd) && !cvd->vdev_detached)) { + eligible[eligible_idx++] = cvd; + } + } + VERIFY(eligible_idx > 0); + + uint64_t child_no = ztest_random(eligible_idx); + return (ztest_random_concrete_vdev_leaf(eligible[child_no])); +} + +/* ARGSUSED */ +void +ztest_initialize(ztest_ds_t *zd, uint64_t id) +{ + spa_t *spa = ztest_spa; + int error = 0; + + mutex_enter(&ztest_vdev_lock); + + spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER); + + /* Random leaf vdev */ + vdev_t *rand_vd = ztest_random_concrete_vdev_leaf(spa->spa_root_vdev); + if (rand_vd == NULL) { + spa_config_exit(spa, SCL_VDEV, FTAG); + mutex_exit(&ztest_vdev_lock); + return; + } + + /* + * The random vdev we've selected may change as soon as we + * drop the spa_config_lock. We create local copies of things + * we're interested in. + */ + uint64_t guid = rand_vd->vdev_guid; + char *path = strdup(rand_vd->vdev_path); + boolean_t active = rand_vd->vdev_initialize_thread != NULL; + + zfs_dbgmsg("vd %p, guid %llu", rand_vd, guid); + spa_config_exit(spa, SCL_VDEV, FTAG); + + uint64_t cmd = ztest_random(POOL_INITIALIZE_FUNCS); + + nvlist_t *vdev_guids = fnvlist_alloc(); + nvlist_t *vdev_errlist = fnvlist_alloc(); + fnvlist_add_uint64(vdev_guids, path, guid); + error = spa_vdev_initialize(spa, vdev_guids, cmd, vdev_errlist); + fnvlist_free(vdev_guids); + fnvlist_free(vdev_errlist); + + switch (cmd) { + case POOL_INITIALIZE_CANCEL: + if (ztest_opts.zo_verbose >= 4) { + (void) printf("Cancel initialize %s", path); + if (!active) + (void) printf(" failed (no initialize active)"); + (void) printf("\n"); + } + break; + case POOL_INITIALIZE_DO: + if (ztest_opts.zo_verbose >= 4) { + (void) printf("Start initialize %s", path); + if (active && error == 0) + (void) printf(" failed (already active)"); + else if (error != 0) + (void) printf(" failed (error %d)", error); + (void) printf("\n"); + } + break; + case POOL_INITIALIZE_SUSPEND: + if (ztest_opts.zo_verbose >= 4) { + (void) printf("Suspend initialize %s", path); + if (!active) + (void) printf(" failed (no initialize active)"); + (void) printf("\n"); + } + break; + } + free(path); + mutex_exit(&ztest_vdev_lock); +} + /* * Verify pool integrity by running zdb. */ @@ -6744,6 +6855,39 @@ ztest_dataset_close(int d) ztest_zd_fini(zd); } +/* ARGSUSED */ +static int +ztest_replay_zil_cb(const char *name, void *arg) +{ + objset_t *os; + ztest_ds_t *zdtmp; + + VERIFY0(ztest_dmu_objset_own(name, DMU_OST_ANY, B_TRUE, + B_TRUE, FTAG, &os)); + + zdtmp = umem_alloc(sizeof (ztest_ds_t), UMEM_NOFAIL); + + ztest_zd_init(zdtmp, NULL, os); + zil_replay(os, zdtmp, ztest_replay_vector); + ztest_zd_fini(zdtmp); + + if (dmu_objset_zil(os)->zl_parse_lr_count != 0 && + ztest_opts.zo_verbose >= 6) { + zilog_t *zilog = dmu_objset_zil(os); + + (void) printf("%s replay %llu blocks, %llu records, seq %llu\n", + name, + (u_longlong_t)zilog->zl_parse_blk_count, + (u_longlong_t)zilog->zl_parse_lr_count, + (u_longlong_t)zilog->zl_replaying_seq); + } + + umem_free(zdtmp, sizeof (ztest_ds_t)); + + dmu_objset_disown(os, B_TRUE, FTAG); + return (0); +} + /* * Kick off threads to run tests on all datasets in parallel. */ @@ -6839,12 +6983,41 @@ ztest_run(ztest_shared_t *zs) } zs->zs_enospc_count = 0; + /* + * If we were in the middle of ztest_device_removal() and were killed + * we need to ensure the removal and scrub complete before running + * any tests that check ztest_device_removal_active. The removal will + * be restarted automatically when the spa is opened, but we need to + * initiate the scrub manually if it is not already in progress. Note + * that we always run the scrub whenever an indirect vdev exists + * because we have no way of knowing for sure if ztest_device_removal() + * fully completed its scrub before the pool was reimported. + */ + if (spa->spa_removing_phys.sr_state == DSS_SCANNING || + spa->spa_removing_phys.sr_prev_indirect_vdev != -1) { + while (spa->spa_removing_phys.sr_state == DSS_SCANNING) + txg_wait_synced(spa_get_dsl(spa), 0); + + (void) spa_scan(spa, POOL_SCAN_SCRUB); + while (dsl_scan_scrubbing(spa_get_dsl(spa))) + txg_wait_synced(spa_get_dsl(spa), 0); + } + run_threads = umem_zalloc(ztest_opts.zo_threads * sizeof (kthread_t *), UMEM_NOFAIL); if (ztest_opts.zo_verbose >= 4) (void) printf("starting main threads...\n"); + /* + * Replay all logs of all datasets in the pool. This is primarily for + * temporary datasets which wouldn't otherwise get replayed, which + * can trigger failures when attempting to offline a SLOG in + * ztest_fault_inject(). + */ + (void) dmu_objset_find(ztest_opts.zo_pool, ztest_replay_zil_cb, + NULL, DS_FIND_CHILDREN); + /* * Kick off all the tests that run in parallel. */ @@ -6861,11 +7034,17 @@ ztest_run(ztest_shared_t *zs) } /* - * Wait for all of the tests to complete. We go in reverse order - * so we don't close datasets while threads are still using them. + * Wait for all of the tests to complete. */ - for (t = ztest_opts.zo_threads - 1; t >= 0; t--) { + for (t = 0; t < ztest_opts.zo_threads; t++) VERIFY0(thread_join(run_threads[t])); + + /* + * Close all datasets. This must be done after all the threads + * are joined so we can be sure none of the datasets are in-use + * by any of the threads. + */ + for (t = 0; t < ztest_opts.zo_threads; t++) { if (t < ztest_opts.zo_datasets) ztest_dataset_close(t); } @@ -7065,7 +7244,6 @@ make_random_props(void) static void ztest_import(ztest_shared_t *zs) { - libzfs_handle_t *hdl; importargs_t args = { 0 }; spa_t *spa; nvlist_t *cfg = NULL; @@ -7080,14 +7258,14 @@ ztest_import(ztest_shared_t *zs) VERIFY0(pthread_rwlock_init(&ztest_name_lock, NULL)); kernel_init(FREAD | FWRITE); - hdl = libzfs_init(); searchdirs[0] = ztest_opts.zo_dir; args.paths = nsearch; args.path = searchdirs; args.can_be_active = B_FALSE; - error = zpool_tryimport(hdl, name, &cfg, &args); + error = zpool_find_config(NULL, name, &cfg, &args, + &libzpool_config_ops); if (error) (void) fatal(0, "No pools found\n"); @@ -7097,7 +7275,6 @@ ztest_import(ztest_shared_t *zs) 1ULL << spa->spa_root_vdev->vdev_child[0]->vdev_ms_shift; spa_close(spa, FTAG); - libzfs_fini(hdl); kernel_fini(); if (!ztest_opts.zo_mmp_test) {