From 4d137189c00df630c901bda878d588b91df0dc11 Mon Sep 17 00:00:00 2001 From: Tom Caputi Date: Wed, 8 Nov 2017 14:12:59 -0500 Subject: [PATCH 1/5] Encryption Stability and On-Disk Format Fixes The on-disk format for encrypted datasets protects not only the encrypted and authenticated blocks themselves, but also the order and interpretation of these blocks. In order to make this work while maintaining the ability to do raw sends, the indirect bps maintain a secure checksum of all the MACs in the block below it along with a few other fields that determine how the data is interpreted. Unfortunately, the current on-disk format erroneously includes some fields which are not portable and thus cannot support raw sends. It is not possible to easily work around this issue due to a separate and much smaller bug which causes indirect blocks for encrypted dnodes to not be compressed, which conflicts with the previous bug. In addition, the current code generates incompatible on-disk formats on big endian and little endian systems due to an issue with how block pointers are authenticated. Finally, raw send streams do not currently include dn_maxblkid when sending both the metadnode and normal dnodes which are needed in order to ensure that we are correctly maintaining the portable objset MAC. This patch zero's out the offending fields when computing the bp MAC and ensures that these MACs are always calculated in little endian order (regardless of the host system's byte order). This patch also registers an errata for the old on-disk format, which we detect by adding a "version" field to newly created DSL Crypto Keys. We allow datasets without a version (version 0) to only be mounted for read so that they can easily be migrated. We also now include dn_maxblkid in raw send streams to ensure the MAC can be maintained correctly. This patch also contains minor bug fixes and cleanups. Fixes #6845 Fixes #7052 Signed-off-by: Tom Caputi --- cmd/zfs/zfs_main.c | 4 +- cmd/zpool/zpool_main.c | 20 + cmd/zstreamdump/zstreamdump.c | 6 +- contrib/dracut/90zfs/zfs-load-key.sh | 52 +++ include/sys/dmu.h | 7 + include/sys/dmu_objset.h | 1 + include/sys/dnode.h | 8 + include/sys/dsl_crypt.h | 3 +- include/sys/fs/zfs.h | 1 + include/sys/zfs_ioctl.h | 4 +- include/sys/zio_crypt.h | 11 +- lib/libzfs/libzfs_crypto.c | 19 +- lib/libzfs/libzfs_status.c | 18 +- module/zfs/arc.c | 15 +- module/zfs/dmu.c | 22 +- module/zfs/dmu_objset.c | 10 + module/zfs/dmu_send.c | 32 +- module/zfs/dnode.c | 6 + module/zfs/dnode_sync.c | 12 + module/zfs/dsl_crypt.c | 91 ++++- module/zfs/dsl_dir.c | 7 + module/zfs/zfs_vfsops.c | 12 +- module/zfs/zio.c | 50 ++- module/zfs/zio_crypt.c | 343 ++++++++++++------ module/zfs/zvol.c | 7 +- tests/runfiles/linux.run | 6 +- .../cli_root/zpool_import/Makefile.am | 6 +- .../cli_root/zpool_import/cryptv0.dat.bz2 | Bin 0 -> 94716 bytes .../zpool_import/zpool_import_errata3.ksh | 99 +++++ .../tests/functional/rsend/Makefile.am | 1 + .../functional/rsend/send_encrypted_files.ksh | 101 ++++++ 31 files changed, 787 insertions(+), 187 deletions(-) create mode 100644 contrib/dracut/90zfs/zfs-load-key.sh create mode 100644 tests/zfs-tests/tests/functional/cli_root/zpool_import/cryptv0.dat.bz2 create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata3.ksh create mode 100644 tests/zfs-tests/tests/functional/rsend/send_encrypted_files.ksh diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 924a4d4aa6f9..64cccc3d3c5a 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -342,8 +342,8 @@ get_usage(zfs_help_t idx) return (gettext("\tunload-key [-r] " "<-a | filesystem|volume>\n")); case HELP_CHANGE_KEY: - return (gettext("\tchange-key [-l] [-o keyformat=]" - "\t [-o keylocation=] [-o pbkfd2iters=]" + return (gettext("\tchange-key [-l] [-o keyformat=]\n" + "\t [-o keylocation=] [-o pbkfd2iters=]\n" "\t \n" "\tchange-key -i [-l] \n")); } diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 4905927fca3f..4d9e6bbb5515 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -2121,6 +2121,15 @@ show_import(nvlist_t *config) "updating.\n")); break; + case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION: + (void) printf(gettext(" action: Existing " + "encrypted datasets contain an on-disk " + "incompatibility, which\n\tneeds to be " + "corrected. Backup these datasets to new " + "encrypted datasets\n\tand destroy the " + "old ones.\n")); + break; + default: /* * All errata must contain an action message. @@ -6499,6 +6508,17 @@ status_callback(zpool_handle_t *zhp, void *data) "run 'zpool scrub'.\n")); break; + case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION: + (void) printf(gettext("\tExisting encrypted datasets " + "contain an on-disk incompatibility\n\twhich " + "needs to be corrected.\n")); + (void) printf(gettext("action: To correct the issue " + "backup existing encrypted datasets to new\n\t" + "encrypted datasets and destroy the old ones. " + "'zfs mount -o ro' can\n\tbe used to temporarily " + "mount existing encrypted datasets readonly.\n")); + break; + default: /* * All errata which allow the pool to be imported diff --git a/cmd/zstreamdump/zstreamdump.c b/cmd/zstreamdump/zstreamdump.c index f7bba4c8cf16..4c33e0a5a92d 100644 --- a/cmd/zstreamdump/zstreamdump.c +++ b/cmd/zstreamdump/zstreamdump.c @@ -443,6 +443,8 @@ main(int argc, char *argv[]) drro->drr_raw_bonuslen = BSWAP_32(drro->drr_raw_bonuslen); drro->drr_toguid = BSWAP_64(drro->drr_toguid); + drro->drr_maxblkid = + BSWAP_64(drro->drr_maxblkid); } payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro); @@ -451,7 +453,8 @@ main(int argc, char *argv[]) (void) printf("OBJECT object = %llu type = %u " "bonustype = %u blksz = %u bonuslen = %u " "dn_slots = %u raw_bonuslen = %u " - "flags = %u indblkshift = %u nlevels = %u " + "flags = %u maxblkid = %llu " + "indblkshift = %u nlevels = %u " "nblkptr = %u\n", (u_longlong_t)drro->drr_object, drro->drr_type, @@ -461,6 +464,7 @@ main(int argc, char *argv[]) drro->drr_dn_slots, drro->drr_raw_bonuslen, drro->drr_flags, + (u_longlong_t)drro->drr_maxblkid, drro->drr_indblkshift, drro->drr_nlevels, drro->drr_nblkptr); diff --git a/contrib/dracut/90zfs/zfs-load-key.sh b/contrib/dracut/90zfs/zfs-load-key.sh new file mode 100644 index 000000000000..d86763fcc91e --- /dev/null +++ b/contrib/dracut/90zfs/zfs-load-key.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# This script only gets executed on systemd systems, see mount-zfs.sh for non-systemd systems + +# import the libs now that we know the pool imported +[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh +[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh +. "$dracutlib" + +# load the kernel command line vars +[ -z "$root" ] && root=$(getarg root=) +# If root is not ZFS= or zfs: or rootfstype is not zfs then we are not supposed to handle it. +[ "${root##zfs:}" = "${root}" -a "${root##ZFS=}" = "${root}" -a "$rootfstype" != "zfs" ] && exit 0 + +# There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported +while true; do + zpool list -H | grep -q -v '^$' && break + [[ $(systemctl is-failed zfs-import-cache.service) == 'failed' ]] && exit 1 + [[ $(systemctl is-failed zfs-import-scan.service) == 'failed' ]] && exit 1 + sleep 0.1s +done + +# run this after import as zfs-import-cache/scan service is confirmed good +if [[ "${root}" = "zfs:AUTO" ]] ; then + root=$(zpool list -H -o bootfs | awk '$1 != "-" {print; exit}') +else + root="${root##zfs:}" + root="${root##ZFS=}" +fi + +# if pool encryption is active and the zfs command understands '-o encryption' +if [[ $(zpool list -H -o feature@encryption $(echo "${root}" | awk -F\/ '{print $1}')) == 'active' ]]; then + # check if root dataset has encryption enabled + if $(zfs list -H -o encryption "${root}" | grep -q -v off); then + # figure out where the root dataset has its key, the keylocation should not be none + while true; do + if [[ $(zfs list -H -o keylocation "${root}") == 'none' ]]; then + root=$(echo -n "${root}" | awk 'BEGIN{FS=OFS="/"}{NF--; print}') + [[ "${root}" == '' ]] && exit 1 + else + break + fi + done + # decrypt them + TRY_COUNT=5 + while [ $TRY_COUNT != 0 ]; do + zfs load-key "$root" <<< $(systemd-ask-password "Encrypted ZFS password for ${root}: ") + [[ $? == 0 ]] && break + ((TRY_COUNT-=1)) + done + fi +fi diff --git a/include/sys/dmu.h b/include/sys/dmu.h index 61c02e8a7683..1da43d3276be 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -434,6 +434,13 @@ int dmu_object_set_nlevels(objset_t *os, uint64_t object, int nlevels, int dmu_object_set_blocksize(objset_t *os, uint64_t object, uint64_t size, int ibs, dmu_tx_t *tx); +/* + * Manually set the maxblkid on a dnode. This will adjust nlevels accordingly + * to accommodate the change. + */ +int dmu_object_set_maxblkid(objset_t *os, uint64_t object, uint64_t maxblkid, + dmu_tx_t *tx); + /* * Set the checksum property on a dnode. The new checksum algorithm will * apply to all newly written blocks; existing blocks will not be affected. diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h index 11b8fc625795..f3013ad13d2d 100644 --- a/include/sys/dmu_objset.h +++ b/include/sys/dmu_objset.h @@ -217,6 +217,7 @@ boolean_t dmu_objset_userobjused_enabled(objset_t *os); boolean_t dmu_objset_userobjspace_upgradable(objset_t *os); void dmu_objset_userobjspace_upgrade(objset_t *os); boolean_t dmu_objset_userobjspace_present(objset_t *os); +boolean_t dmu_objset_incompatible_encryption_version(objset_t *os); int dmu_fsname(const char *snapname, char *buf); diff --git a/include/sys/dnode.h b/include/sys/dnode.h index e5e39b18c9e9..a2bef9d2c77b 100644 --- a/include/sys/dnode.h +++ b/include/sys/dnode.h @@ -221,6 +221,13 @@ typedef struct dnode_phys { uint64_t dn_maxblkid; /* largest allocated block ID */ uint64_t dn_used; /* bytes (or sectors) of disk space */ + /* + * Both dn_pad2 and dn_pad3 are protected by the block's MAC. This + * allows us to protect any fields that might be added here in the + * future. In either case, developers will want to check + * zio_crypt_init_uios_dnode() to ensure the new field is being + * protected properly. + */ uint64_t dn_pad3[4]; /* @@ -301,6 +308,7 @@ struct dnode { uint8_t dn_rm_spillblk[TXG_SIZE]; /* for removing spill blk */ uint16_t dn_next_bonuslen[TXG_SIZE]; uint32_t dn_next_blksz[TXG_SIZE]; /* next block size in bytes */ + uint64_t dn_next_maxblkid[TXG_SIZE]; /* next maxblkid in bytes */ /* protected by dn_dbufs_mtx; declared here to fill 32-bit hole */ uint32_t dn_dbufs_count; /* count of dn_dbufs */ diff --git a/include/sys/dsl_crypt.h b/include/sys/dsl_crypt.h index 6fb91f67d1ab..d0c789035f3d 100644 --- a/include/sys/dsl_crypt.h +++ b/include/sys/dsl_crypt.h @@ -39,7 +39,7 @@ #define DSL_CRYPTO_KEY_HMAC_KEY "DSL_CRYPTO_HMAC_KEY_1" #define DSL_CRYPTO_KEY_ROOT_DDOBJ "DSL_CRYPTO_ROOT_DDOBJ" #define DSL_CRYPTO_KEY_REFCOUNT "DSL_CRYPTO_REFCOUNT" - +#define DSL_CRYPTO_KEY_VERSION "DSL_CRYPTO_VERSION" /* * In-memory representation of a wrapping key. One of these structs will exist @@ -169,6 +169,7 @@ int dsl_crypto_params_create_nvlist(dcp_cmd_t cmd, nvlist_t *props, void dsl_crypto_params_free(dsl_crypto_params_t *dcp, boolean_t unload); void dsl_dataset_crypt_stats(struct dsl_dataset *ds, nvlist_t *nv); int dsl_crypto_can_set_keylocation(const char *dsname, const char *keylocation); +boolean_t dsl_dir_incompatible_encryption_version(dsl_dir_t *dd); void spa_keystore_init(spa_keystore_t *sk); void spa_keystore_fini(spa_keystore_t *sk); diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 6b1c3bb565b9..611279d6b822 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -891,6 +891,7 @@ typedef enum zpool_errata { ZPOOL_ERRATA_NONE, ZPOOL_ERRATA_ZOL_2094_SCRUB, ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY, + ZPOOL_ERRATA_ZOL_6845_ENCRYPTION, } zpool_errata_t; /* diff --git a/include/sys/zfs_ioctl.h b/include/sys/zfs_ioctl.h index 6924280c4a47..827f619d9670 100644 --- a/include/sys/zfs_ioctl.h +++ b/include/sys/zfs_ioctl.h @@ -219,10 +219,12 @@ typedef struct dmu_replay_record { uint8_t drr_flags; uint32_t drr_raw_bonuslen; uint64_t drr_toguid; - /* only nonzero for raw streams */ + /* only (possibly) nonzero for raw streams */ uint8_t drr_indblkshift; uint8_t drr_nlevels; uint8_t drr_nblkptr; + uint8_t drr_pad[5]; + uint64_t drr_maxblkid; /* bonus content follows */ } drr_object; struct drr_freeobjects { diff --git a/include/sys/zio_crypt.h b/include/sys/zio_crypt.h index 9cf9a17c2c13..57b4c1e7c322 100644 --- a/include/sys/zio_crypt.h +++ b/include/sys/zio_crypt.h @@ -36,6 +36,8 @@ struct zbookmark_phys; #define MASTER_KEY_MAX_LEN 32 #define SHA512_HMAC_KEYLEN 64 +#define ZIO_CRYPT_KEY_CURRENT_VERSION 1ULL + typedef enum zio_crypt_type { ZC_TYPE_NONE = 0, ZC_TYPE_CCM, @@ -64,6 +66,9 @@ typedef struct zio_crypt_key { /* encryption algorithm */ uint64_t zk_crypt; + /* on-disk format version */ + uint64_t zk_version; + /* GUID for uniquely identifying this key. Not encrypted on disk. */ uint64_t zk_guid; @@ -104,9 +109,9 @@ int zio_crypt_key_get_salt(zio_crypt_key_t *key, uint8_t *salt_out); int zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv, uint8_t *mac, uint8_t *keydata_out, uint8_t *hmac_keydata_out); -int zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t guid, - uint8_t *keydata, uint8_t *hmac_keydata, uint8_t *iv, uint8_t *mac, - zio_crypt_key_t *key); +int zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version, + uint64_t guid, uint8_t *keydata, uint8_t *hmac_keydata, uint8_t *iv, + uint8_t *mac, zio_crypt_key_t *key); int zio_crypt_generate_iv(uint8_t *ivbuf); int zio_crypt_generate_iv_salt_dedup(zio_crypt_key_t *key, uint8_t *data, uint_t datalen, uint8_t *ivbuf, uint8_t *salt); diff --git a/lib/libzfs/libzfs_crypto.c b/lib/libzfs/libzfs_crypto.c index b1fac2f62138..6ccee740f6e8 100644 --- a/lib/libzfs/libzfs_crypto.c +++ b/lib/libzfs/libzfs_crypto.c @@ -1054,7 +1054,7 @@ zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop, char *alt_keylocation) } try_again: - /* fetching and deriving the key are correctible errors. set the flag */ + /* fetching and deriving the key are correctable errors. set the flag */ correctible = B_TRUE; /* get key material from key format and location */ @@ -1110,22 +1110,25 @@ zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop, char *alt_keylocation) error: zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf); - if (key_material != NULL) + if (key_material != NULL) { free(key_material); - if (key_data != NULL) + key_material = NULL; + } + if (key_data != NULL) { free(key_data); + key_data = NULL; + } /* * Here we decide if it is ok to allow the user to retry entering their * key. The can_retry flag will be set if the user is entering their - * key from an interactive prompt. The correctible flag will only be - * set if an error that occured could be corrected by retrying. Both + * key from an interactive prompt. The correctable flag will only be + * set if an error that occurred could be corrected by retrying. Both * flags are needed to allow the user to attempt key entry again */ - if (can_retry && correctible && attempts <= MAX_KEY_PROMPT_ATTEMPTS) { - attempts++; + attempts++; + if (can_retry && correctible && attempts < MAX_KEY_PROMPT_ATTEMPTS) goto try_again; - } return (ret); } diff --git a/lib/libzfs/libzfs_status.c b/lib/libzfs/libzfs_status.c index 320783523b7d..f900ac723107 100644 --- a/lib/libzfs/libzfs_status.c +++ b/lib/libzfs/libzfs_status.c @@ -351,6 +351,15 @@ check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap) if (find_vdev_problem(nvroot, vdev_removed)) return (ZPOOL_STATUS_REMOVED_DEV); + /* + * Informational errata available. + */ + (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRATA, &errata); + if (errata) { + *erratap = errata; + return (ZPOOL_STATUS_ERRATA); + } + /* * Outdated, but usable, version */ @@ -382,15 +391,6 @@ check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap) } } - /* - * Informational errata available. - */ - (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRATA, &errata); - if (errata) { - *erratap = errata; - return (ZPOOL_STATUS_ERRATA); - } - return (ZPOOL_STATUS_OK); } diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 45b0abe7fd6c..2f3fe97719d5 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -1229,6 +1229,7 @@ hdr_full_cons(void *vbuf, void *unused, int kmflag) arc_buf_hdr_t *hdr = vbuf; bzero(hdr, HDR_FULL_SIZE); + hdr->b_l1hdr.b_byteswap = DMU_BSWAP_NUMFUNCS; cv_init(&hdr->b_l1hdr.b_cv, NULL, CV_DEFAULT, NULL); refcount_create(&hdr->b_l1hdr.b_refcnt); mutex_init(&hdr->b_l1hdr.b_freeze_lock, NULL, MUTEX_DEFAULT, NULL); @@ -3246,9 +3247,6 @@ arc_hdr_alloc_abd(arc_buf_hdr_t *hdr, boolean_t alloc_rdata) ASSERT(!HDR_SHARED_DATA(hdr) || alloc_rdata); IMPLY(alloc_rdata, HDR_PROTECTED(hdr)); - if (hdr->b_l1hdr.b_pabd == NULL && !HDR_HAS_RABD(hdr)) - hdr->b_l1hdr.b_byteswap = DMU_BSWAP_NUMFUNCS; - if (alloc_rdata) { size = HDR_GET_PSIZE(hdr); ASSERT3P(hdr->b_crypt_hdr.b_rabd, ==, NULL); @@ -6751,6 +6749,17 @@ arc_write_ready(zio_t *zio) ASSERT3U(BP_GET_TYPE(bp), !=, DMU_OT_INTENT_LOG); ASSERT(HDR_PROTECTED(hdr)); + if (BP_SHOULD_BYTESWAP(bp)) { + if (BP_GET_LEVEL(bp) > 0) { + hdr->b_l1hdr.b_byteswap = DMU_BSWAP_UINT64; + } else { + hdr->b_l1hdr.b_byteswap = + DMU_OT_BYTESWAP(BP_GET_TYPE(bp)); + } + } else { + hdr->b_l1hdr.b_byteswap = DMU_BSWAP_NUMFUNCS; + } + hdr->b_crypt_hdr.b_ot = BP_GET_TYPE(bp); hdr->b_crypt_hdr.b_dsobj = zio->io_bookmark.zb_objset; zio_crypt_decode_params_bp(bp, hdr->b_crypt_hdr.b_salt, diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 56740ae375a8..20ed3ebffcac 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -2029,6 +2029,23 @@ dmu_object_set_blocksize(objset_t *os, uint64_t object, uint64_t size, int ibs, return (err); } +int +dmu_object_set_maxblkid(objset_t *os, uint64_t object, uint64_t maxblkid, + dmu_tx_t *tx) +{ + dnode_t *dn; + int err; + + err = dnode_hold(os, object, FTAG, &dn); + if (err) + return (err); + rw_enter(&dn->dn_struct_rwlock, RW_WRITER); + dnode_new_blkid(dn, maxblkid, tx, B_FALSE); + rw_exit(&dn->dn_struct_rwlock); + dnode_rele(dn, FTAG); + return (0); +} + void dmu_object_set_checksum(objset_t *os, uint64_t object, uint8_t checksum, dmu_tx_t *tx) @@ -2214,8 +2231,10 @@ dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp) dedup = B_FALSE; } - if (type == DMU_OT_DNODE || type == DMU_OT_OBJSET) + if (level <= 0 && + (type == DMU_OT_DNODE || type == DMU_OT_OBJSET)) { compress = ZIO_COMPRESS_EMPTY; + } } zp->zp_compress = compress; @@ -2488,6 +2507,7 @@ EXPORT_SYMBOL(dmu_object_size_from_db); EXPORT_SYMBOL(dmu_object_dnsize_from_db); EXPORT_SYMBOL(dmu_object_set_nlevels); EXPORT_SYMBOL(dmu_object_set_blocksize); +EXPORT_SYMBOL(dmu_object_set_maxblkid); EXPORT_SYMBOL(dmu_object_set_checksum); EXPORT_SYMBOL(dmu_object_set_compress); EXPORT_SYMBOL(dmu_write_policy); diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index e596b70e9ca0..2b069b6ced02 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -663,6 +663,9 @@ dmu_objset_own_impl(dsl_dataset_t *ds, dmu_objset_type_t type, return (SET_ERROR(EINVAL)); } else if (!readonly && dsl_dataset_is_snapshot(ds)) { return (SET_ERROR(EROFS)); + } else if (!readonly && decrypt && + dsl_dir_incompatible_encryption_version(ds->ds_dir)) { + return (SET_ERROR(EROFS)); } /* if we are decrypting, we can now check MACs in os->os_phys_buf */ @@ -2635,6 +2638,13 @@ dmu_objset_find(char *name, int func(const char *, void *), void *arg, return (error); } +boolean_t +dmu_objset_incompatible_encryption_version(objset_t *os) +{ + return (dsl_dir_incompatible_encryption_version( + os->os_dsl_dataset->ds_dir)); +} + void dmu_objset_set_user(objset_t *os, void *user_ptr) { diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 09d79742bae6..63a4f98bfd15 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -570,6 +570,7 @@ dump_dnode(dmu_sendarg_t *dsp, const blkptr_t *bp, uint64_t object, drro->drr_flags |= DRR_RAW_BYTESWAP; /* needed for reconstructing dnp on recv side */ + drro->drr_maxblkid = dnp->dn_maxblkid; drro->drr_indblkshift = dnp->dn_indblkshift; drro->drr_nlevels = dnp->dn_nlevels; drro->drr_nblkptr = dnp->dn_nblkptr; @@ -2294,6 +2295,7 @@ byteswap_record(dmu_replay_record_t *drr) DO32(drr_object.drr_bonuslen); DO32(drr_object.drr_raw_bonuslen); DO64(drr_object.drr_toguid); + DO64(drr_object.drr_maxblkid); break; case DRR_FREEOBJECTS: DO64(drr_freeobjects.drr_firstobj); @@ -2478,11 +2480,17 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro, if (rwa->raw && nblkptr != drro->drr_nblkptr) return (SET_ERROR(EINVAL)); - if (drro->drr_blksz != doi.doi_data_block_size || + if (rwa->raw && + (drro->drr_blksz != doi.doi_data_block_size || nblkptr < doi.doi_nblkptr || - (rwa->raw && - (indblksz != doi.doi_metadata_block_size || - drro->drr_nlevels < doi.doi_indirection))) { + indblksz != doi.doi_metadata_block_size || + drro->drr_nlevels < doi.doi_indirection)) { + err = dmu_free_long_range_raw(rwa->os, + drro->drr_object, 0, DMU_OBJECT_END); + if (err != 0) + return (SET_ERROR(EINVAL)); + } else if (drro->drr_blksz != doi.doi_data_block_size || + nblkptr < doi.doi_nblkptr) { err = dmu_free_long_range(rwa->os, drro->drr_object, 0, DMU_OBJECT_END); if (err != 0) @@ -2538,6 +2546,8 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro, drro->drr_blksz, drro->drr_indblkshift, tx)); VERIFY0(dmu_object_set_nlevels(rwa->os, drro->drr_object, drro->drr_nlevels, tx)); + VERIFY0(dmu_object_set_maxblkid(rwa->os, drro->drr_object, + drro->drr_maxblkid, tx)); } if (data != NULL) { @@ -2839,9 +2849,12 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs, dmu_tx_abort(tx); return (err); } - dmu_buf_will_dirty(db_spill, tx); - if (rwa->raw) + if (rwa->raw) { VERIFY0(dmu_object_dirty_raw(rwa->os, drrs->drr_object, tx)); + dmu_buf_will_change_crypt_params(db_spill, tx); + } else { + dmu_buf_will_dirty(db_spill, tx); + } if (db_spill->db_size < drrs->drr_length) VERIFY(0 == dbuf_spill_set_blksz(db_spill, @@ -3772,7 +3785,12 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp, int next_err = 0; while (next_err == 0) { - free_err = dmu_free_long_object(rwa->os, obj); + if (drc->drc_raw) { + free_err = dmu_free_long_object_raw(rwa->os, + obj); + } else { + free_err = dmu_free_long_object(rwa->os, obj); + } if (free_err != 0 && free_err != ENOENT) break; diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c index c1fbf3c3b3f7..544e736d8600 100644 --- a/module/zfs/dnode.c +++ b/module/zfs/dnode.c @@ -134,6 +134,7 @@ dnode_cons(void *arg, void *unused, int kmflag) bzero(&dn->dn_rm_spillblk[0], sizeof (dn->dn_rm_spillblk)); bzero(&dn->dn_next_bonuslen[0], sizeof (dn->dn_next_bonuslen)); bzero(&dn->dn_next_blksz[0], sizeof (dn->dn_next_blksz)); + bzero(&dn->dn_next_maxblkid[0], sizeof (dn->dn_next_maxblkid)); for (i = 0; i < TXG_SIZE; i++) { list_link_init(&dn->dn_dirty_link[i]); @@ -193,6 +194,7 @@ dnode_dest(void *arg, void *unused) ASSERT0(dn->dn_rm_spillblk[i]); ASSERT0(dn->dn_next_bonuslen[i]); ASSERT0(dn->dn_next_blksz[i]); + ASSERT0(dn->dn_next_maxblkid[i]); } ASSERT0(dn->dn_allocated_txg); @@ -602,6 +604,7 @@ dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs, ASSERT0(dn->dn_next_bonustype[i]); ASSERT0(dn->dn_rm_spillblk[i]); ASSERT0(dn->dn_next_blksz[i]); + ASSERT0(dn->dn_next_maxblkid[i]); ASSERT(!list_link_active(&dn->dn_dirty_link[i])); ASSERT3P(list_head(&dn->dn_dirty_records[i]), ==, NULL); ASSERT3P(dn->dn_free_ranges[i], ==, NULL); @@ -767,6 +770,8 @@ dnode_move_impl(dnode_t *odn, dnode_t *ndn) sizeof (odn->dn_next_bonuslen)); bcopy(&odn->dn_next_blksz[0], &ndn->dn_next_blksz[0], sizeof (odn->dn_next_blksz)); + bcopy(&odn->dn_next_maxblkid[0], &ndn->dn_next_maxblkid[0], + sizeof (odn->dn_next_maxblkid)); for (i = 0; i < TXG_SIZE; i++) { list_move_tail(&ndn->dn_dirty_records[i], &odn->dn_dirty_records[i]); @@ -1751,6 +1756,7 @@ dnode_new_blkid(dnode_t *dn, uint64_t blkid, dmu_tx_t *tx, boolean_t have_read) goto out; dn->dn_maxblkid = blkid; + dn->dn_next_maxblkid[tx->tx_txg & TXG_MASK] = blkid; /* * Compute the number of levels necessary to support the new maxblkid. diff --git a/module/zfs/dnode_sync.c b/module/zfs/dnode_sync.c index 2ec729a6f93a..09437993a89b 100644 --- a/module/zfs/dnode_sync.c +++ b/module/zfs/dnode_sync.c @@ -519,6 +519,7 @@ dnode_sync_free(dnode_t *dn, dmu_tx_t *tx) dn->dn_next_nlevels[txgoff] = 0; dn->dn_next_indblkshift[txgoff] = 0; dn->dn_next_blksz[txgoff] = 0; + dn->dn_next_maxblkid[txgoff] = 0; /* ASSERT(blkptrs are zero); */ ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE); @@ -718,6 +719,17 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx) dn->dn_next_nlevels[txgoff] = 0; } + /* + * This must be done after dnode_sync_free_range() + * and dnode_increase_indirection(). + */ + if (dn->dn_next_maxblkid[txgoff]) { + mutex_enter(&dn->dn_mtx); + dnp->dn_maxblkid = dn->dn_next_maxblkid[txgoff]; + dn->dn_next_maxblkid[txgoff] = 0; + mutex_exit(&dn->dn_mtx); + } + if (dn->dn_next_nblkptr[txgoff]) { /* this should only happen on a realloc */ ASSERT(dn->dn_allocated_txg == tx->tx_txg); diff --git a/module/zfs/dsl_crypt.c b/module/zfs/dsl_crypt.c index 59562d194e73..cb13d2cdca6d 100644 --- a/module/zfs/dsl_crypt.c +++ b/module/zfs/dsl_crypt.c @@ -347,7 +347,7 @@ spa_keystore_fini(spa_keystore_t *sk) rw_destroy(&sk->sk_dk_lock); } -int +static int dsl_dir_get_encryption_root_ddobj(dsl_dir_t *dd, uint64_t *rddobj) { if (dd->dd_crypto_obj == 0) @@ -357,6 +357,34 @@ dsl_dir_get_encryption_root_ddobj(dsl_dir_t *dd, uint64_t *rddobj) DSL_CRYPTO_KEY_ROOT_DDOBJ, 8, 1, rddobj)); } +int +dsl_dir_get_encryption_version(dsl_dir_t *dd, uint64_t *version) +{ + *version = 0; + + if (dd->dd_crypto_obj == 0) + return (SET_ERROR(ENOENT)); + + /* version 0 is implied by ENOENT */ + (void) zap_lookup(dd->dd_pool->dp_meta_objset, dd->dd_crypto_obj, + DSL_CRYPTO_KEY_VERSION, 8, 1, version); + + return (0); +} + +boolean_t +dsl_dir_incompatible_encryption_version(dsl_dir_t *dd) +{ + int ret; + uint64_t version = 0; + + ret = dsl_dir_get_encryption_version(dd, &version); + if (ret != 0) + return (B_FALSE); + + return (version != ZIO_CRYPT_KEY_CURRENT_VERSION); +} + static int spa_keystore_wkey_hold_ddobj_impl(spa_t *spa, uint64_t ddobj, void *tag, dsl_wrapping_key_t **wkey_out) @@ -514,7 +542,7 @@ dsl_crypto_key_open(objset_t *mos, dsl_wrapping_key_t *wkey, uint64_t dckobj, void *tag, dsl_crypto_key_t **dck_out) { int ret; - uint64_t crypt = 0, guid = 0; + uint64_t crypt = 0, guid = 0, version = 0; uint8_t raw_keydata[MASTER_KEY_MAX_LEN]; uint8_t raw_hmac_keydata[SHA512_HMAC_KEYLEN]; uint8_t iv[WRAPPING_IV_LEN]; @@ -556,12 +584,15 @@ dsl_crypto_key_open(objset_t *mos, dsl_wrapping_key_t *wkey, if (ret != 0) goto error; + /* the initial on-disk format for encryption did not have a version */ + (void) zap_lookup(mos, dckobj, DSL_CRYPTO_KEY_VERSION, 8, 1, &version); + /* * Unwrap the keys. If there is an error return EACCES to indicate * an authentication failure. */ - ret = zio_crypt_key_unwrap(&wkey->wk_key, crypt, guid, raw_keydata, - raw_hmac_keydata, iv, mac, &dck->dck_key); + ret = zio_crypt_key_unwrap(&wkey->wk_key, crypt, version, guid, + raw_keydata, raw_hmac_keydata, iv, mac, &dck->dck_key); if (ret != 0) { ret = SET_ERROR(EACCES); goto error; @@ -1883,7 +1914,7 @@ dsl_crypto_recv_key_check(void *arg, dmu_tx_t *tx) dsl_dataset_t *ds = NULL; uint8_t *buf = NULL; uint_t len; - uint64_t intval, guid, nlevels, blksz, ibs, nblkptr; + uint64_t intval, guid, nlevels, blksz, ibs, nblkptr, maxblkid, version; boolean_t is_passphrase = B_FALSE; ret = dsl_dataset_hold_obj(tx->tx_pool, dcrka->dcrka_dsobj, FTAG, &ds); @@ -1952,6 +1983,17 @@ dsl_crypto_recv_key_check(void *arg, dmu_tx_t *tx) goto error; } + /* + * We don't support receiving old on-disk formats. The version 0 + * implementation protected several fields in an objset that were + * not always portable during a raw receive. As a result, we call + * the old version an on-disk errata #3. + */ + ret = nvlist_lookup_uint64(nvl, DSL_CRYPTO_KEY_VERSION, &version); + if (ret != 0 || version != ZIO_CRYPT_KEY_CURRENT_VERSION) { + ret = SET_ERROR(ENOTSUP); + goto error; + } ret = nvlist_lookup_uint8_array(nvl, "portable_mac", &buf, &len); if (ret != 0 || len != ZIO_OBJSET_MAC_LEN) { @@ -2028,6 +2070,12 @@ dsl_crypto_recv_key_check(void *arg, dmu_tx_t *tx) goto error; } + ret = nvlist_lookup_uint64(nvl, "mdn_maxblkid", &maxblkid); + if (ret != 0) { + ret = SET_ERROR(EINVAL); + goto error; + } + ret = dmu_objset_from_ds(ds, &os); if (ret != 0) goto error; @@ -2078,8 +2126,9 @@ dsl_crypto_recv_key_sync(void *arg, dmu_tx_t *tx) uint8_t *keydata, *hmac_keydata, *iv, *mac, *portable_mac; uint_t len; uint64_t rddobj, one = 1; + uint64_t version = ZIO_CRYPT_KEY_CURRENT_VERSION; uint64_t crypt, guid, keyformat, iters, salt; - uint64_t compress, checksum, nlevels, blksz, ibs; + uint64_t compress, checksum, nlevels, blksz, ibs, maxblkid; char *keylocation = "prompt"; VERIFY0(dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds)); @@ -2108,6 +2157,7 @@ dsl_crypto_recv_key_sync(void *arg, dmu_tx_t *tx) nlevels = fnvlist_lookup_uint64(nvl, "mdn_nlevels"); blksz = fnvlist_lookup_uint64(nvl, "mdn_blksz"); ibs = fnvlist_lookup_uint64(nvl, "mdn_indblkshift"); + maxblkid = fnvlist_lookup_uint64(nvl, "mdn_maxblkid"); /* if we haven't created an objset for the ds yet, do that now */ rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); @@ -2132,6 +2182,11 @@ dsl_crypto_recv_key_sync(void *arg, dmu_tx_t *tx) /* set metadnode compression and checksum */ mdn->dn_compress = compress; mdn->dn_checksum = checksum; + + rw_enter(&mdn->dn_struct_rwlock, RW_WRITER); + dnode_new_blkid(mdn, maxblkid, tx, B_FALSE); + rw_exit(&mdn->dn_struct_rwlock); + dsl_dataset_dirty(ds, tx); /* if this is a new dataset setup the DSL Crypto Key. */ @@ -2146,6 +2201,9 @@ dsl_crypto_recv_key_sync(void *arg, dmu_tx_t *tx) VERIFY0(zap_update(tx->tx_pool->dp_meta_objset, ds->ds_dir->dd_crypto_obj, DSL_CRYPTO_KEY_REFCOUNT, sizeof (uint64_t), 1, &one, tx)); + VERIFY0(zap_update(tx->tx_pool->dp_meta_objset, + ds->ds_dir->dd_crypto_obj, DSL_CRYPTO_KEY_VERSION, + sizeof (uint64_t), 1, &version, tx)); dsl_dataset_activate_feature(dsobj, SPA_FEATURE_ENCRYPTION, tx); ds->ds_feature_inuse[SPA_FEATURE_ENCRYPTION] = B_TRUE; @@ -2209,7 +2267,8 @@ dsl_crypto_populate_key_nvlist(dsl_dataset_t *ds, nvlist_t **nvl_out) dsl_dir_t *rdd = NULL; dsl_pool_t *dp = ds->ds_dir->dd_pool; objset_t *mos = dp->dp_meta_objset; - uint64_t crypt = 0, guid = 0, format = 0, iters = 0, salt = 0; + uint64_t crypt = 0, guid = 0, format = 0; + uint64_t iters = 0, salt = 0, version = 0; uint8_t raw_keydata[MASTER_KEY_MAX_LEN]; uint8_t raw_hmac_keydata[SHA512_HMAC_KEYLEN]; uint8_t iv[WRAPPING_IV_LEN]; @@ -2254,6 +2313,17 @@ dsl_crypto_populate_key_nvlist(dsl_dataset_t *ds, nvlist_t **nvl_out) if (ret != 0) goto error; + /* + * We don't support raw sends of legacy on-disk formats. See the + * comment in dsl_crypto_recv_key_check() for details. + */ + ret = zap_lookup(mos, dckobj, DSL_CRYPTO_KEY_VERSION, 8, 1, &version); + if (ret != 0 || version != ZIO_CRYPT_KEY_CURRENT_VERSION) { + dp->dp_spa->spa_errata = ZPOOL_ERRATA_ZOL_6845_ENCRYPTION; + ret = SET_ERROR(ENOTSUP); + goto error; + } + /* * Lookup wrapping key properties. An early version of the code did * not correctly add these values to the wrapping key or the DSL @@ -2293,6 +2363,7 @@ dsl_crypto_populate_key_nvlist(dsl_dataset_t *ds, nvlist_t **nvl_out) fnvlist_add_uint64(nvl, DSL_CRYPTO_KEY_CRYPTO_SUITE, crypt); fnvlist_add_uint64(nvl, DSL_CRYPTO_KEY_GUID, guid); + fnvlist_add_uint64(nvl, DSL_CRYPTO_KEY_VERSION, version); VERIFY0(nvlist_add_uint8_array(nvl, DSL_CRYPTO_KEY_MASTER_KEY, raw_keydata, MASTER_KEY_MAX_LEN)); VERIFY0(nvlist_add_uint8_array(nvl, DSL_CRYPTO_KEY_HMAC_KEY, @@ -2312,6 +2383,7 @@ dsl_crypto_populate_key_nvlist(dsl_dataset_t *ds, nvlist_t **nvl_out) fnvlist_add_uint64(nvl, "mdn_blksz", mdn->dn_datablksz); fnvlist_add_uint64(nvl, "mdn_indblkshift", mdn->dn_indblkshift); fnvlist_add_uint64(nvl, "mdn_nblkptr", mdn->dn_nblkptr); + fnvlist_add_uint64(nvl, "mdn_maxblkid", mdn->dn_maxblkid); *nvl_out = nvl; return (0); @@ -2332,7 +2404,8 @@ dsl_crypto_key_create_sync(uint64_t crypt, dsl_wrapping_key_t *wkey, dmu_tx_t *tx) { dsl_crypto_key_t dck; - uint64_t one = 1; + uint64_t version = ZIO_CRYPT_KEY_CURRENT_VERSION; + uint64_t one = 1ULL; ASSERT(dmu_tx_is_syncing(tx)); ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS); @@ -2349,6 +2422,8 @@ dsl_crypto_key_create_sync(uint64_t crypt, dsl_wrapping_key_t *wkey, dsl_crypto_key_sync(&dck, tx); VERIFY0(zap_update(tx->tx_pool->dp_meta_objset, dck.dck_obj, DSL_CRYPTO_KEY_REFCOUNT, sizeof (uint64_t), 1, &one, tx)); + VERIFY0(zap_update(tx->tx_pool->dp_meta_objset, dck.dck_obj, + DSL_CRYPTO_KEY_VERSION, sizeof (uint64_t), 1, &version, tx)); zio_crypt_key_destroy(&dck.dck_key); bzero(&dck.dck_key, sizeof (zio_crypt_key_t)); diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index 68791fe742f2..96e8dd62e1a6 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -187,6 +188,12 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj, VERIFY0(zap_lookup(dp->dp_meta_objset, ddobj, DD_FIELD_CRYPTO_KEY_OBJ, sizeof (uint64_t), 1, &dd->dd_crypto_obj)); + + /* check for on-disk format errata */ + if (dsl_dir_incompatible_encryption_version(dd)) { + dp->dp_spa->spa_errata = + ZPOOL_ERRATA_ZOL_6845_ENCRYPTION; + } } mutex_init(&dd->dd_lock, NULL, MUTEX_DEFAULT, NULL); diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c index 7286773d98b9..18b4ec3d6cf1 100644 --- a/module/zfs/zfs_vfsops.c +++ b/module/zfs/zfs_vfsops.c @@ -1100,6 +1100,15 @@ static int zfsvfs_setup(zfsvfs_t *zfsvfs, boolean_t mounting) { int error; + boolean_t readonly = zfs_is_readonly(zfsvfs); + + /* + * Check for a bad on-disk format version now since we + * lied about owning the dataset readonly before. + */ + if (!readonly && + dmu_objset_incompatible_encryption_version(zfsvfs->z_os)) + return (SET_ERROR(EROFS)); error = zfs_register_callbacks(zfsvfs->z_vfs); if (error) @@ -1113,13 +1122,10 @@ zfsvfs_setup(zfsvfs_t *zfsvfs, boolean_t mounting) * operations out since we closed the ZIL. */ if (mounting) { - boolean_t readonly; - /* * During replay we remove the read only flag to * allow replays to succeed. */ - readonly = zfs_is_readonly(zfsvfs); if (readonly != 0) readonly_changed_cb(zfsvfs, B_FALSE); else diff --git a/module/zfs/zio.c b/module/zfs/zio.c index 263c77e4a2d3..37259ad8ec28 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -402,6 +402,8 @@ zio_decrypt(zio_t *zio, abd_t *data, uint64_t size) int ret; void *tmp; blkptr_t *bp = zio->io_bp; + spa_t *spa = zio->io_spa; + uint64_t dsobj = zio->io_bookmark.zb_objset; uint64_t lsize = BP_GET_LSIZE(bp); dmu_object_type_t ot = BP_GET_TYPE(bp); uint8_t salt[ZIO_DATA_SALT_LEN]; @@ -460,13 +462,12 @@ zio_decrypt(zio_t *zio, abd_t *data, uint64_t size) */ if (BP_IS_AUTHENTICATED(bp)) { if (ot == DMU_OT_OBJSET) { - ret = spa_do_crypt_objset_mac_abd(B_FALSE, zio->io_spa, - zio->io_bookmark.zb_objset, zio->io_abd, size, - BP_SHOULD_BYTESWAP(bp)); + ret = spa_do_crypt_objset_mac_abd(B_FALSE, spa, + dsobj, zio->io_abd, size, BP_SHOULD_BYTESWAP(bp)); } else { zio_crypt_decode_mac_bp(bp, mac); - ret = spa_do_crypt_mac_abd(B_FALSE, zio->io_spa, - zio->io_bookmark.zb_objset, zio->io_abd, size, mac); + ret = spa_do_crypt_mac_abd(B_FALSE, spa, dsobj, + zio->io_abd, size, mac); } abd_copy(data, zio->io_abd, size); @@ -486,9 +487,8 @@ zio_decrypt(zio_t *zio, abd_t *data, uint64_t size) zio_crypt_decode_mac_bp(bp, mac); } - ret = spa_do_crypt_abd(B_FALSE, zio->io_spa, zio->io_bookmark.zb_objset, - bp, bp->blk_birth, size, data, zio->io_abd, iv, mac, salt, - &no_crypt); + ret = spa_do_crypt_abd(B_FALSE, spa, dsobj, bp, bp->blk_birth, + size, data, zio->io_abd, iv, mac, salt, &no_crypt); if (no_crypt) abd_copy(data, zio->io_abd, size); @@ -509,7 +509,7 @@ zio_decrypt(zio_t *zio, abd_t *data, uint64_t size) ret = SET_ERROR(EIO); if ((zio->io_flags & ZIO_FLAG_SPECULATIVE) == 0) { zfs_ereport_post(FM_EREPORT_ZFS_AUTHENTICATION, - zio->io_spa, NULL, &zio->io_bookmark, zio, 0, 0); + spa, NULL, &zio->io_bookmark, zio, 0, 0); } } else { zio->io_error = ret; @@ -3729,6 +3729,7 @@ zio_encrypt(zio_t *zio) spa_t *spa = zio->io_spa; blkptr_t *bp = zio->io_bp; uint64_t psize = BP_GET_PSIZE(bp); + uint64_t dsobj = zio->io_bookmark.zb_objset; dmu_object_type_t ot = BP_GET_TYPE(bp); void *enc_buf = NULL; abd_t *eabd = NULL; @@ -3752,10 +3753,27 @@ zio_encrypt(zio_t *zio) /* if we are doing raw encryption set the provided encryption params */ if (zio->io_flags & ZIO_FLAG_RAW_ENCRYPT) { + ASSERT0(BP_GET_LEVEL(bp)); BP_SET_CRYPT(bp, B_TRUE); BP_SET_BYTEORDER(bp, zp->zp_byteorder); if (ot != DMU_OT_OBJSET) zio_crypt_encode_mac_bp(bp, zp->zp_mac); + + /* dnode blocks must be written out in the provided byteorder */ + if (zp->zp_byteorder != ZFS_HOST_BYTEORDER && + ot == DMU_OT_DNODE) { + void *bswap_buf = zio_buf_alloc(psize); + abd_t *babd = abd_get_from_buf(bswap_buf, psize); + + ASSERT3U(BP_GET_COMPRESS(bp), ==, ZIO_COMPRESS_OFF); + abd_copy_to_buf(bswap_buf, zio->io_abd, psize); + dmu_ot_byteswap[DMU_OT_BYTESWAP(ot)].ob_func(bswap_buf, + psize); + + abd_take_ownership_of_buf(babd, B_TRUE); + zio_push_transform(zio, babd, psize, psize, NULL); + } + if (DMU_OT_IS_ENCRYPTED(ot)) zio_crypt_encode_params_bp(bp, zp->zp_salt, zp->zp_iv); return (ZIO_PIPELINE_CONTINUE); @@ -3779,17 +3797,16 @@ zio_encrypt(zio_t *zio) ASSERT0(DMU_OT_IS_ENCRYPTED(ot)); ASSERT3U(BP_GET_COMPRESS(bp), ==, ZIO_COMPRESS_OFF); BP_SET_CRYPT(bp, B_TRUE); - VERIFY0(spa_do_crypt_objset_mac_abd(B_TRUE, spa, - zio->io_bookmark.zb_objset, zio->io_abd, psize, - BP_SHOULD_BYTESWAP(bp))); + VERIFY0(spa_do_crypt_objset_mac_abd(B_TRUE, spa, dsobj, + zio->io_abd, psize, BP_SHOULD_BYTESWAP(bp))); return (ZIO_PIPELINE_CONTINUE); } /* unencrypted object types are only authenticated with a MAC */ if (!DMU_OT_IS_ENCRYPTED(ot)) { BP_SET_CRYPT(bp, B_TRUE); - VERIFY0(spa_do_crypt_mac_abd(B_TRUE, spa, - zio->io_bookmark.zb_objset, zio->io_abd, psize, mac)); + VERIFY0(spa_do_crypt_mac_abd(B_TRUE, spa, dsobj, + zio->io_abd, psize, mac)); zio_crypt_encode_mac_bp(bp, mac); return (ZIO_PIPELINE_CONTINUE); } @@ -3823,8 +3840,8 @@ zio_encrypt(zio_t *zio) } /* Perform the encryption. This should not fail */ - VERIFY0(spa_do_crypt_abd(B_TRUE, spa, zio->io_bookmark.zb_objset, bp, - zio->io_txg, psize, zio->io_abd, eabd, iv, mac, salt, &no_crypt)); + VERIFY0(spa_do_crypt_abd(B_TRUE, spa, dsobj, bp, zio->io_txg, + psize, zio->io_abd, eabd, iv, mac, salt, &no_crypt)); /* encode encryption metadata into the bp */ if (ot == DMU_OT_INTENT_LOG) { @@ -4154,7 +4171,6 @@ zio_done(zio_t *zio) if (zio->io_type == ZIO_TYPE_WRITE && !BP_IS_HOLE(zio->io_bp) && zio->io_bp_override == NULL && !(zio->io_flags & ZIO_FLAG_IO_REPAIR)) { - ASSERT(!BP_SHOULD_BYTESWAP(zio->io_bp)); ASSERT3U(zio->io_prop.zp_copies, <=, BP_GET_NDVAS(zio->io_bp)); ASSERT(BP_COUNT_GANG(zio->io_bp) == 0 || diff --git a/module/zfs/zio_crypt.c b/module/zfs/zio_crypt.c index 5ffa1e8b0ce2..823e6b8d66ea 100644 --- a/module/zfs/zio_crypt.c +++ b/module/zfs/zio_crypt.c @@ -187,6 +187,12 @@ (MIN(zfs_key_max_salt_uses, ZFS_KEY_MAX_SALT_USES_DEFAULT)) unsigned long zfs_key_max_salt_uses = ZFS_KEY_MAX_SALT_USES_DEFAULT; +typedef struct blkptr_auth_buf { + uint64_t bab_prop; /* blk_prop - portable mask */ + uint8_t bab_mac[ZIO_DATA_MAC_LEN]; /* MAC from blk_cksum */ + uint64_t bab_pad; /* reserved for future use */ +} blkptr_auth_buf_t; + zio_crypt_info_t zio_crypt_table[ZIO_CRYPT_FUNCTIONS] = { {"", ZC_TYPE_NONE, 0, "inherit"}, {"", ZC_TYPE_NONE, 0, "on"}, @@ -275,6 +281,7 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key) key->zk_hmac_tmpl = NULL; key->zk_crypt = crypt; + key->zk_version = ZIO_CRYPT_KEY_CURRENT_VERSION; key->zk_salt_count = 0; rw_init(&key->zk_salt_lock, NULL, RW_DEFAULT, NULL); @@ -472,10 +479,10 @@ zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv, { int ret; uio_t puio, cuio; + uint64_t aad[3]; iovec_t plain_iovecs[2], cipher_iovecs[3]; uint64_t crypt = key->zk_crypt; - uint64_t le_guid = LE_64(key->zk_guid); - uint_t enc_len, keydata_len; + uint_t enc_len, keydata_len, aad_len; ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS); ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW); @@ -500,6 +507,22 @@ zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv, cipher_iovecs[2].iov_base = mac; cipher_iovecs[2].iov_len = WRAPPING_MAC_LEN; + /* + * Although we don't support writing to the old format, we do + * support rewrapping the key so that the user can move and + * quarantine datasets on the old format. + */ + if (key->zk_version == 0) { + aad_len = sizeof (uint64_t); + aad[0] = LE_64(key->zk_guid); + } else { + ASSERT3U(key->zk_version, ==, ZIO_CRYPT_KEY_CURRENT_VERSION); + aad_len = sizeof (uint64_t) * 3; + aad[0] = LE_64(key->zk_guid); + aad[1] = LE_64(crypt); + aad[2] = LE_64(key->zk_version); + } + enc_len = zio_crypt_table[crypt].ci_keylen + SHA512_HMAC_KEYLEN; puio.uio_iov = plain_iovecs; puio.uio_iovcnt = 2; @@ -510,7 +533,7 @@ zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv, /* encrypt the keys and store the resulting ciphertext and mac */ ret = zio_do_crypt_uio(B_TRUE, crypt, cwkey, NULL, iv, enc_len, - &puio, &cuio, (uint8_t *)&le_guid, sizeof (uint64_t)); + &puio, &cuio, (uint8_t *)aad, aad_len); if (ret != 0) goto error; @@ -521,16 +544,16 @@ zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv, } int -zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t guid, - uint8_t *keydata, uint8_t *hmac_keydata, uint8_t *iv, uint8_t *mac, - zio_crypt_key_t *key) +zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version, + uint64_t guid, uint8_t *keydata, uint8_t *hmac_keydata, uint8_t *iv, + uint8_t *mac, zio_crypt_key_t *key) { int ret; crypto_mechanism_t mech; uio_t puio, cuio; + uint64_t aad[3]; iovec_t plain_iovecs[2], cipher_iovecs[3]; - uint_t enc_len, keydata_len; - uint64_t le_guid = LE_64(guid); + uint_t enc_len, keydata_len, aad_len; ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS); ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW); @@ -550,6 +573,17 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t guid, cipher_iovecs[2].iov_base = mac; cipher_iovecs[2].iov_len = WRAPPING_MAC_LEN; + if (version == 0) { + aad_len = sizeof (uint64_t); + aad[0] = LE_64(guid); + } else { + ASSERT3U(version, ==, ZIO_CRYPT_KEY_CURRENT_VERSION); + aad_len = sizeof (uint64_t) * 3; + aad[0] = LE_64(guid); + aad[1] = LE_64(crypt); + aad[2] = LE_64(version); + } + enc_len = keydata_len + SHA512_HMAC_KEYLEN; puio.uio_iov = plain_iovecs; puio.uio_segflg = UIO_SYSSPACE; @@ -560,7 +594,7 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t guid, /* decrypt the keys and store the result in the output buffers */ ret = zio_do_crypt_uio(B_FALSE, crypt, cwkey, NULL, iv, enc_len, - &puio, &cuio, (uint8_t *)&le_guid, sizeof (uint64_t)); + &puio, &cuio, (uint8_t *)aad, aad_len); if (ret != 0) goto error; @@ -602,6 +636,7 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t guid, key->zk_hmac_tmpl = NULL; key->zk_crypt = crypt; + key->zk_version = version; key->zk_guid = guid; key->zk_salt_count = 0; rw_init(&key->zk_salt_lock, NULL, RW_DEFAULT, NULL); @@ -700,19 +735,32 @@ zio_crypt_generate_iv_salt_dedup(zio_crypt_key_t *key, uint8_t *data, * byte strings, which normally means that these strings would not need to deal * with byteswapping at all. However, both blkptr_t and zil_header_t may be * byteswapped by lower layers and so we must "undo" that byteswap here upon - * decoding. + * decoding and encoding in a non-native byteorder. These functions require + * that the byteorder bit is correct before being called. */ void zio_crypt_encode_params_bp(blkptr_t *bp, uint8_t *salt, uint8_t *iv) { + uint64_t val64; uint32_t val32; ASSERT(BP_IS_ENCRYPTED(bp)); - bcopy(salt, &bp->blk_dva[2].dva_word[0], sizeof (uint64_t)); - bcopy(iv, &bp->blk_dva[2].dva_word[1], sizeof (uint64_t)); - bcopy(iv + sizeof (uint64_t), &val32, sizeof (uint32_t)); - BP_SET_IV2(bp, val32); + if (!BP_SHOULD_BYTESWAP(bp)) { + bcopy(salt, &bp->blk_dva[2].dva_word[0], sizeof (uint64_t)); + bcopy(iv, &bp->blk_dva[2].dva_word[1], sizeof (uint64_t)); + bcopy(iv + sizeof (uint64_t), &val32, sizeof (uint32_t)); + BP_SET_IV2(bp, val32); + } else { + bcopy(salt, &val64, sizeof (uint64_t)); + bp->blk_dva[2].dva_word[0] = BSWAP_64(val64); + + bcopy(iv, &val64, sizeof (uint64_t)); + bp->blk_dva[2].dva_word[1] = BSWAP_64(val64); + + bcopy(iv + sizeof (uint64_t), &val32, sizeof (uint32_t)); + BP_SET_IV2(bp, BSWAP_32(val32)); + } } void @@ -751,12 +799,22 @@ zio_crypt_decode_params_bp(const blkptr_t *bp, uint8_t *salt, uint8_t *iv) void zio_crypt_encode_mac_bp(blkptr_t *bp, uint8_t *mac) { + uint64_t val64; + ASSERT(BP_USES_CRYPT(bp)); ASSERT3U(BP_GET_TYPE(bp), !=, DMU_OT_OBJSET); - bcopy(mac, &bp->blk_cksum.zc_word[2], sizeof (uint64_t)); - bcopy(mac + sizeof (uint64_t), &bp->blk_cksum.zc_word[3], - sizeof (uint64_t)); + if (!BP_SHOULD_BYTESWAP(bp)) { + bcopy(mac, &bp->blk_cksum.zc_word[2], sizeof (uint64_t)); + bcopy(mac + sizeof (uint64_t), &bp->blk_cksum.zc_word[3], + sizeof (uint64_t)); + } else { + bcopy(mac, &val64, sizeof (uint64_t)); + bp->blk_cksum.zc_word[2] = BSWAP_64(val64); + + bcopy(mac + sizeof (uint64_t), &val64, sizeof (uint64_t)); + bp->blk_cksum.zc_word[3] = BSWAP_64(val64); + } } void @@ -841,55 +899,107 @@ zio_crypt_copy_dnode_bonus(abd_t *src_abd, uint8_t *dst, uint_t datalen) abd_return_buf(src_abd, src, datalen); } +/* + * This function decides what fields from blk_prop are included in + * the on-disk various MAC algorithms. + */ static void -zio_crypt_bp_zero_nonportable_blkprop(blkptr_t *bp) +zio_crypt_bp_zero_nonportable_blkprop(blkptr_t *bp, uint64_t version) { - BP_SET_DEDUP(bp, 0); - BP_SET_CHECKSUM(bp, 0); + /* + * Version 0 did not properly zero out all non-portable fields + * as it should have done. We maintain this code so that we can + * do read-only imports of pools on this version. + */ + if (version == 0) { + BP_SET_DEDUP(bp, 0); + BP_SET_CHECKSUM(bp, 0); + BP_SET_PSIZE(bp, SPA_MINBLOCKSIZE); + return; + } + + ASSERT3U(version, ==, ZIO_CRYPT_KEY_CURRENT_VERSION); + + /* + * The hole_birth feature might set these fields even if this bp + * is a hole. We zero them out here to guarantee that raw sends + * will function with or without the feature. + */ + if (BP_IS_HOLE(bp)) { + bp->blk_prop = 0ULL; + return; + } /* - * psize cannot be set to zero or it will trigger asserts, but the - * value doesn't really matter as long as it is constant. + * At L0 we want to verify these fields to ensure that data blocks + * can not be reinterpretted. For instance, we do not want an attacker + * to trick us into returning raw lz4 compressed data to the user + * by modifying the compression bits. At higher levels, we cannot + * enforce this policy since raw sends do not convey any information + * about indirect blocks, so these values might be different on the + * receive side. Fortunately, this does not open any new attack + * vectors, since any alterations that can be made to a higher level + * bp must still verify the correct order of the layer below it. */ - BP_SET_PSIZE(bp, SPA_MINBLOCKSIZE); + if (BP_GET_LEVEL(bp) != 0) { + BP_SET_BYTEORDER(bp, 0); + BP_SET_COMPRESS(bp, 0); + + /* + * psize cannot be set to zero or it will trigger + * asserts, but the value doesn't really matter as + * long as it is constant. + */ + BP_SET_PSIZE(bp, SPA_MINBLOCKSIZE); + } + + BP_SET_DEDUP(bp, 0); + BP_SET_CHECKSUM(bp, 0); } -static int -zio_crypt_bp_do_hmac_updates(crypto_context_t ctx, boolean_t should_bswap, - blkptr_t *bp) +static void +zio_crypt_bp_auth_init(uint64_t version, boolean_t should_bswap, blkptr_t *bp, + blkptr_auth_buf_t *bab, uint_t *bab_len) { - int ret; - crypto_data_t cd; - uint64_t le_blkprop; blkptr_t tmpbp = *bp; - uint8_t mac[ZIO_DATA_MAC_LEN]; - - cd.cd_format = CRYPTO_DATA_RAW; - cd.cd_offset = 0; if (should_bswap) byteswap_uint64_array(&tmpbp, sizeof (blkptr_t)); ASSERT(BP_USES_CRYPT(&tmpbp) || BP_IS_HOLE(&tmpbp)); ASSERT0(BP_IS_EMBEDDED(&tmpbp)); - zio_crypt_bp_zero_nonportable_blkprop(&tmpbp); - le_blkprop = (ZFS_HOST_BYTEORDER) ? - tmpbp.blk_prop : BSWAP_64(tmpbp.blk_prop); + zio_crypt_decode_mac_bp(&tmpbp, bab->bab_mac); - cd.cd_length = sizeof (uint64_t); - cd.cd_raw.iov_base = (char *)&le_blkprop; - cd.cd_raw.iov_len = cd.cd_length; + /* + * We always MAC blk_prop in LE to ensure portability. This + * must be done after decoding the mac, since the endianness + * will get zero'd out here. + */ + zio_crypt_bp_zero_nonportable_blkprop(&tmpbp, version); + bab->bab_prop = LE_64(tmpbp.blk_prop); + bab->bab_pad = 0ULL; + + /* version 0 did not include the padding */ + *bab_len = sizeof (blkptr_auth_buf_t); + if (version == 0) + *bab_len -= sizeof (uint64_t); +} - ret = crypto_mac_update(ctx, &cd, NULL); - if (ret != CRYPTO_SUCCESS) { - ret = SET_ERROR(EIO); - goto error; - } +static int +zio_crypt_bp_do_hmac_updates(crypto_context_t ctx, uint64_t version, + boolean_t should_bswap, blkptr_t *bp) +{ + int ret; + uint_t bab_len; + blkptr_auth_buf_t bab; + crypto_data_t cd; - zio_crypt_decode_mac_bp(&tmpbp, mac); - cd.cd_length = ZIO_DATA_MAC_LEN; - cd.cd_raw.iov_base = (char *)mac; + zio_crypt_bp_auth_init(version, should_bswap, bp, &bab, &bab_len); + cd.cd_format = CRYPTO_DATA_RAW; + cd.cd_offset = 0; + cd.cd_length = bab_len; + cd.cd_raw.iov_base = (char *)&bab; cd.cd_raw.iov_len = cd.cd_length; ret = crypto_mac_update(ctx, &cd, NULL); @@ -905,60 +1015,32 @@ zio_crypt_bp_do_hmac_updates(crypto_context_t ctx, boolean_t should_bswap, } static void -zio_crypt_bp_do_indrect_checksum_updates(SHA2_CTX *ctx, boolean_t should_bswap, - blkptr_t *bp) +zio_crypt_bp_do_indrect_checksum_updates(SHA2_CTX *ctx, uint64_t version, + boolean_t should_bswap, blkptr_t *bp) { - blkptr_t tmpbp = *bp; - uint8_t mac[ZIO_DATA_MAC_LEN]; - - if (should_bswap) - byteswap_uint64_array(&tmpbp, sizeof (blkptr_t)); + uint_t bab_len; + blkptr_auth_buf_t bab; - ASSERT(BP_USES_CRYPT(&tmpbp) || BP_IS_HOLE(&tmpbp)); - ASSERT0(BP_IS_EMBEDDED(&tmpbp)); - zio_crypt_bp_zero_nonportable_blkprop(&tmpbp); - zio_crypt_decode_mac_bp(&tmpbp, mac); - - if (should_bswap) - byteswap_uint64_array(&tmpbp, sizeof (blkptr_t)); - - SHA2Update(ctx, &tmpbp.blk_prop, sizeof (uint64_t)); - SHA2Update(ctx, mac, ZIO_DATA_MAC_LEN); + zio_crypt_bp_auth_init(version, should_bswap, bp, &bab, &bab_len); + SHA2Update(ctx, &bab, bab_len); } static void -zio_crypt_bp_do_aad_updates(uint8_t **aadp, uint_t *aad_len, +zio_crypt_bp_do_aad_updates(uint8_t **aadp, uint_t *aad_len, uint64_t version, boolean_t should_bswap, blkptr_t *bp) { - uint_t crypt_len; - blkptr_t tmpbp = *bp; - uint8_t mac[ZIO_DATA_MAC_LEN]; - - if (should_bswap) - byteswap_uint64_array(&tmpbp, sizeof (blkptr_t)); - - ASSERT(BP_USES_CRYPT(&tmpbp) || BP_IS_HOLE(&tmpbp)); - ASSERT0(BP_IS_EMBEDDED(&tmpbp)); - zio_crypt_bp_zero_nonportable_blkprop(&tmpbp); - zio_crypt_decode_mac_bp(&tmpbp, mac); - - if (should_bswap) - byteswap_uint64_array(&tmpbp, sizeof (blkptr_t)); + uint_t bab_len; + blkptr_auth_buf_t bab; - crypt_len = sizeof (uint64_t); - bcopy(&tmpbp.blk_prop, *aadp, crypt_len); - *aadp += crypt_len; - *aad_len += crypt_len; - - crypt_len = ZIO_DATA_MAC_LEN; - bcopy(mac, *aadp, crypt_len); - *aadp += crypt_len; - *aad_len += crypt_len; + zio_crypt_bp_auth_init(version, should_bswap, bp, &bab, &bab_len); + bcopy(&bab, *aadp, bab_len); + *aadp += bab_len; + *aad_len += bab_len; } static int -zio_crypt_do_dnode_hmac_updates(crypto_context_t ctx, boolean_t should_bswap, - dnode_phys_t *dnp) +zio_crypt_do_dnode_hmac_updates(crypto_context_t ctx, uint64_t version, + boolean_t should_bswap, dnode_phys_t *dnp) { int ret, i; dnode_phys_t *adnp; @@ -992,14 +1074,14 @@ zio_crypt_do_dnode_hmac_updates(crypto_context_t ctx, boolean_t should_bswap, } for (i = 0; i < dnp->dn_nblkptr; i++) { - ret = zio_crypt_bp_do_hmac_updates(ctx, + ret = zio_crypt_bp_do_hmac_updates(ctx, version, should_bswap, &dnp->dn_blkptr[i]); if (ret != 0) goto error; } if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) { - ret = zio_crypt_bp_do_hmac_updates(ctx, + ret = zio_crypt_bp_do_hmac_updates(ctx, version, should_bswap, DN_SPILL_BLKPTR(dnp)); if (ret != 0) goto error; @@ -1095,8 +1177,8 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen, } /* add in fields from the metadnode */ - ret = zio_crypt_do_dnode_hmac_updates(ctx, should_bswap, - &osp->os_meta_dnode); + ret = zio_crypt_do_dnode_hmac_updates(ctx, key->zk_version, + should_bswap, &osp->os_meta_dnode); if (ret) goto error; @@ -1149,13 +1231,13 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen, } /* add in fields from the user accounting dnodes */ - ret = zio_crypt_do_dnode_hmac_updates(ctx, should_bswap, - &osp->os_userused_dnode); + ret = zio_crypt_do_dnode_hmac_updates(ctx, key->zk_version, + should_bswap, &osp->os_userused_dnode); if (ret) goto error; - ret = zio_crypt_do_dnode_hmac_updates(ctx, should_bswap, - &osp->os_groupused_dnode); + ret = zio_crypt_do_dnode_hmac_updates(ctx, key->zk_version, + should_bswap, &osp->os_groupused_dnode); if (ret) goto error; @@ -1194,9 +1276,9 @@ zio_crypt_destroy_uio(uio_t *uio) * checksum, and psize bits. For an explanation of the purpose of this, see * the comment block on object set authentication. */ -int -zio_crypt_do_indirect_mac_checksum(boolean_t generate, void *buf, - uint_t datalen, boolean_t byteswap, uint8_t *cksum) +static int +zio_crypt_do_indirect_mac_checksum_impl(boolean_t generate, void *buf, + uint_t datalen, uint64_t version, boolean_t byteswap, uint8_t *cksum) { blkptr_t *bp; int i, epb = datalen >> SPA_BLKPTRSHIFT; @@ -1206,7 +1288,8 @@ zio_crypt_do_indirect_mac_checksum(boolean_t generate, void *buf, /* checksum all of the MACs from the layer below */ SHA2Init(SHA512, &ctx); for (i = 0, bp = buf; i < epb; i++, bp++) { - zio_crypt_bp_do_indrect_checksum_updates(&ctx, byteswap, bp); + zio_crypt_bp_do_indrect_checksum_updates(&ctx, version, + byteswap, bp); } SHA2Final(digestbuf, &ctx); @@ -1222,10 +1305,34 @@ zio_crypt_do_indirect_mac_checksum(boolean_t generate, void *buf, } int -zio_crypt_do_indirect_mac_checksum_abd(boolean_t generate, abd_t *abd, +zio_crypt_do_indirect_mac_checksum(boolean_t generate, void *buf, uint_t datalen, boolean_t byteswap, uint8_t *cksum) { + int ret; + /* + * Unfortunately, callers of this function will not always have + * easy access to the on-disk format version. This info is + * normally found in the DSL Crypto Key, but the checksum-of-MACs + * is expected to be verifiable even when the key isn't loaded. + * Here, instead of doing a ZAP lookup for the version for each + * zio, we simply try both existing formats. + */ + ret = zio_crypt_do_indirect_mac_checksum_impl(generate, buf, + datalen, ZIO_CRYPT_KEY_CURRENT_VERSION, byteswap, cksum); + if (ret == ECKSUM) { + ASSERT(!generate); + ret = zio_crypt_do_indirect_mac_checksum_impl(generate, + buf, datalen, 0, byteswap, cksum); + } + + return (ret); +} + +int +zio_crypt_do_indirect_mac_checksum_abd(boolean_t generate, abd_t *abd, + uint_t datalen, boolean_t byteswap, uint8_t *cksum) +{ int ret; void *buf; @@ -1439,10 +1546,10 @@ zio_crypt_init_uios_zil(boolean_t encrypt, uint8_t *plainbuf, * Special case handling routine for encrypting / decrypting dnode blocks. */ static int -zio_crypt_init_uios_dnode(boolean_t encrypt, uint8_t *plainbuf, - uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, uio_t *puio, - uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, uint_t *auth_len, - boolean_t *no_crypt) +zio_crypt_init_uios_dnode(boolean_t encrypt, uint64_t version, + uint8_t *plainbuf, uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, + uio_t *puio, uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, + uint_t *auth_len, boolean_t *no_crypt) { int ret; uint_t nr_src, nr_dst, crypt_len; @@ -1544,12 +1651,12 @@ zio_crypt_init_uios_dnode(boolean_t encrypt, uint8_t *plainbuf, for (j = 0; j < dnp->dn_nblkptr; j++) { zio_crypt_bp_do_aad_updates(&aadp, &aad_len, - byteswap, &dnp->dn_blkptr[j]); + version, byteswap, &dnp->dn_blkptr[j]); } if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) { zio_crypt_bp_do_aad_updates(&aadp, &aad_len, - byteswap, DN_SPILL_BLKPTR(dnp)); + version, byteswap, DN_SPILL_BLKPTR(dnp)); } /* @@ -1682,9 +1789,9 @@ zio_crypt_init_uios_normal(boolean_t encrypt, uint8_t *plainbuf, * data (AAD) for the encryption modes. */ static int -zio_crypt_init_uios(boolean_t encrypt, dmu_object_type_t ot, uint8_t *plainbuf, - uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, uint8_t *mac, - uio_t *puio, uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, +zio_crypt_init_uios(boolean_t encrypt, uint64_t version, dmu_object_type_t ot, + uint8_t *plainbuf, uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, + uint8_t *mac, uio_t *puio, uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, uint_t *auth_len, boolean_t *no_crypt) { int ret; @@ -1700,9 +1807,9 @@ zio_crypt_init_uios(boolean_t encrypt, dmu_object_type_t ot, uint8_t *plainbuf, no_crypt); break; case DMU_OT_DNODE: - ret = zio_crypt_init_uios_dnode(encrypt, plainbuf, cipherbuf, - datalen, byteswap, puio, cuio, enc_len, authbuf, auth_len, - no_crypt); + ret = zio_crypt_init_uios_dnode(encrypt, version, plainbuf, + cipherbuf, datalen, byteswap, puio, cuio, enc_len, authbuf, + auth_len, no_crypt); break; default: ret = zio_crypt_init_uios_normal(encrypt, plainbuf, cipherbuf, @@ -1754,9 +1861,9 @@ zio_do_crypt_data(boolean_t encrypt, zio_crypt_key_t *key, uint8_t *salt, bzero(&cuio, sizeof (uio_t)); /* create uios for encryption */ - ret = zio_crypt_init_uios(encrypt, ot, plainbuf, cipherbuf, datalen, - byteswap, mac, &puio, &cuio, &enc_len, &authbuf, &auth_len, - no_crypt); + ret = zio_crypt_init_uios(encrypt, key->zk_version, ot, plainbuf, + cipherbuf, datalen, byteswap, mac, &puio, &cuio, &enc_len, + &authbuf, &auth_len, no_crypt); if (ret != 0) return (ret); diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 6ea822467b61..572018d7524b 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -1406,7 +1406,12 @@ zvol_open(struct block_device *bdev, fmode_t flag) goto out_mutex; } - if ((flag & FMODE_WRITE) && (zv->zv_flags & ZVOL_RDONLY)) { + /* + * Check for a bad on-disk format version now since we + * lied about owning the dataset readonly before. + */ + if ((flag & FMODE_WRITE) && ((zv->zv_flags & ZVOL_RDONLY) || + dmu_objset_incompatible_encryption_version(zv->zv_objset))) { error = -EROFS; goto out_open_count; } diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index af96e6a64eb9..fd3781f23c1e 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -332,7 +332,8 @@ tests = ['zpool_import_001_pos', 'zpool_import_002_pos', 'zpool_import_features_003_pos','zpool_import_missing_001_pos', 'zpool_import_missing_002_pos', 'zpool_import_rename_001_pos', 'zpool_import_all_001_pos', - 'zpool_import_encrypted', 'zpool_import_encrypted_load'] + 'zpool_import_encrypted', 'zpool_import_encrypted_load', + 'zpool_import_errata3'] tags = ['functional', 'cli_root', 'zpool_import'] [tests/functional/cli_root/zpool_labelclear] @@ -650,7 +651,8 @@ tests = ['rsend_001_pos', 'rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos', 'send-c_lz4_disabled', 'send-c_recv_lz4_disabled', 'send-c_mixed_compression', 'send-c_stream_size_estimate', 'send-cD', 'send-c_embedded_blocks', 'send-c_resume', 'send-cpL_varied_recsize', - 'send-c_recv_dedup', 'send_encrypted_heirarchy', 'send_freeobjects'] + 'send-c_recv_dedup', 'send_encrypted_files', 'send_encrypted_heirarchy', + 'send_freeobjects'] tags = ['functional', 'rsend'] [tests/functional/scrub_mirror] diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am index fab6e7459ffe..687646f05e78 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am @@ -26,10 +26,12 @@ dist_pkgdata_SCRIPTS = \ zpool_import_missing_003_pos.ksh \ zpool_import_rename_001_pos.ksh \ zpool_import_encrypted.ksh \ - zpool_import_encrypted_load.ksh + zpool_import_encrypted_load.ksh \ + zpool_import_errata3.ksh BLOCKFILES = \ - unclean_export.dat.bz2 + unclean_export.dat.bz2 \ + cryptv0.dat.bz2 dist_pkgdata_DATA = $(BLOCKFILES) EXTRA_DIST = $(BLOCKFILES) diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_import/cryptv0.dat.bz2 b/tests/zfs-tests/tests/functional/cli_root/zpool_import/cryptv0.dat.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..1c625c2c447bcaa7d126a5f98a3e8a50102a6adb GIT binary patch literal 94716 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 literal 0 HcmV?d00001 diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata3.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata3.ksh new file mode 100755 index 000000000000..67e4caee8776 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata3.ksh @@ -0,0 +1,99 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2017 Datto, Inc. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# 'zpool import' should import a pool with Errata #3 while preventing +# the user from performing read write operations +# +# STRATEGY: +# 1. Import a pre-packaged pool with Errata #3 +# 2. Attempt to write to the effected datasets +# 3. Attempt to read from the effected datasets +# 4. Attempt to perform a raw send of the effected datasets +# 5. Perform a regular send of the datasets under a new encryption root +# 6. Verify the new datasets can be read from and written to +# 7. Destroy the old effected datasets +# 8. Reimport the pool and verify that the errata is no longer present +# + +verify_runnable "global" + +POOL_NAME=cryptv0 +POOL_FILE=cryptv0.dat + +function uncompress_pool +{ + log_note "Creating pool from $POOL_FILE" + log_must bzcat \ + $STF_SUITE/tests/functional/cli_root/zpool_import/$POOL_FILE.bz2 \ + > /$TESTPOOL/$POOL_FILE + return 0 +} + +function cleanup +{ + poolexists $POOL_NAME && log_must zpool destroy $POOL_NAME + [[ -e /$TESTPOOL/$POOL_FILE ]] && rm /$TESTPOOL/$POOL_FILE + return 0 +} +log_onexit cleanup + +log_assert "Verify that Errata 3 is properly handled" + +uncompress_pool +log_must zpool import -d /$TESTPOOL/ $POOL_NAME +log_must eval "zpool status | grep -q Errata" +log_must eval "echo 'password' | zfs load-key $POOL_NAME/testfs" +log_must eval "echo 'password' | zfs load-key $POOL_NAME/testvol" + +log_mustnot zfs mount $POOL_NAME/testfs +log_must zfs mount -o ro $POOL_NAME/testfs + +old_mntpnt=$(get_prop mountpoint $POOL_NAME/testfs) +log_must eval "ls $old_mntpnt | grep -q testfile" +block_device_wait +log_mustnot dd if=/dev/zero of=/dev/zvol/$POOL_NAME/testvol bs=512 count=1 +log_must dd if=/dev/zvol/$POOL_NAME/testvol of=/dev/null bs=512 count=1 +log_must eval "echo 'password' | zfs create \ + -o encryption=on -o keyformat=passphrase -o keylocation=prompt \ + cryptv0/encroot" +log_mustnot eval "zfs send -w $POOL_NAME/testfs@snap1 | \ + zfs recv $POOL_NAME/encroot/testfs" +log_mustnot eval "zfs send -w $POOL_NAME/testvol@snap1 | \ + zfs recv $POOL_NAME/encroot/testvol" + +log_must eval "zfs send $POOL_NAME/testfs@snap1 | \ + zfs recv $POOL_NAME/encroot/testfs" +log_must eval "zfs send $POOL_NAME/testvol@snap1 | \ + zfs recv $POOL_NAME/encroot/testvol" +block_device_wait +log_must dd if=/dev/zero of=/dev/zvol/$POOL_NAME/encroot/testvol bs=512 count=1 +new_mntpnt=$(get_prop mountpoint $POOL_NAME/encroot/testfs) +log_must eval "ls $new_mntpnt | grep -q testfile" +log_must zfs destroy -r $POOL_NAME/testfs +log_must zfs destroy -r $POOL_NAME/testvol + +log_must zpool export $POOL_NAME +log_must zpool import -d /$TESTPOOL/ $POOL_NAME +log_mustnot eval "zpool status | grep -q Errata" +log_pass "Errata 3 is properly handled" diff --git a/tests/zfs-tests/tests/functional/rsend/Makefile.am b/tests/zfs-tests/tests/functional/rsend/Makefile.am index 8833d1d760fe..6598b1c3db7e 100644 --- a/tests/zfs-tests/tests/functional/rsend/Makefile.am +++ b/tests/zfs-tests/tests/functional/rsend/Makefile.am @@ -23,6 +23,7 @@ dist_pkgdata_SCRIPTS = \ rsend_021_pos.ksh \ rsend_022_pos.ksh \ rsend_024_pos.ksh \ + send_encrypted_files.ksh \ send_encrypted_heirarchy.ksh \ send-cD.ksh \ send-c_embedded_blocks.ksh \ diff --git a/tests/zfs-tests/tests/functional/rsend/send_encrypted_files.ksh b/tests/zfs-tests/tests/functional/rsend/send_encrypted_files.ksh new file mode 100644 index 000000000000..20f3788d561a --- /dev/null +++ b/tests/zfs-tests/tests/functional/rsend/send_encrypted_files.ksh @@ -0,0 +1,101 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2017 by Datto Inc. All rights reserved. +# + +. $STF_SUITE/tests/functional/rsend/rsend.kshlib + +# +# DESCRIPTION: +# +# +# STRATEGY: +# 1. Create a new encrypted filesystem +# 2. Add an empty file to the filesystem +# 3. Add a small 512 byte file to the filesystem +# 4. Add a larger 32M file to the filesystem +# 5. Add a large sparse file to the filesystem +# 6. Add a file truncated to 4M to the filesystem +# 7. Add a sparse file with metadata compression disabled to the filesystem +# 8. Add and remove 1000 empty files to the filesystem +# 9. Snapshot the filesystem +# 10. Send and receive the filesystem, ensuring that it can be mounted +# + +verify_runnable "both" + +function set_metadata_compression_disabled # <0|1> +{ + echo $1 > /sys/module/zfs/parameters/zfs_mdcomp_disable +} + +function cleanup +{ + datasetexists $TESTPOOL/$TESTFS2 && \ + log_must zfs destroy -r $TESTPOOL/$TESTFS2 + datasetexists $TESTPOOL/recv && \ + log_must zfs destroy -r $TESTPOOL/recv + [[ -f $keyfile ]] && log_must rm $keyfile + [[ -f $sendfile ]] && log_must rm $sendfile +} +log_onexit cleanup + +log_assert "Verify 'zfs send -w' works with many different file layouts" + +typeset keyfile=/$TESTPOOL/pkey +typeset sendfile=/$TESTPOOL/sendfile + +log_must eval "echo 'password' > $keyfile" +log_must zfs create -o encryption=on -o keyformat=passphrase \ + -o keylocation=file://$keyfile $TESTPOOL/$TESTFS2 + +log_must touch /$TESTPOOL/$TESTFS2/empty +log_must mkfile 512 /$TESTPOOL/$TESTFS2/small +log_must mkfile 32M /$TESTPOOL/$TESTFS2/full +log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS2/sparse \ + bs=512 count=1 seek=10G >/dev/null 2>&1 +log_must mkfile 32M /$TESTPOOL/$TESTFS2/truncated +log_must truncate -s 4M /$TESTPOOL/$TESTFS2/truncated +sync + +log_must set_metadata_compression_disabled 1 +log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS2/no_mdcomp \ + count=1 bs=512 seek=10G >/dev/null 2>&1 +sync +log_must set_metadata_compression_disabled 0 + +log_must mkdir -p /$TESTPOOL/$TESTFS2/dir +for i in {1..1000}; do + log_must mkfile 512 /$TESTPOOL/$TESTFS2/dir/file-$i +done +sync + +for i in {1..1000}; do + log_must rm /$TESTPOOL/$TESTFS2/dir/file-$i +done +sync + +log_must zfs snapshot $TESTPOOL/$TESTFS2@now +log_must eval "zfs send -wR $TESTPOOL/$TESTFS2@now > $sendfile" + +log_must eval "zfs recv -F $TESTPOOL/recv < $sendfile" +log_must zfs load-key $TESTPOOL/recv + +log_must zfs mount -a + +log_pass "Verified 'zfs send -w' works with many different file layouts" From ef130d07f89583c8f2810ad4a1c25e3cc28a7a9a Mon Sep 17 00:00:00 2001 From: Tom Caputi Date: Mon, 4 Dec 2017 14:10:31 -0500 Subject: [PATCH 2/5] Fix for #6916 When performing zil_claim() at pool import time, it is important that encrypted datasets set os_next_write_raw before writing to the zil_header_t. This prevents the code from attempting to re-authenticate the objset_phys_t when it writes it out, which is unnecessary because the zil_header_t is not protected by either objset MAC and impossible since the keys aren't loaded yet. Unfortunately, one of the code paths did not set this flag, which causes failed ASSERTs during 'zpool import -F'. This patch corrects this issue. Signed-off-by: Tom Caputi --- module/zfs/zil.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/zfs/zil.c b/module/zfs/zil.c index 81bc6de412e0..4e0f308957dc 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -819,6 +819,8 @@ zil_claim(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg) if (zilog->zl_parse_lr_count || zilog->zl_parse_blk_count > 1) zh->zh_flags |= ZIL_REPLAY_NEEDED; zh->zh_flags |= ZIL_CLAIM_LR_SEQ_VALID; + if (os->os_encrypted) + os->os_next_write_raw = B_TRUE; dsl_dataset_dirty(dmu_objset_ds(os), tx); } From 735fafde162683eb6e34d7b39943fc582152c1dc Mon Sep 17 00:00:00 2001 From: Tom Caputi Date: Fri, 19 Jan 2018 04:19:47 -0500 Subject: [PATCH 3/5] Raw sends must be able to decrease nlevels Currently, when a raw zfs send file includes a DRR_OBJECT record that would decrease the number of levels of an existing object, the object is reallocated with dmu_object_reclaim() which creates the new dnode using the old object's nlevels. For non-raw sends this doesn't really matter, but raw sends require that nlevels on the receive side match that of the send side so that the checksum-of-MAC tree can be properly maintained. This patch corrects the issue by freeing the object completely before allocating it again in this case. This patch also corrects several issues with dnode_hold_impl() and related functions that prevented dnodes (particularly multi-slot dnodes) from being reallocated properly due to the fact that existing dnodes were not being fully cleaned up when they were freed. Fixes #6821 Signed-off-by: Tom Caputi Signed-off-by: Brian Behlendorf --- cmd/ztest/ztest.c | 25 +++++++++++- include/sys/dnode.h | 6 +++ module/zfs/dmu_object.c | 1 - module/zfs/dmu_send.c | 84 ++++++++++++++++++++++++++++++++++++++--- module/zfs/dnode.c | 84 ++++++++++++++++++++++++++++++++++++++--- module/zfs/dnode_sync.c | 2 + 6 files changed, 188 insertions(+), 14 deletions(-) diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index a8b5418b60b2..8a21bf3781c8 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -200,7 +200,8 @@ extern uint64_t metaslab_df_alloc_threshold; extern unsigned long zfs_deadman_synctime_ms; extern int metaslab_preload_limit; extern boolean_t zfs_compressed_arc_enabled; -extern int zfs_abd_scatter_enabled; +extern int zfs_abd_scatter_enabled; +extern int dmu_object_alloc_chunk_shift; static ztest_shared_opts_t *ztest_shared_opts; static ztest_shared_opts_t ztest_opts; @@ -314,6 +315,7 @@ static ztest_shared_callstate_t *ztest_shared_callstate; ztest_func_t ztest_dmu_read_write; ztest_func_t ztest_dmu_write_parallel; ztest_func_t ztest_dmu_object_alloc_free; +ztest_func_t ztest_dmu_object_next_chunk; ztest_func_t ztest_dmu_commit_callbacks; ztest_func_t ztest_zap; ztest_func_t ztest_zap_parallel; @@ -361,6 +363,7 @@ ztest_info_t ztest_info[] = { ZTI_INIT(ztest_dmu_read_write, 1, &zopt_always), ZTI_INIT(ztest_dmu_write_parallel, 10, &zopt_always), ZTI_INIT(ztest_dmu_object_alloc_free, 1, &zopt_always), + ZTI_INIT(ztest_dmu_object_next_chunk, 1, &zopt_sometimes), ZTI_INIT(ztest_dmu_commit_callbacks, 1, &zopt_always), ZTI_INIT(ztest_zap, 30, &zopt_always), ZTI_INIT(ztest_zap_parallel, 100, &zopt_always), @@ -4055,6 +4058,26 @@ ztest_dmu_object_alloc_free(ztest_ds_t *zd, uint64_t id) umem_free(od, size); } +/* + * Rewind the global allocator to verify object allocation backfilling. + */ +void +ztest_dmu_object_next_chunk(ztest_ds_t *zd, uint64_t id) +{ + objset_t *os = zd->zd_os; + int dnodes_per_chunk = 1 << dmu_object_alloc_chunk_shift; + uint64_t object; + + /* + * Rewind the global allocator randomly back to a lower object number + * to force backfilling and reclamation of recently freed dnodes. + */ + mutex_enter(&os->os_obj_lock); + object = ztest_random(os->os_obj_next_chunk); + os->os_obj_next_chunk = P2ALIGN(object, dnodes_per_chunk); + mutex_exit(&os->os_obj_lock); +} + #undef OD_ARRAY_SIZE #define OD_ARRAY_SIZE 2 diff --git a/include/sys/dnode.h b/include/sys/dnode.h index a2bef9d2c77b..691fd443a260 100644 --- a/include/sys/dnode.h +++ b/include/sys/dnode.h @@ -424,6 +424,7 @@ int dnode_next_offset(dnode_t *dn, int flags, uint64_t *off, int minlvl, uint64_t blkfill, uint64_t txg); void dnode_evict_dbufs(dnode_t *dn); void dnode_evict_bonus(dnode_t *dn); +void dnode_free_interior_slots(dnode_t *dn); #define DNODE_IS_CACHEABLE(_dn) \ ((_dn)->dn_objset->os_primary_cache == ZFS_CACHE_ALL || \ @@ -517,6 +518,11 @@ typedef struct dnode_stats { * which had already been unlinked in an earlier txg. */ kstat_named_t dnode_hold_free_txg; + /* + * Number of times dnode_free_interior_slots() needed to retry + * acquiring a slot zrl lock due to contention. + */ + kstat_named_t dnode_free_interior_lock_retry; /* * Number of new dnodes allocated by dnode_allocate(). */ diff --git a/module/zfs/dmu_object.c b/module/zfs/dmu_object.c index e7412b7509f4..f53da407fd40 100644 --- a/module/zfs/dmu_object.c +++ b/module/zfs/dmu_object.c @@ -275,7 +275,6 @@ dmu_object_reclaim_dnsize(objset_t *os, uint64_t object, dmu_object_type_t ot, return (err); } - int dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx) { diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 63a4f98bfd15..2c2ed8fb3191 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -2455,10 +2455,8 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro, } err = dmu_object_info(rwa->os, drro->drr_object, &doi); - - if (err != 0 && err != ENOENT) + if (err != 0 && err != ENOENT && err != EEXIST) return (SET_ERROR(EINVAL)); - object = err == 0 ? drro->drr_object : DMU_NEW_OBJECT; if (drro->drr_object > rwa->max_object) rwa->max_object = drro->drr_object; @@ -2476,6 +2474,8 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro, int nblkptr = deduce_nblkptr(drro->drr_bonustype, drro->drr_bonuslen); + object = drro->drr_object; + /* nblkptr will be bounded by the bonus size and type */ if (rwa->raw && nblkptr != drro->drr_nblkptr) return (SET_ERROR(EINVAL)); @@ -2484,18 +2484,89 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro, (drro->drr_blksz != doi.doi_data_block_size || nblkptr < doi.doi_nblkptr || indblksz != doi.doi_metadata_block_size || - drro->drr_nlevels < doi.doi_indirection)) { + drro->drr_nlevels < doi.doi_indirection || + drro->drr_dn_slots != doi.doi_dnodesize >> DNODE_SHIFT)) { err = dmu_free_long_range_raw(rwa->os, drro->drr_object, 0, DMU_OBJECT_END); if (err != 0) return (SET_ERROR(EINVAL)); } else if (drro->drr_blksz != doi.doi_data_block_size || - nblkptr < doi.doi_nblkptr) { + nblkptr < doi.doi_nblkptr || + drro->drr_dn_slots != doi.doi_dnodesize >> DNODE_SHIFT) { err = dmu_free_long_range(rwa->os, drro->drr_object, 0, DMU_OBJECT_END); if (err != 0) return (SET_ERROR(EINVAL)); } + + /* + * The dmu does not currently support decreasing nlevels + * on an object. For non-raw sends, this does not matter + * and the new object can just use the previous one's nlevels. + * For raw sends, however, the structure of the received dnode + * (including nlevels) must match that of the send side. + * Therefore, instead of using dmu_object_reclaim(), we must + * free the object completely and call dmu_object_claim_dnsize() + * instead. + */ + if ((rwa->raw && drro->drr_nlevels < doi.doi_indirection) || + drro->drr_dn_slots != doi.doi_dnodesize >> DNODE_SHIFT) { + if (rwa->raw) { + err = dmu_free_long_object_raw(rwa->os, + drro->drr_object); + } else { + err = dmu_free_long_object(rwa->os, + drro->drr_object); + } + if (err != 0) + return (SET_ERROR(EINVAL)); + + txg_wait_synced(dmu_objset_pool(rwa->os), 0); + object = DMU_NEW_OBJECT; + } + } else if (err == EEXIST) { + /* + * The object requested is currently an interior slot of a + * multi-slot dnode. This will be resolved when the next txg + * is synced out, since the send stream will have told us + * to free this slot when we freed the associated dnode + * earlier in the stream. + */ + txg_wait_synced(dmu_objset_pool(rwa->os), 0); + object = drro->drr_object; + } else { + /* object is free and we are about to allocate a new one */ + object = DMU_NEW_OBJECT; + } + + /* + * If this is a multi-slot dnode there is a chance that this + * object will expand into a slot that is already used by + * another object from the previous snapshot. We must free + * these objects before we attempt to allocate the new dnode. + */ + if (drro->drr_dn_slots > 1) { + for (uint64_t slot = drro->drr_object + 1; + slot < drro->drr_object + drro->drr_dn_slots; + slot++) { + dmu_object_info_t slot_doi; + + err = dmu_object_info(rwa->os, slot, &slot_doi); + if (err == ENOENT || err == EEXIST) + continue; + else if (err != 0) + return (err); + + if (rwa->raw) + err = dmu_free_long_object_raw(rwa->os, slot); + else + err = dmu_free_long_object(rwa->os, slot); + + if (err != 0) + return (err); + } + + txg_wait_synced(dmu_objset_pool(rwa->os), 0); } tx = dmu_tx_create(rwa->os); @@ -2849,6 +2920,7 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs, dmu_tx_abort(tx); return (err); } + if (rwa->raw) { VERIFY0(dmu_object_dirty_raw(rwa->os, drrs->drr_object, tx)); dmu_buf_will_change_crypt_params(db_spill, tx); @@ -3199,7 +3271,7 @@ receive_read_record(struct receive_arg *ra) * See receive_read_prefetch for an explanation why we're * storing this object in the ignore_obj_list. */ - if (err == ENOENT || + if (err == ENOENT || err == EEXIST || (err == 0 && doi.doi_data_block_size != drro->drr_blksz)) { objlist_insert(&ra->ignore_objlist, drro->drr_object); err = 0; diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c index 544e736d8600..b4c131e98323 100644 --- a/module/zfs/dnode.c +++ b/module/zfs/dnode.c @@ -55,6 +55,7 @@ dnode_stats_t dnode_stats = { { "dnode_hold_free_overflow", KSTAT_DATA_UINT64 }, { "dnode_hold_free_refcount", KSTAT_DATA_UINT64 }, { "dnode_hold_free_txg", KSTAT_DATA_UINT64 }, + { "dnode_free_interior_lock_retry", KSTAT_DATA_UINT64 }, { "dnode_allocate", KSTAT_DATA_UINT64 }, { "dnode_reallocate", KSTAT_DATA_UINT64 }, { "dnode_buf_evict", KSTAT_DATA_UINT64 }, @@ -518,7 +519,8 @@ dnode_destroy(dnode_t *dn) mutex_exit(&os->os_lock); /* the dnode can no longer move, so we can release the handle */ - zrl_remove(&dn->dn_handle->dnh_zrlock); + if (!zrl_is_locked(&dn->dn_handle->dnh_zrlock)) + zrl_remove(&dn->dn_handle->dnh_zrlock); dn->dn_allocated_txg = 0; dn->dn_free_txg = 0; @@ -665,6 +667,8 @@ dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(dn->dn_objset)))); dn_slots = dn_slots > 0 ? dn_slots : DNODE_MIN_SLOTS; + + dnode_free_interior_slots(dn); DNODE_STAT_BUMP(dnode_reallocate); /* clean up any unreferenced dbufs */ @@ -1067,19 +1071,73 @@ dnode_set_slots(dnode_children_t *children, int idx, int slots, void *ptr) } static boolean_t -dnode_check_slots(dnode_children_t *children, int idx, int slots, void *ptr) +dnode_check_slots_free(dnode_children_t *children, int idx, int slots) { ASSERT3S(idx + slots, <=, DNODES_PER_BLOCK); for (int i = idx; i < idx + slots; i++) { dnode_handle_t *dnh = &children->dnc_children[i]; - if (dnh->dnh_dnode != ptr) + dnode_t *dn = dnh->dnh_dnode; + + if (dn == DN_SLOT_FREE) { + continue; + } else if (DN_SLOT_IS_PTR(dn)) { + mutex_enter(&dn->dn_mtx); + dmu_object_type_t type = dn->dn_type; + mutex_exit(&dn->dn_mtx); + + if (type != DMU_OT_NONE) + return (B_FALSE); + + continue; + } else { return (B_FALSE); + } + + return (B_FALSE); } return (B_TRUE); } +static void +dnode_reclaim_slots(dnode_children_t *children, int idx, int slots) +{ + ASSERT3S(idx + slots, <=, DNODES_PER_BLOCK); + + for (int i = idx; i < idx + slots; i++) { + dnode_handle_t *dnh = &children->dnc_children[i]; + + ASSERT(zrl_is_locked(&dnh->dnh_zrlock)); + + if (DN_SLOT_IS_PTR(dnh->dnh_dnode)) { + ASSERT3S(dnh->dnh_dnode->dn_type, ==, DMU_OT_NONE); + dnode_destroy(dnh->dnh_dnode); + dnh->dnh_dnode = DN_SLOT_FREE; + } + } +} + +void +dnode_free_interior_slots(dnode_t *dn) +{ + dnode_children_t *children = dmu_buf_get_user(&dn->dn_dbuf->db); + int epb = dn->dn_dbuf->db.db_size >> DNODE_SHIFT; + int idx = (dn->dn_object & (epb - 1)) + 1; + int slots = dn->dn_num_slots - 1; + + if (slots == 0) + return; + + ASSERT3S(idx + slots, <=, DNODES_PER_BLOCK); + + while (!dnode_slots_tryenter(children, idx, slots)) + DNODE_STAT_BUMP(dnode_free_interior_lock_retry); + + dnode_set_slots(children, idx, slots, DN_SLOT_FREE); + dnode_slots_rele(children, idx, slots); +} + void dnode_special_close(dnode_handle_t *dnh) { @@ -1377,7 +1435,7 @@ dnode_hold_impl(objset_t *os, uint64_t object, int flag, int slots, while (dn == DN_SLOT_UNINIT) { dnode_slots_hold(dnc, idx, slots); - if (!dnode_check_slots(dnc, idx, slots, DN_SLOT_FREE)) { + if (!dnode_check_slots_free(dnc, idx, slots)) { DNODE_STAT_BUMP(dnode_hold_free_misses); dnode_slots_rele(dnc, idx, slots); dbuf_rele(db, FTAG); @@ -1390,15 +1448,29 @@ dnode_hold_impl(objset_t *os, uint64_t object, int flag, int slots, continue; } - if (!dnode_check_slots(dnc, idx, slots, DN_SLOT_FREE)) { + if (!dnode_check_slots_free(dnc, idx, slots)) { DNODE_STAT_BUMP(dnode_hold_free_lock_misses); dnode_slots_rele(dnc, idx, slots); dbuf_rele(db, FTAG); return (SET_ERROR(ENOSPC)); } + /* + * Allocated but otherwise free dnodes which would + * be in the interior of a multi-slot dnodes need + * to be freed. Single slot dnodes can be safely + * re-purposed as a performance optimization. + */ + if (slots > 1) + dnode_reclaim_slots(dnc, idx + 1, slots - 1); + dnh = &dnc->dnc_children[idx]; - dn = dnode_create(os, dn_block + idx, db, object, dnh); + if (DN_SLOT_IS_PTR(dnh->dnh_dnode)) { + dn = dnh->dnh_dnode; + } else { + dn = dnode_create(os, dn_block + idx, db, + object, dnh); + } } mutex_enter(&dn->dn_mtx); diff --git a/module/zfs/dnode_sync.c b/module/zfs/dnode_sync.c index 09437993a89b..7d3850a5f82a 100644 --- a/module/zfs/dnode_sync.c +++ b/module/zfs/dnode_sync.c @@ -529,6 +529,7 @@ dnode_sync_free(dnode_t *dn, dmu_tx_t *tx) if (dn->dn_allocated_txg != dn->dn_free_txg) dmu_buf_will_dirty(&dn->dn_dbuf->db, tx); bzero(dn->dn_phys, sizeof (dnode_phys_t) * dn->dn_num_slots); + dnode_free_interior_slots(dn); mutex_enter(&dn->dn_mtx); dn->dn_type = DMU_OT_NONE; @@ -536,6 +537,7 @@ dnode_sync_free(dnode_t *dn, dmu_tx_t *tx) dn->dn_allocated_txg = 0; dn->dn_free_txg = 0; dn->dn_have_spill = B_FALSE; + dn->dn_num_slots = 1; mutex_exit(&dn->dn_mtx); ASSERT(dn->dn_object != DMU_META_DNODE_OBJECT); From 852911da52f12e81021f12ca075a6d4c53e0e7cd Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Mon, 11 Dec 2017 17:20:48 -0500 Subject: [PATCH 4/5] Add 'zfs recv' dnode reallocation test cases This patch adds a test to make sure that zfs recv functions properly with incremental streams containing dnodes of different sizes. Reviewed-by: Tom Caputi Signed-off-by: Brian Behlendorf --- tests/runfiles/linux.run | 2 +- .../tests/functional/rsend/Makefile.am | 3 +- .../rsend/send_realloc_dnode_size.ksh | 98 +++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100755 tests/zfs-tests/tests/functional/rsend/send_realloc_dnode_size.ksh diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index fd3781f23c1e..ca8e0bf3195f 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -652,7 +652,7 @@ tests = ['rsend_001_pos', 'rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos', 'send-c_mixed_compression', 'send-c_stream_size_estimate', 'send-cD', 'send-c_embedded_blocks', 'send-c_resume', 'send-cpL_varied_recsize', 'send-c_recv_dedup', 'send_encrypted_files', 'send_encrypted_heirarchy', - 'send_freeobjects'] + 'send_freeobjects', 'send_realloc_dnode_size'] tags = ['functional', 'rsend'] [tests/functional/scrub_mirror] diff --git a/tests/zfs-tests/tests/functional/rsend/Makefile.am b/tests/zfs-tests/tests/functional/rsend/Makefile.am index 6598b1c3db7e..7a8b8a33a474 100644 --- a/tests/zfs-tests/tests/functional/rsend/Makefile.am +++ b/tests/zfs-tests/tests/functional/rsend/Makefile.am @@ -40,4 +40,5 @@ dist_pkgdata_SCRIPTS = \ send-c_volume.ksh \ send-c_zstreamdump.ksh \ send-cpL_varied_recsize.ksh \ - send_freeobjects.ksh + send_freeobjects.ksh \ + send_realloc_dnode_size.ksh diff --git a/tests/zfs-tests/tests/functional/rsend/send_realloc_dnode_size.ksh b/tests/zfs-tests/tests/functional/rsend/send_realloc_dnode_size.ksh new file mode 100755 index 000000000000..206763949e8d --- /dev/null +++ b/tests/zfs-tests/tests/functional/rsend/send_realloc_dnode_size.ksh @@ -0,0 +1,98 @@ +#!/bin/ksh + +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017 by Lawrence Livermore National Security, LLC. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/rsend/rsend.kshlib + +# +# Description: +# Verify incremental receive properly handles objects with changed +# dnode slot count. +# +# Strategy: +# 1. Populate a dataset with 1k byte dnodes and snapshot +# 2. Remove objects, set dnodesize=legacy, and remount dataset so new objects +# get recycled numbers and formerly "interior" dnode slots get assigned +# to new objects +# 3. Remove objects, set dnodesize=2k, and remount dataset so new objects +# overlap with recently recycled and formerly "normal" dnode slots get +# assigned to new objects +# 4. Generate initial and incremental streams +# 5. Verify initial and incremental streams can be received +# + +verify_runnable "both" + +log_assert "Verify incremental receive handles objects with changed dnode size" + +function cleanup +{ + rm -f $BACKDIR/fs-dn-legacy + rm -f $BACKDIR/fs-dn-1k + rm -f $BACKDIR/fs-dn-2k + + if datasetexists $POOL/fs ; then + log_must zfs destroy -rR $POOL/fs + fi + + if datasetexists $POOL/newfs ; then + log_must zfs destroy -rR $POOL/newfs + fi +} + +log_onexit cleanup + +# 1. Populate a dataset with 1k byte dnodes and snapshot +log_must zfs create -o dnodesize=1k $POOL/fs +log_must mk_files 200 262144 0 $POOL/fs +log_must zfs snapshot $POOL/fs@a + +# 2. Remove objects, set dnodesize=legacy, and remount dataset so new objects +# get recycled numbers and formerly "interior" dnode slots get assigned +# to new objects +rm /$POOL/fs/* + +log_must zfs unmount $POOL/fs +log_must zfs set dnodesize=legacy $POOL/fs +log_must zfs mount $POOL/fs + +log_must mk_files 200 262144 0 $POOL/fs +log_must zfs snapshot $POOL/fs@b + +# 3. Remove objects, set dnodesize=2k, and remount dataset so new objects +# overlap with recently recycled and formerly "normal" dnode slots get +# assigned to new objects +rm /$POOL/fs/* + +log_must zfs unmount $POOL/fs +log_must zfs set dnodesize=2k $POOL/fs +log_must zfs mount $POOL/fs + +mk_files 200 262144 0 $POOL/fs +log_must zfs snapshot $POOL/fs@c + +# 4. Generate initial and incremental streams +log_must eval "zfs send $POOL/fs@a > $BACKDIR/fs-dn-1k" +log_must eval "zfs send -i $POOL/fs@a $POOL/fs@b > $BACKDIR/fs-dn-legacy" +log_must eval "zfs send -i $POOL/fs@b $POOL/fs@c > $BACKDIR/fs-dn-2k" + +# 5. Verify initial and incremental streams can be received +log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-1k" +log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-legacy" +log_must eval "zfs recv $POOL/newfs < $BACKDIR/fs-dn-2k" + +log_pass "Verify incremental receive handles objects with changed dnode size" From 193a718dbed8987d880463bc4aba725f87bb8b65 Mon Sep 17 00:00:00 2001 From: Tom Caputi Date: Thu, 1 Feb 2018 15:37:24 -0500 Subject: [PATCH 5/5] Change os->os_next_write_raw to work per txg Currently, os_next_write_raw is a single boolean used for determining whether or not the next call to dmu_objset_sync() should write out the objset_phys_t as a raw buffer. Since the boolean is not associated with a txg, the work simply happens during the next txg, which is not necessarily the correct one. In the current implementation this issue was misdiagnosed, resulting in a small hack in dmu_objset_sync() which seemed to resolve the problem. This patch changes os_next_write_raw to be an array of booleans, one for each txg in TXG_OFF and removes the hack. Signed-off-by: Tom Caputi --- include/sys/dmu_objset.h | 2 +- module/zfs/dbuf.c | 1 + module/zfs/dmu_objset.c | 4 ++-- module/zfs/dsl_crypt.c | 2 +- module/zfs/dsl_dataset.c | 2 +- module/zfs/zil.c | 4 ++-- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h index f3013ad13d2d..7ee992f3116e 100644 --- a/include/sys/dmu_objset.h +++ b/include/sys/dmu_objset.h @@ -127,7 +127,7 @@ struct objset { boolean_t os_rescan_dnodes; /* os_phys_buf should be written raw next txg */ - boolean_t os_next_write_raw; + boolean_t os_next_write_raw[TXG_SIZE]; /* Protected by os_obj_lock */ kmutex_t os_obj_lock; diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index 517a284de2be..e805681ce2a8 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -2067,6 +2067,7 @@ dmu_buf_will_change_crypt_params(dmu_buf_t *db_fake, dmu_tx_t *tx) ASSERT3P(dr, !=, NULL); ASSERT3U(dr->dr_txg, ==, tx->tx_txg); dr->dt.dl.dr_raw = B_TRUE; + db->db_objset->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE; } #pragma weak dmu_buf_fill_done = dbuf_fill_done diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index 2b069b6ced02..befce9be6bc8 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -1508,9 +1508,9 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) * the os_phys_buf raw. Neither of these actions will effect the MAC * at this point. */ - if (arc_is_unauthenticated(os->os_phys_buf) || os->os_next_write_raw) { + if (os->os_next_write_raw[tx->tx_txg & TXG_MASK]) { ASSERT(os->os_encrypted); - os->os_next_write_raw = B_FALSE; + os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_FALSE; arc_convert_to_raw(os->os_phys_buf, os->os_dsl_dataset->ds_object, ZFS_HOST_BYTEORDER, DMU_OT_OBJSET, NULL, NULL, NULL); diff --git a/module/zfs/dsl_crypt.c b/module/zfs/dsl_crypt.c index cb13d2cdca6d..6a63d54cadb3 100644 --- a/module/zfs/dsl_crypt.c +++ b/module/zfs/dsl_crypt.c @@ -2177,7 +2177,7 @@ dsl_crypto_recv_key_sync(void *arg, dmu_tx_t *tx) arc_release(os->os_phys_buf, &os->os_phys_buf); bcopy(portable_mac, os->os_phys->os_portable_mac, ZIO_OBJSET_MAC_LEN); bzero(os->os_phys->os_local_mac, ZIO_OBJSET_MAC_LEN); - os->os_next_write_raw = B_TRUE; + os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE; /* set metadnode compression and checksum */ mdn->dn_compress = compress; diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 36ceaf17583f..3c329f20783e 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -941,7 +941,7 @@ dsl_dataset_zero_zil(dsl_dataset_t *ds, dmu_tx_t *tx) bzero(&os->os_zil_header, sizeof (os->os_zil_header)); if (os->os_encrypted) - os->os_next_write_raw = B_TRUE; + os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE; zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); dsl_dataset_sync(ds, zio, tx); diff --git a/module/zfs/zil.c b/module/zfs/zil.c index 4e0f308957dc..2efe2f0d84fc 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -796,7 +796,7 @@ zil_claim(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg) zio_free_zil(zilog->zl_spa, first_txg, &zh->zh_log); BP_ZERO(&zh->zh_log); if (os->os_encrypted) - os->os_next_write_raw = B_TRUE; + os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE; dsl_dataset_dirty(dmu_objset_ds(os), tx); dmu_objset_disown(os, B_FALSE, FTAG); return (0); @@ -820,7 +820,7 @@ zil_claim(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg) zh->zh_flags |= ZIL_REPLAY_NEEDED; zh->zh_flags |= ZIL_CLAIM_LR_SEQ_VALID; if (os->os_encrypted) - os->os_next_write_raw = B_TRUE; + os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE; dsl_dataset_dirty(dmu_objset_ds(os), tx); }