From f44ad9297da6e638482232636e9d63302b96f7e9 Mon Sep 17 00:00:00 2001 From: Tom Caputi Date: Wed, 7 Nov 2018 18:40:24 -0500 Subject: [PATCH] Replay logs before starting ztest workers This patch ensures that logs are replayed on all datasets prior to starting ztest workers. This ensures that the call to vdev_offline() a log device in ztest_fault_inject() will not fail due to the log device being required for replay. This patch also fixes a small issue found during testing where spa_keystore_load_wkey() does not check that the dataset specified is an encryption root. This check was present in libzfs, however. Reviewed-by: Matthew Ahrens Reviewed-by: Brian Behlendorf Signed-off-by: Tom Caputi Closes #8084 --- cmd/ztest/ztest.c | 79 ++++++++++++++++++++++++++++++++++++------ module/zfs/dsl_crypt.c | 11 ++++-- 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index 1ad87bb30c..36647c4ff9 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -1304,19 +1304,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 +1325,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); @@ -6744,6 +6759,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. */ @@ -6845,6 +6893,15 @@ ztest_run(ztest_shared_t *zs) 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. */ diff --git a/module/zfs/dsl_crypt.c b/module/zfs/dsl_crypt.c index d2545c6fa4..da2a126f2e 100644 --- a/module/zfs/dsl_crypt.c +++ b/module/zfs/dsl_crypt.c @@ -758,7 +758,7 @@ spa_keystore_load_wkey(const char *dsname, dsl_crypto_params_t *dcp, dsl_crypto_key_t *dck = NULL; dsl_wrapping_key_t *wkey = dcp->cp_wkey; dsl_pool_t *dp = NULL; - uint64_t keyformat, salt, iters; + uint64_t rddobj, keyformat, salt, iters; /* * We don't validate the wrapping key's keyformat, salt, or iters @@ -775,7 +775,7 @@ spa_keystore_load_wkey(const char *dsname, dsl_crypto_params_t *dcp, goto error; if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ENCRYPTION)) { - ret = (SET_ERROR(ENOTSUP)); + ret = SET_ERROR(ENOTSUP); goto error; } @@ -786,6 +786,13 @@ spa_keystore_load_wkey(const char *dsname, dsl_crypto_params_t *dcp, goto error; } + /* confirm that dd is the encryption root */ + ret = dsl_dir_get_encryption_root_ddobj(dd, &rddobj); + if (ret != 0 || rddobj != dd->dd_object) { + ret = SET_ERROR(EINVAL); + goto error; + } + /* initialize the wkey's ddobj */ wkey->wk_ddobj = dd->dd_object;