X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=cmd%2Fztest%2Fztest.c;h=e080f7bb44191754808098cd67c13b2c89a97c16;hb=ce5fb2a7c6dfaa0f305350225e064e9f536bd5a4;hp=f7f584358cd8e731bb376d29700b78c06470076d;hpb=d611989fdc176ccb54c24df99fd6c81b1cfff833;p=mirror_zfs.git diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index f7f584358..e080f7bb4 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -216,7 +216,6 @@ extern int dmu_object_alloc_chunk_shift; 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; -extern int zfs_object_remap_one_indirect_delay_ms; static ztest_shared_opts_t *ztest_shared_opts; @@ -373,7 +372,6 @@ 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; @@ -427,7 +425,6 @@ 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), @@ -479,6 +476,7 @@ static ztest_ds_t *ztest_ds; static kmutex_t ztest_vdev_lock; static boolean_t ztest_device_removal_active = B_FALSE; +static boolean_t ztest_pool_scrubbed = B_FALSE; static kmutex_t ztest_checkpoint_lock; /* @@ -518,6 +516,7 @@ enum ztest_object { }; static void usage(boolean_t) __NORETURN; +static int ztest_scrub_impl(spa_t *spa); /* * These libumem hooks provide a reasonable set of defaults for the allocator's @@ -3430,10 +3429,17 @@ ztest_vdev_attach_detach(ztest_ds_t *zd, uint64_t id) pguid = pvd->vdev_guid; /* - * If oldvd has siblings, then half of the time, detach it. + * If oldvd has siblings, then half of the time, detach it. Prior + * to the detach the pool is scrubbed in order to prevent creating + * unrepairable blocks as a result of the data corruption injection. */ if (oldvd_has_siblings && ztest_random(2) == 0) { spa_config_exit(spa, SCL_ALL, FTAG); + + error = ztest_scrub_impl(spa); + if (error) + goto out; + error = spa_vdev_detach(spa, oldguid, pguid, B_FALSE); if (error != 0 && error != ENODEV && error != EBUSY && error != ENOTSUP && error != ZFS_ERR_CHECKPOINT_EXISTS && @@ -4850,14 +4856,14 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id) FTAG, &dbt, DMU_READ_NO_PREFETCH) == 0); } if (i != 5 || chunksize < (SPA_MINBLOCKSIZE * 2)) { - dmu_assign_arcbuf_by_dbuf(bonus_db, off, - bigbuf_arcbufs[j], tx); + VERIFY0(dmu_assign_arcbuf_by_dbuf(bonus_db, + off, bigbuf_arcbufs[j], tx)); } else { - dmu_assign_arcbuf_by_dbuf(bonus_db, off, - bigbuf_arcbufs[2 * j], tx); - dmu_assign_arcbuf_by_dbuf(bonus_db, + VERIFY0(dmu_assign_arcbuf_by_dbuf(bonus_db, + off, bigbuf_arcbufs[2 * j], tx)); + VERIFY0(dmu_assign_arcbuf_by_dbuf(bonus_db, off + chunksize / 2, - bigbuf_arcbufs[2 * j + 1], tx); + bigbuf_arcbufs[2 * j + 1], tx)); } if (i == 1) { dmu_buf_rele(dbt, FTAG); @@ -5550,20 +5556,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) @@ -5774,6 +5766,19 @@ ztest_fault_inject(ztest_ds_t *zd, uint64_t id) ASSERT(leaves >= 1); + /* + * While ztest is running the number of leaves will not change. This + * is critical for the fault injection logic as it determines where + * errors can be safely injected such that they are always repairable. + * + * When restarting ztest a different number of leaves may be requested + * which will shift the regions to be damaged. This is fine as long + * as the pool has been scrubbed prior to using the new mapping. + * Failure to do can result in non-repairable damage being injected. + */ + if (ztest_pool_scrubbed == B_FALSE) + goto out; + /* * Grab the name lock as reader. There are some operations * which don't like to have their vdevs changed while @@ -6010,20 +6015,13 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) spa_t *spa = ztest_spa; objset_t *os = zd->zd_os; ztest_od_t *od; - uint64_t object, blocksize, txg, pattern, psize; + uint64_t object, blocksize, txg, pattern; enum zio_checksum checksum = spa_dedup_checksum(spa); dmu_buf_t *db; dmu_tx_t *tx; - abd_t *abd; - blkptr_t blk; - int copies = 2 * ZIO_DEDUPDITTO_MIN; - int i; - - blocksize = ztest_random_blocksize(); - blocksize = MIN(blocksize, 2048); /* because we write so many */ od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL); - ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0, 0); + ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0); if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) { umem_free(od, sizeof (ztest_od_t)); @@ -6032,7 +6030,7 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) /* * Take the name lock as writer to prevent anyone else from changing - * the pool and dataset properies we need to maintain during this test. + * the pool and dataset properties we need to maintain during this test. */ (void) pthread_rwlock_wrlock(&ztest_name_lock); @@ -6054,6 +6052,31 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) blocksize = od[0].od_blocksize; pattern = zs->zs_guid ^ dds.dds_guid; + /* + * The numbers of copies written must always be greater than or + * equal to the threshold set by the dedupditto property. This + * is initialized in ztest_run() and then randomly changed by + * ztest_spa_prop_get_set(), these function will never set it + * larger than 2 * ZIO_DEDUPDITTO_MIN. + */ + int copies = 2 * ZIO_DEDUPDITTO_MIN; + + /* + * The block size is limited by DMU_MAX_ACCESS (64MB) which + * caps the maximum transaction size. A block size of up to + * SPA_OLD_MAXBLOCKSIZE is allowed which results in a maximum + * transaction size of: 128K * 200 (copies) = ~25MB + * + * The actual block size is checked here, rather than requested + * above, because the way ztest_od_init() is implemented it does + * not guarantee the block size requested will be used. + */ + if (blocksize > SPA_OLD_MAXBLOCKSIZE) { + (void) pthread_rwlock_unlock(&ztest_name_lock); + umem_free(od, sizeof (ztest_od_t)); + return; + } + ASSERT(object != 0); tx = dmu_tx_create(os); @@ -6068,7 +6091,7 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) /* * Write all the copies of our block. */ - for (i = 0; i < copies; i++) { + for (int i = 0; i < copies; i++) { uint64_t offset = i * blocksize; int error = dmu_buf_hold(os, object, offset, FTAG, &db, DMU_READ_NO_PREFETCH); @@ -6091,16 +6114,15 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) /* * Find out what block we got. */ - VERIFY0(dmu_buf_hold(os, object, 0, FTAG, &db, - DMU_READ_NO_PREFETCH)); - blk = *((dmu_buf_impl_t *)db)->db_blkptr; + VERIFY0(dmu_buf_hold(os, object, 0, FTAG, &db, DMU_READ_NO_PREFETCH)); + blkptr_t blk = *((dmu_buf_impl_t *)db)->db_blkptr; dmu_buf_rele(db, FTAG); /* * Damage the block. Dedup-ditto will save us when we read it later. */ - psize = BP_GET_PSIZE(&blk); - abd = abd_alloc_linear(psize, B_TRUE); + uint64_t psize = BP_GET_PSIZE(&blk); + abd_t *abd = abd_alloc_linear(psize, B_TRUE); ztest_pattern_set(abd_to_buf(abd), psize, ~pattern); (void) zio_wait(zio_rewrite(NULL, spa, 0, &blk, @@ -6113,6 +6135,32 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id) umem_free(od, sizeof (ztest_od_t)); } +/* + * By design ztest will never inject uncorrectable damage in to the pool. + * Issue a scrub, wait for it to complete, and verify there is never any + * any persistent damage. + * + * Only after a full scrub has been completed is it safe to start injecting + * data corruption. See the comment in zfs_fault_inject(). + */ +static int +ztest_scrub_impl(spa_t *spa) +{ + int error = spa_scan(spa, POOL_SCAN_SCRUB); + if (error) + return (error); + + while (dsl_scan_scrubbing(spa_get_dsl(spa))) + txg_wait_synced(spa_get_dsl(spa), 0); + + if (spa_get_errlog_size(spa) > 0) + return (ECKSUM); + + ztest_pool_scrubbed = B_TRUE; + + return (0); +} + /* * Scrub the pool. */ @@ -6121,6 +6169,7 @@ void ztest_scrub(ztest_ds_t *zd, uint64_t id) { spa_t *spa = ztest_spa; + int error; /* * Scrub in progress by device removal. @@ -6128,9 +6177,16 @@ ztest_scrub(ztest_ds_t *zd, uint64_t id) if (ztest_device_removal_active) return; + /* + * Start a scrub, wait a moment, then force a restart. + */ (void) spa_scan(spa, POOL_SCAN_SCRUB); - (void) poll(NULL, 0, 100); /* wait a moment, then force a restart */ - (void) spa_scan(spa, POOL_SCAN_SCRUB); + (void) poll(NULL, 0, 100); + + error = ztest_scrub_impl(spa); + if (error == EBUSY) + error = 0; + ASSERT0(error); } /* @@ -6464,8 +6520,7 @@ ztest_run_zdb(char *pool) ztest_get_zdb_bin(bin, len); (void) sprintf(zdb, - "%s -bcc%s%s -G -d -U %s " - "-o zfs_reconstruct_indirect_combinations_max=65536 %s", + "%s -bcc%s%s -G -d -Y -U %s %s", bin, ztest_opts.zo_verbose >= 3 ? "s" : "", ztest_opts.zo_verbose >= 4 ? "v" : "", @@ -6629,12 +6684,6 @@ ztest_resume_thread(void *arg) */ if (ztest_random(10) == 0) zfs_abd_scatter_enabled = ztest_random(2); - - /* - * Periodically inject remapping delays (10% of the time). - */ - zfs_object_remap_one_indirect_delay_ms = - ztest_random(10) == 0 ? ztest_random(1000) + 1 : 0; } thread_exit(); @@ -7021,9 +7070,10 @@ ztest_run(ztest_shared_t *zs) 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); + error = ztest_scrub_impl(spa); + if (error == EBUSY) + error = 0; + ASSERT0(error); } run_threads = umem_zalloc(ztest_opts.zo_threads * sizeof (kthread_t *),