diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c index 761bd0301d13..f612950ee8e3 100644 --- a/usr/src/cmd/zfs/zfs_main.c +++ b/usr/src/cmd/zfs/zfs_main.c @@ -3737,11 +3737,12 @@ zfs_do_send(int argc, char **argv) {"embed", no_argument, NULL, 'e'}, {"resume", required_argument, NULL, 't'}, {"compressed", no_argument, NULL, 'c'}, + {"raw", no_argument, NULL, 'w'}, {0, 0, 0, 0} }; /* check options */ - while ((c = getopt_long(argc, argv, ":i:I:RbDpvnPLet:cr", long_options, + while ((c = getopt_long(argc, argv, ":i:I:RbDpvnPLet:cw", long_options, NULL)) != -1) { switch (c) { case 'i': @@ -3789,8 +3790,11 @@ zfs_do_send(int argc, char **argv) case 'c': flags.compress = B_TRUE; break; - case 'r': + case 'w': flags.raw = B_TRUE; + flags.compress = B_TRUE; + flags.embed_data = B_TRUE; + flags.largeblock = B_TRUE; break; case ':': /* @@ -3860,12 +3864,6 @@ zfs_do_send(int argc, char **argv) } } - if (flags.raw && flags.compress) { - (void) fprintf(stderr, - gettext("raw and compress flags are mutually exclusive\n")); - return (1); - } - if (!flags.dryrun && isatty(STDOUT_FILENO)) { (void) fprintf(stderr, gettext("Error: Stream can not be written to a terminal.\n" diff --git a/usr/src/cmd/zstreamdump/zstreamdump.c b/usr/src/cmd/zstreamdump/zstreamdump.c index 566e6141704a..49da0045931b 100644 --- a/usr/src/cmd/zstreamdump/zstreamdump.c +++ b/usr/src/cmd/zstreamdump/zstreamdump.c @@ -196,11 +196,31 @@ print_block(char *buf, int length) } } +/* + * Print an array of bytes to stdout as hexidecimal characters. str must + * have buf_len * 2 + 1 bytes of space. + */ +static void +sprintf_bytes(char *str, uint8_t *buf, uint_t buf_len) +{ + int i, n; + + for (i = 0; i < buf_len; i++) { + n = sprintf(str, "%02x", buf[i] & 0xff); + str += n; + } + + str[0] = '\0'; +} + int main(int argc, char *argv[]) { char *buf = safe_malloc(SPA_MAXBLOCKSIZE); uint64_t drr_record_count[DRR_NUMTYPES] = { 0 }; + char salt[ZIO_DATA_SALT_LEN * 2 + 1]; + char iv[ZIO_DATA_IV_LEN * 2 + 1]; + char mac[ZIO_DATA_MAC_LEN * 2 + 1]; uint64_t total_records = 0; uint64_t payload_size; dmu_replay_record_t thedrr; @@ -424,14 +444,19 @@ main(int argc, char *argv[]) if (verbose) { (void) printf("OBJECT object = %llu type = %u " "bonustype = %u blksz = %u bonuslen = %u " - "raw_bonuslen = %u flags = %u\n", + "raw_bonuslen = %u flags = %u " + "indblkshift = %u nlevels = %u " + "nblkptr = %u\n", (u_longlong_t)drro->drr_object, drro->drr_type, drro->drr_bonustype, drro->drr_blksz, drro->drr_bonuslen, drro->drr_raw_bonuslen, - drro->drr_flags); + drro->drr_flags, + drro->drr_indblkshift, + drro->drr_nlevels, + drro->drr_nblkptr); } if (drro->drr_bonuslen > 0) { (void) ssread(buf, payload_size, &zc); @@ -477,13 +502,20 @@ main(int argc, char *argv[]) * print info on the modified block */ if (verbose) { + sprintf_bytes(salt, drrw->drr_salt, + ZIO_DATA_SALT_LEN); + sprintf_bytes(iv, drrw->drr_iv, + ZIO_DATA_IV_LEN); + sprintf_bytes(mac, drrw->drr_mac, + ZIO_DATA_MAC_LEN); + (void) printf("WRITE object = %llu type = %u " "checksum type = %u compression type = %u\n" " flags = %u offset = %llu " "logical_size = %llu " "compressed_size = %llu " - "payload_size = %llu " - "props = %llx\n", + "payload_size = %llu props = %llx " + "salt = %s iv = %s mac = %s\n", (u_longlong_t)drrw->drr_object, drrw->drr_type, drrw->drr_checksumtype, @@ -493,7 +525,10 @@ main(int argc, char *argv[]) (u_longlong_t)drrw->drr_logical_size, (u_longlong_t)drrw->drr_compressed_size, (u_longlong_t)payload_size, - (u_longlong_t)drrw->drr_key.ddk_prop); + (u_longlong_t)drrw->drr_key.ddk_prop, + salt, + iv, + mac); } /* @@ -564,12 +599,31 @@ main(int argc, char *argv[]) if (do_byteswap) { drrs->drr_object = BSWAP_64(drrs->drr_object); drrs->drr_length = BSWAP_64(drrs->drr_length); + drrs->drr_compressed_size = + BSWAP_64(drrs->drr_compressed_size); drrs->drr_type = BSWAP_32(drrs->drr_type); } if (verbose) { + sprintf_bytes(salt, drrs->drr_salt, + ZIO_DATA_SALT_LEN); + sprintf_bytes(iv, drrs->drr_iv, + ZIO_DATA_IV_LEN); + sprintf_bytes(mac, drrs->drr_mac, + ZIO_DATA_MAC_LEN); + (void) printf("SPILL block for object = %llu " - "length = %llu\n", drrs->drr_object, - drrs->drr_length); + "length = %llu flags = %u " + "compression type = %u " + "compressed_size = %llu " + "salt = %s iv = %s mac = %s\n", + (u_longlong_t)drrs->drr_object, + (u_longlong_t)drrs->drr_length, + drrs->drr_flags, + drrs->drr_compressiontype, + (u_longlong_t)drrs->drr_compressed_size, + salt, + iv, + mac); } (void) ssread(buf, drrs->drr_length, &zc); if (dump) { @@ -618,10 +672,14 @@ main(int argc, char *argv[]) } if (verbose) { (void) printf("OBJECT_RANGE firstobj = %llu " - "numslots = %llu flags = %u\n", + "numslots = %llu flags = %u " + "salt = %s iv = %s mac = %s\n", (u_longlong_t)drror->drr_firstobj, (u_longlong_t)drror->drr_numslots, - drror->drr_flags); + drror->drr_flags, + salt, + iv, + mac); } break; } diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index de751c9aaf96..8d3204cd92cb 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -632,7 +632,7 @@ typedef struct sendflags { /* compressed WRITE records are permitted */ boolean_t compress; - /* raw WRITE records are permitted, mutually exclusive with compress */ + /* raw encrypted records are permitted */ boolean_t raw; } sendflags_t; diff --git a/usr/src/lib/libzfs/common/libzfs_sendrecv.c b/usr/src/lib/libzfs/common/libzfs_sendrecv.c index 19e8843b3f73..77156cb24e21 100644 --- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c +++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c @@ -3367,7 +3367,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, char *snapname = NULL; nvlist_t *props = NULL; char tmp_keylocation[MAXNAMELEN]; - + begin_time = time(NULL); bzero(tmp_keylocation, MAXNAMELEN); @@ -3397,11 +3397,11 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, * the keylocation for now to avoid any errors from the receive * ioctl. */ - err = nvlist_lookup_string(rcvprops, + err = nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation); if (err == 0) { - strcpy(tmp_keylocation, keylocation); - (void) nvlist_remove_all(rcvprops, + (void) strcpy(tmp_keylocation, keylocation); + (void) nvlist_remove_all(props, zfs_prop_to_name(ZFS_PROP_KEYLOCATION)); } @@ -3984,7 +3984,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, } if (tmp_keylocation[0] != '\0') { - VERIFY(0 == nvlist_add_string(rcvprops, + VERIFY(0 == nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_KEYLOCATION), tmp_keylocation)); } diff --git a/usr/src/man/man1m/zfs.1m b/usr/src/man/man1m/zfs.1m index 96acd0e775d4..398e20791ae8 100644 --- a/usr/src/man/man1m/zfs.1m +++ b/usr/src/man/man1m/zfs.1m @@ -165,7 +165,7 @@ .Ar snapshot bookmark .Nm .Cm send -.Op Fl DLPRcenprv +.Op Fl DLPRcenpvw .Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot .Ar snapshot .Nm @@ -2642,7 +2642,7 @@ feature. .It Xo .Nm .Cm send -.Op Fl DLPRcenprv +.Op Fl DLPRcenpvw .Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot .Ar snapshot .Xc @@ -2775,7 +2775,7 @@ and the verbose output goes to standard error Include the dataset's properties in the stream. This flag is implicit when .Fl R is specified. The receiving system must also support this feature. -.It Fl r, -raw +.It Fl w, -raw For encrypted datasets send data exactly as it exists on disk. This allows backups to be taken even if encryption keys are not currently loaded. The backup may then be received on an untrusted machine since that machine will @@ -2787,7 +2787,7 @@ property will be defaulted to .Sy prompt if not otherwise provided. For unencrypted datasets, this flag will be equivalent to -.Fl c . +.Fl Lec . Note that if you do not use this flag for sending encrypted datasets, data will be sent unencrypted and may be re-encrypted with a different encryption key on the receiving system, which will disable the ability @@ -2880,7 +2880,7 @@ property will be defaulted to .Sy prompt if not otherwise provided. For unencrypted datasets, this flag will be equivalent to -.Fl c . +.Fl Lec . Note that if you do not use this flag for sending encrypted datasets, data will be sent unencrypted and may be re-encrypted with a different encryption key on the receiving system, which will disable the ability diff --git a/usr/src/pkg/manifests/system-test-zfstest.mf b/usr/src/pkg/manifests/system-test-zfstest.mf index b3a4d502fefc..20e4a7c9f5ba 100644 --- a/usr/src/pkg/manifests/system-test-zfstest.mf +++ b/usr/src/pkg/manifests/system-test-zfstest.mf @@ -905,6 +905,9 @@ file path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos \ mode=0555 file path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted \ mode=0555 +file \ + path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted_unloaded \ + mode=0555 file path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw \ mode=0555 file path=opt/zfs-tests/tests/functional/cli_root/zfs_set/cache_001_pos \ @@ -2193,8 +2196,6 @@ file path=opt/zfs-tests/tests/functional/rsend/rsend_020_pos mode=0555 file path=opt/zfs-tests/tests/functional/rsend/rsend_021_pos mode=0555 file path=opt/zfs-tests/tests/functional/rsend/rsend_022_pos mode=0555 file path=opt/zfs-tests/tests/functional/rsend/rsend_024_pos mode=0555 -file path=opt/zfs-tests/tests/functional/rsend/send_encrypted_heirarchy \ - mode=0555 file path=opt/zfs-tests/tests/functional/rsend/send-cD mode=0555 file path=opt/zfs-tests/tests/functional/rsend/send-c_embedded_blocks \ mode=0555 @@ -2216,6 +2217,8 @@ file path=opt/zfs-tests/tests/functional/rsend/send-c_volume mode=0555 file path=opt/zfs-tests/tests/functional/rsend/send-c_zstreamdump mode=0555 file path=opt/zfs-tests/tests/functional/rsend/send-cpL_varied_recsize \ mode=0555 +file path=opt/zfs-tests/tests/functional/rsend/send_encrypted_heirarchy \ + mode=0555 file path=opt/zfs-tests/tests/functional/rsend/setup mode=0555 file path=opt/zfs-tests/tests/functional/scrub_mirror/cleanup mode=0555 file path=opt/zfs-tests/tests/functional/scrub_mirror/default.cfg mode=0444 diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_encryptionroot.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_encryptionroot.ksh new file mode 100644 index 000000000000..336c7b2538bc --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_encryptionroot.ksh @@ -0,0 +1,80 @@ +#!/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 +. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib + +# +# DESCRIPTION: +# ZFS must promote clones of an encryption root. +# +# STRATEGY: +# 1. Create an encrypted dataset +# 2. Clone the encryption root +# 3. Clone the clone +# 4. Verify the encryption root of all three datasets is the origin +# 5. Promote the clone of the clone +# 6. Verify the encryption root of all three datasets is still the origin +# 7. Promote the clone of the original encryption root +# 8. Verify the encryption root of all three datasets is the promoted dataset +# + +verify_runnable "both" + +function cleanup +{ + datasetexists $TESTPOOL/$TESTFS1 && \ + log_must zfs destroy -Rf $TESTPOOL/$TESTFS1 + datasetexists $TESTPOOL/clone1 && \ + log_must zfs destroy -Rf $TESTPOOL/clone1 + datasetexists $TESTPOOL/clone2 && \ + log_must zfs destroy -Rf $TESTPOOL/clone2 +} +log_onexit cleanup + +log_assert "ZFS must promote clones of an encryption root" + +passphrase="password" +snaproot="$TESTPOOL/$TESTFS1@snap1" +snapclone="$TESTPOOL/clone1@snap2" + +log_must eval "echo $passphrase | zfs create -o encryption=on" \ + "-o keyformat=passphrase $TESTPOOL/$TESTFS1" + +log_must zfs snap $snaproot +log_must zfs clone $snaproot $TESTPOOL/clone1 +log_must zfs snap $snapclone +log_must zfs clone $snapclone $TESTPOOL/clone2 + +log_must verify_encryption_root $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1 +log_must verify_encryption_root $TESTPOOL/clone1 $TESTPOOL/$TESTFS1 +log_must verify_encryption_root $TESTPOOL/clone2 $TESTPOOL/$TESTFS1 + +log_must zfs promote $TESTPOOL/clone2 +log_must verify_encryption_root $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1 +log_must verify_encryption_root $TESTPOOL/clone1 $TESTPOOL/$TESTFS1 +log_must verify_encryption_root $TESTPOOL/clone2 $TESTPOOL/$TESTFS1 + +log_must zfs promote $TESTPOOL/clone2 +log_must verify_encryption_root $TESTPOOL/$TESTFS1 $TESTPOOL/clone2 +log_must verify_encryption_root $TESTPOOL/clone1 $TESTPOOL/clone2 +log_must verify_encryption_root $TESTPOOL/clone2 $TESTPOOL/clone2 + +log_pass "ZFS promotes clones of an encryption root" diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh index 5c9c26a32e25..2042b37a98f7 100644 --- a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh +++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh @@ -66,7 +66,7 @@ typeset checksum=$(md5sum /$TESTPOOL/$TESTFS1/$TESTFILE0 | \ log_must zfs snapshot $snap log_note "Verify ZFS can receive a raw send stream from an encrypted dataset" -log_must eval "zfs send -r $snap | zfs receive $TESTPOOL/$TESTFS2" +log_must eval "zfs send -w $snap | zfs receive $TESTPOOL/$TESTFS2" keystatus=$(get_prop keystatus $TESTPOOL/$TESTFS2) [[ "$keystatus" == "unavailable" ]] || \ @@ -78,7 +78,7 @@ typeset cksum1=$(md5sum /$TESTPOOL/$TESTFS2/$TESTFILE0 | awk '{ print $1 }') [[ "$cksum1" == "$checksum" ]] || \ log_fail "Checksums differ ($cksum1 != $checksum)" -log_must eval "zfs send -r $snap | zfs receive $TESTPOOL/$TESTFS1/c1" +log_must eval "zfs send -w $snap | zfs receive $TESTPOOL/$TESTFS1/c1" keystatus=$(get_prop keystatus $TESTPOOL/$TESTFS1/c1) [[ "$keystatus" == "unavailable" ]] || \ diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_incremental.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_incremental.ksh index 30efe38e9b28..c813809a0b5e 100644 --- a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_incremental.ksh +++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_incremental.ksh @@ -64,8 +64,8 @@ typeset checksum=$(md5sum /$TESTPOOL/$TESTFS1/$TESTFILE0 | awk '{ print $1 }') log_must zfs snapshot $snap2 -log_must eval "zfs send -r $snap1 | zfs receive $TESTPOOL/$TESTFS2" -log_must eval "zfs send -r -i $snap1 $snap2 | zfs receive $TESTPOOL/$TESTFS2" +log_must eval "zfs send -w $snap1 | zfs receive $TESTPOOL/$TESTFS2" +log_must eval "zfs send -w -i $snap1 $snap2 | zfs receive $TESTPOOL/$TESTFS2" log_must eval "echo $passphrase | zfs mount -l $TESTPOOL/$TESTFS2" typeset cksum1=$(md5sum /$TESTPOOL/$TESTFS2/$TESTFILE0 | awk '{ print $1 }') diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh index 34406644871b..85cc7407e1a1 100644 --- a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh +++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw.ksh @@ -59,21 +59,21 @@ log_must eval "echo $passphrase | zfs create -o encryption=on" \ log_must zfs snapshot $snap log_must zfs snapshot $snap1 -log_must eval "zfs send -r $snap > /dev/null" -log_must eval "zfs send -r $snap1 > /dev/null" +log_must eval "zfs send -w $snap > /dev/null" +log_must eval "zfs send -w $snap1 > /dev/null" log_note "Verify ZFS can perform raw sends with properties" -log_must eval "zfs send -rp $snap > /dev/null" -log_must eval "zfs send -rp $snap1 > /dev/null" +log_must eval "zfs send -wp $snap > /dev/null" +log_must eval "zfs send -wp $snap1 > /dev/null" log_note "Verify ZFS can perform raw replication sends" -log_must eval "zfs send -rR $snap > /dev/null" -log_must eval "zfs send -rR $snap1 > /dev/null" +log_must eval "zfs send -wR $snap > /dev/null" +log_must eval "zfs send -wR $snap1 > /dev/null" log_note "Verify ZFS can perform a raw send of an encrypted datasets with" \ "its key unloaded" log_must zfs unmount $TESTPOOL/$TESTFS1 log_must zfs unload-key $TESTPOOL/$TESTFS1 -log_must eval "zfs send -r $snap1 > /dev/null" +log_must eval "zfs send -w $snap1 > /dev/null" log_pass "ZFS performs raw sends of datasets" diff --git a/usr/src/test/zfs-tests/tests/functional/rsend/send_encrypted_heirarchy.ksh b/usr/src/test/zfs-tests/tests/functional/rsend/send_encrypted_heirarchy.ksh new file mode 100644 index 000000000000..5e19a6b6c073 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/rsend/send_encrypted_heirarchy.ksh @@ -0,0 +1,96 @@ +#!/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 +. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib + +# +# DESCRIPTION: +# Raw recursive sends preserve filesystem structure. +# +# STRATEGY: +# 1. Create an encrypted filesystem with a clone and a child +# 2. Snapshot and send the filesystem tree +# 3. Verify that the filesystem structure was correctly received +# 4. Change the child to an encryption root and promote the clone +# 5. Snapshot and send the filesystem tree again +# 6. Verify that the new structure is received correctly +# + +verify_runnable "both" + +function cleanup +{ + log_must cleanup_pool $POOL + log_must cleanup_pool $POOL2 + log_must setup_test_model $POOL +} + +log_assert "Raw recursive sends preserve filesystem structure." +log_onexit cleanup + +# Create the filesystem heirarchy +log_must cleanup_pool $POOL +log_must eval "echo $PASSPHRASE | zfs create -o encryption=on" \ + "-o keyformat=passphrase $POOL/$FS" +log_must zfs snapshot $POOL/$FS@snap +log_must zfs clone $POOL/$FS@snap $POOL/clone +log_must zfs create $POOL/$FS/child + +# Back up the tree and verify the structure +log_must zfs snapshot -r $POOL@before +log_must eval "zfs send -wR $POOL@before > $BACKDIR/fs-before-R" +log_must eval "zfs receive -d -F $POOL2 < $BACKDIR/fs-before-R" +dstds=$(get_dst_ds $POOL/$FS $POOL2) +log_must cmp_ds_subs $POOL/$FS $dstds + +log_must verify_encryption_root $POOL/$FS $POOL/$FS +log_must verify_keylocation $POOL/$FS "prompt" +log_must verify_origin $POOL/$FS "-" + +log_must verify_encryption_root $POOL/clone $POOL/$FS +log_must verify_keylocation $POOL/clone "none" +log_must verify_origin $POOL/clone "$POOL/$FS@snap" + +log_must verify_encryption_root $POOL/$FS/child $POOL/$FS +log_must verify_keylocation $POOL/$FS/child "none" + +# Alter the heirarchy and re-send +log_must eval "echo $PASSPHRASE1 | zfs change-key -o keyformat=passphrase" \ + "$POOL/$FS/child" +log_must zfs promote $POOL/clone +log_must zfs snapshot -r $POOL@after +log_must eval "zfs send -wR -i $POOL@before $POOL@after >" \ + "$BACKDIR/fs-after-R" +log_must eval "zfs receive -d -F $POOL2 < $BACKDIR/fs-after-R" +log_must cmp_ds_subs $POOL/$FS $dstds + +log_must verify_encryption_root $POOL/$FS $POOL/clone +log_must verify_keylocation $POOL/$FS "none" +log_must verify_origin $POOL/$FS "$POOL/clone@snap" + +log_must verify_encryption_root $POOL/clone $POOL/clone +log_must verify_keylocation $POOL/clone "prompt" +log_must verify_origin $POOL/clone "-" + +log_must verify_encryption_root $POOL/$FS/child $POOL/$FS/child +log_must verify_keylocation $POOL/$FS/child "prompt" + +log_pass "Raw recursive sends preserve filesystem structure." diff --git a/usr/src/uts/common/crypto/core/kcf_prov_lib.c b/usr/src/uts/common/crypto/core/kcf_prov_lib.c index 59f7ea1e70da..785d07cedf39 100644 --- a/usr/src/uts/common/crypto/core/kcf_prov_lib.c +++ b/usr/src/uts/common/crypto/core/kcf_prov_lib.c @@ -63,7 +63,7 @@ crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd, offset -= uiop->uio_iov[vec_idx++].iov_len) ; - if (vec_idx == uiop->uio_iovcnt) { + if (vec_idx == uiop->uio_iovcnt && length > 0) { /* * The caller specified an offset that is larger than * the total size of the buffers it provided. diff --git a/usr/src/uts/common/fs/zfs/dmu_objset.c b/usr/src/uts/common/fs/zfs/dmu_objset.c index 8fc9ae22f6e5..334dd09a43c4 100644 --- a/usr/src/uts/common/fs/zfs/dmu_objset.c +++ b/usr/src/uts/common/fs/zfs/dmu_objset.c @@ -53,6 +53,7 @@ #include #include #include +#include /* * Needed to close a window in dnode_move() that allows the objset to be freed @@ -656,8 +657,6 @@ dmu_objset_own(const char *name, dmu_objset_type_t type, } dsl_pool_rele(dp, FTAG); - /* we were able to own the dataset, so we shouldnt be receiving */ - ASSERT0((*osp)->os_receiving); return (0); } @@ -928,7 +927,7 @@ dmu_objset_create_impl_dnstats(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, * encrypted receive. */ if (dmu_objset_userused_enabled(os) && - (!os->os_encrypted || !os->os_receiving)) { + (!os->os_encrypted || !dmu_objset_is_receiving(os))) { os->os_phys->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE; os->os_flags = os->os_phys->os_flags; } @@ -1392,7 +1391,7 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx) txgoff = tx->tx_txg & TXG_MASK; if (dmu_objset_userused_enabled(os) && - (!os->os_encrypted || !os->os_receiving)) { + (!os->os_encrypted || !dmu_objset_is_receiving(os))) { /* * We must create the list here because it uses the * dn_dirty_link[] of this txg. But it may already @@ -1630,7 +1629,7 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx) return; /* if this is a raw receive just return and handle accounting later */ - if (os->os_encrypted && os->os_receiving) + if (os->os_encrypted && dmu_objset_is_receiving(os)) return; /* Allocate the user/groupused objects if necessary. */ @@ -1721,7 +1720,7 @@ dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx) * so that an incremental raw receive may be done on top of an * existing non-raw receive. */ - if (os->os_encrypted && os->os_receiving) + if (os->os_encrypted && dmu_objset_is_receiving(os)) return; if (before && (flags & (DN_ID_CHKED_BONUS|DN_ID_OLD_EXIST| diff --git a/usr/src/uts/common/fs/zfs/dmu_send.c b/usr/src/uts/common/fs/zfs/dmu_send.c index cceb61762d74..56895b2eb9ff 100644 --- a/usr/src/uts/common/fs/zfs/dmu_send.c +++ b/usr/src/uts/common/fs/zfs/dmu_send.c @@ -545,10 +545,12 @@ dump_object_range(dmu_sendarg_t *dsp, const blkptr_t *bp, uint64_t firstobj, struct drr_object_range *drror = &(dsp->dsa_drr->drr_u.drr_object_range); - /* we only use this for raw sends */ + /* we only use this record type for raw sends */ ASSERT(BP_IS_PROTECTED(bp)); ASSERT(dsp->dsa_featureflags & DMU_BACKUP_FEATURE_RAW); ASSERT3U(BP_GET_COMPRESS(bp), ==, ZIO_COMPRESS_OFF); + ASSERT3U(BP_GET_TYPE(bp), ==, DMU_OT_DNODE); + ASSERT0(BP_GET_LEVEL(bp)); if (dsp->dsa_pending_op != PENDING_NONE) { if (dump_record(dsp, NULL, 0) != 0) @@ -790,6 +792,14 @@ do_dump(dmu_sendarg_t *dsa, struct send_block_record *data) */ boolean_t split_large_blocks = blksz > SPA_OLD_MAXBLOCKSIZE && !(dsa->dsa_featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS); + + /* + * Raw sends require that we always get raw data as it exists + * on disk, so we assert that we are not splitting blocks here. + */ + boolean_t request_raw = + (dsa->dsa_featureflags & DMU_BACKUP_FEATURE_RAW) != 0; + /* * We should only request compressed data from the ARC if all * the following are true: @@ -805,15 +815,6 @@ do_dump(dmu_sendarg_t *dsa, struct send_block_record *data) !split_large_blocks && !BP_SHOULD_BYTESWAP(bp) && !BP_IS_EMBEDDED(bp) && !DMU_OT_IS_METADATA(BP_GET_TYPE(bp)); - /* - * Raw sends only apply to protected blocks. Raw sends are - * mutually exclusive with splitting large blocks and - * compressed sends, so we assert that here. - */ - boolean_t request_raw = - (dsa->dsa_featureflags & DMU_BACKUP_FEATURE_RAW) != 0; - - IMPLY(request_raw, !request_compressed); IMPLY(request_raw, !split_large_blocks); IMPLY(request_raw, BP_IS_PROTECTED(bp)); ASSERT0(zb->zb_level); @@ -829,10 +830,10 @@ do_dump(dmu_sendarg_t *dsa, struct send_block_record *data) ASSERT3U(blksz, ==, BP_GET_LSIZE(bp)); enum zio_flag zioflags = ZIO_FLAG_CANFAIL; - if (request_compressed) - zioflags |= ZIO_FLAG_RAW_COMPRESS; - else if (request_raw) + if (request_raw) zioflags |= ZIO_FLAG_RAW; + else if (request_compressed) + zioflags |= ZIO_FLAG_RAW_COMPRESS; if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ, zioflags, &aflags, zb) != 0) { @@ -907,8 +908,6 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds, uint64_t featureflags = 0; struct send_thread_arg to_arg = { 0 }; - ASSERT0(rawok && compressok); - err = dmu_objset_from_ds(to_ds, &os); if (err != 0) { dsl_pool_rele(dp, tag); @@ -957,22 +956,25 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds, if ((large_block_ok || rawok) && to_ds->ds_feature_inuse[SPA_FEATURE_LARGE_BLOCKS]) featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS; - if (embedok && + + /* encrypted datasets will not have embedded blocks */ + if ((embedok || rawok) && !os->os_encrypted && spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) { featureflags |= DMU_BACKUP_FEATURE_EMBED_DATA; if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) featureflags |= DMU_BACKUP_FEATURE_LZ4; } - if (compressok || (rawok && !os->os_encrypted)) { + /* raw send implies compressok */ + if (compressok || rawok) featureflags |= DMU_BACKUP_FEATURE_COMPRESSED; - } else if (rawok && os->os_encrypted) { + if (rawok && os->os_encrypted) featureflags |= DMU_BACKUP_FEATURE_RAW; - } if ((featureflags & - (DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_COMPRESSED)) != - 0 && spa_feature_is_active(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) { + (DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_COMPRESSED | + DMU_BACKUP_FEATURE_RAW)) != 0 && + spa_feature_is_active(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) { featureflags |= DMU_BACKUP_FEATURE_LZ4; } @@ -1564,11 +1566,6 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx) ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL)) return (SET_ERROR(EINVAL)); - /* Raw streams are mutually exclusive with compressed streams */ - if ((featureflags & DMU_BACKUP_FEATURE_COMPRESSED) && - (featureflags & DMU_BACKUP_FEATURE_RAW)) - return (SET_ERROR(EINVAL)); - /* Verify pool version supports SA if SA_SPILL feature set */ if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) && spa_version(dp->dp_spa) < SPA_VERSION_SA) @@ -1766,7 +1763,6 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx) } VERIFY0(dsl_dataset_own_obj(dp, dsobj, dsflags, dmu_recv_tag, &newds)); VERIFY0(dmu_objset_from_ds(newds, &os)); - os->os_receiving = B_TRUE; if (drba->drba_cookie->drc_resumable) { dsl_dataset_zapify(newds, tx); @@ -1857,11 +1853,6 @@ dmu_recv_resume_begin_check(void *arg, dmu_tx_t *tx) drrb->drr_type >= DMU_OST_NUMTYPES) return (SET_ERROR(EINVAL)); - /* Raw streams are mutually exclusive with compressed streams */ - if ((featureflags & DMU_BACKUP_FEATURE_COMPRESSED) && - (featureflags & DMU_BACKUP_FEATURE_RAW)) - return (SET_ERROR(EINVAL)); - /* Verify pool version supports SA if SA_SPILL feature set */ if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) && spa_version(dp->dp_spa) < SPA_VERSION_SA) @@ -1988,7 +1979,6 @@ dmu_recv_resume_begin_sync(void *arg, dmu_tx_t *tx) VERIFY0(dsl_dataset_own_obj(dp, dsobj, dsflags, dmu_recv_tag, &ds)); VERIFY0(dmu_objset_from_ds(ds, &os)); - os->os_receiving = B_TRUE; dmu_buf_will_dirty(ds->ds_dbuf, tx); dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT; @@ -2267,6 +2257,7 @@ byteswap_record(dmu_replay_record_t *drr) DO64(drr_spill.drr_object); DO64(drr_spill.drr_length); DO64(drr_spill.drr_toguid); + DO64(drr_spill.drr_compressed_size); DO32(drr_spill.drr_type); break; case DRR_OBJECT_RANGE: @@ -2785,7 +2776,7 @@ receive_object_range(struct receive_writer_arg *rwa, * match on the sending and receiving side. */ if (drror->drr_numslots != DNODES_PER_BLOCK || - drror->drr_numslots - drror->drr_firstobj != DNODES_PER_BLOCK || + P2PHASE(drror->drr_firstobj, DNODES_PER_BLOCK) != 0 || (drror->drr_flags & DRR_RAW_ENCRYPTED) == 0) return (SET_ERROR(EINVAL)); @@ -2818,12 +2809,15 @@ receive_object_range(struct receive_writer_arg *rwa, static void dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc) { - ds_hold_flags_t dsflags = DS_HOLD_FLAG_DECRYPT; + ds_hold_flags_t dsflags = (drc->drc_raw) ? 0 : DS_HOLD_FLAG_DECRYPT; - drc->drc_ds->ds_objset->os_receiving = B_FALSE; + /* + * Wait for our resume state to be written to disk or for us + * to finish user accounting before we say we are finished + * receiving the dataset. + */ + txg_wait_synced(drc->drc_ds->ds_dir->dd_pool, 0); if (drc->drc_resumable) { - /* wait for our resume state to be written to disk */ - txg_wait_synced(drc->drc_ds->ds_dir->dd_pool, 0); dsl_dataset_disown(drc->drc_ds, dsflags, dmu_recv_tag); } else { char name[ZFS_MAX_DATASET_NAME_LEN]; @@ -3599,7 +3593,6 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx) spa_history_log_internal_ds(drc->drc_ds, "finish receiving", tx, "snap=%s", drc->drc_tosnap); - drc->drc_ds->ds_objset->os_receiving = B_FALSE; if (!drc->drc_newfs) { dsl_dataset_t *origin_head; diff --git a/usr/src/uts/common/fs/zfs/dnode_sync.c b/usr/src/uts/common/fs/zfs/dnode_sync.c index 6089f47f012c..1c8b3a7bd99c 100644 --- a/usr/src/uts/common/fs/zfs/dnode_sync.c +++ b/usr/src/uts/common/fs/zfs/dnode_sync.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -561,10 +562,13 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx) ASSERT(dn->dn_dbuf == NULL || arc_released(dn->dn_dbuf->db_buf)); - /* do user accounting if it is enabled and this is not a raw recv */ + /* + * Do user accounting if it is enabled and this is not + * an encrypted receive. + */ if (dmu_objset_userused_enabled(os) && !DMU_OBJECT_IS_SPECIAL(dn->dn_object) && - (!os->os_encrypted || !os->os_receiving)) { + (!os->os_encrypted || !dmu_objset_is_receiving(os))) { mutex_enter(&dn->dn_mtx); dn->dn_oldused = DN_USED_BYTES(dn->dn_phys); dn->dn_oldflags = dn->dn_phys->dn_flags; diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index 271993fae04a..408785e04bdc 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -5536,7 +5536,8 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare) if (vd == NULL || unspare) { if (vd == NULL) vd = spa_lookup_by_guid(spa, guid, B_TRUE); - ev = spa_event_create(spa, vd, NULL, ESC_ZFS_VDEV_REMOVE_AUX); + ev = spa_event_create(spa, vd, NULL, + ESC_ZFS_VDEV_REMOVE_AUX); spa_vdev_remove_aux(spa->spa_spares.sav_config, ZPOOL_CONFIG_SPARES, spares, nspares, nv); spa_load_spares(spa); diff --git a/usr/src/uts/common/fs/zfs/sys/dmu_objset.h b/usr/src/uts/common/fs/zfs/sys/dmu_objset.h index 03afad6047f3..b42ef585665f 100644 --- a/usr/src/uts/common/fs/zfs/sys/dmu_objset.h +++ b/usr/src/uts/common/fs/zfs/sys/dmu_objset.h @@ -122,7 +122,6 @@ struct objset { uint64_t os_flags; uint64_t os_freed_dnodes; boolean_t os_rescan_dnodes; - boolean_t os_receiving; /* os is currently the target of a receive */ /* os_phys_buf should be written raw next txg */ boolean_t os_next_write_raw; diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h index bf1f8bb5675a..150b14fb75e2 100644 --- a/usr/src/uts/common/fs/zfs/sys/spa.h +++ b/usr/src/uts/common/fs/zfs/sys/spa.h @@ -381,7 +381,7 @@ _NOTE(CONSTCOND) } while (0) BF64_GET_SB((bp)->blk_prop, 25, 7, 0, 1)) #define BPE_SET_PSIZE(bp, x) do { \ ASSERT(BP_IS_EMBEDDED(bp)); \ - BF64_SET_SB((bp)->blk_prop, 25, 7, 0, 1, x); \ + BF64_SET_SB((bp)->blk_prop, 25, 7, 0, 1, x); \ _NOTE(CONSTCOND) } while (0) typedef enum bp_embedded_type { diff --git a/usr/src/uts/common/fs/zfs/zfs_fm.c b/usr/src/uts/common/fs/zfs/zfs_fm.c index 53d30b8d044d..a8a12f471ac0 100644 --- a/usr/src/uts/common/fs/zfs/zfs_fm.c +++ b/usr/src/uts/common/fs/zfs/zfs_fm.c @@ -663,7 +663,8 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info, void zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, - struct zbookmark_phys *zb, zio_t *zio, uint64_t stateoroffset, uint64_t size) + struct zbookmark_phys *zb, zio_t *zio, uint64_t stateoroffset, + uint64_t size) { #ifdef _KERNEL nvlist_t *ereport = NULL; diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c index 0a27b3484a05..fac1fd93fdd6 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c @@ -4486,9 +4486,6 @@ zfs_ioc_send(zfs_cmd_t *zc) boolean_t compressok = (zc->zc_flags & 0x4); boolean_t rawok = (zc->zc_flags & 0x8); - if (rawok && compressok) - return (SET_ERROR(EINVAL)); - if (zc->zc_obj != 0) { dsl_pool_t *dp; dsl_dataset_t *tosnap; @@ -5518,7 +5515,7 @@ zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl) * (optional) "compressok" -> (value ignored) * presence indicates compressed DRR_WRITE records are permitted * (optional) "rawok" -> (value ignored) - * presence indicates raw DRR_WRITE records should be used. + * presence indicates raw encrypted records should be used. * (optional) "resume_object" and "resume_offset" -> (uint64) * if present, resume send stream from specified object and offset. * } @@ -5551,9 +5548,6 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) compressok = nvlist_exists(innvl, "compressok"); rawok = nvlist_exists(innvl, "rawok"); - if (rawok && compressok) - return (SET_ERROR(EINVAL)); - (void) nvlist_lookup_uint64(innvl, "resume_object", &resumeobj); (void) nvlist_lookup_uint64(innvl, "resume_offset", &resumeoff); diff --git a/usr/src/uts/common/fs/zfs/zil.c b/usr/src/uts/common/fs/zfs/zil.c index aca3e2d4a97c..94c4d3b766ff 100644 --- a/usr/src/uts/common/fs/zfs/zil.c +++ b/usr/src/uts/common/fs/zfs/zil.c @@ -577,8 +577,8 @@ zil_create(zilog_t *zilog) BP_ZERO(&blk); } - error = zio_alloc_zil(zilog->zl_spa, zilog->zl_os, txg, &blk, NULL, - ZIL_MIN_BLKSZ, &slog); + error = zio_alloc_zil(zilog->zl_spa, zilog->zl_os, txg, &blk, + NULL, ZIL_MIN_BLKSZ, &slog); if (error == 0) zil_init_log_chain(zilog, &blk); diff --git a/usr/src/uts/common/fs/zfs/zio.c b/usr/src/uts/common/fs/zfs/zio.c index 617660652add..5e74cf180da7 100644 --- a/usr/src/uts/common/fs/zfs/zio.c +++ b/usr/src/uts/common/fs/zfs/zio.c @@ -3940,8 +3940,8 @@ zio_done(zio_t *zio) * device is currently unavailable. */ if (zio->io_error != ECKSUM && vd != NULL && !vdev_is_dead(vd)) - zfs_ereport_post(FM_EREPORT_ZFS_IO, spa, vd, &zio->io_bookmark, - zio, 0, 0); + zfs_ereport_post(FM_EREPORT_ZFS_IO, spa, vd, + &zio->io_bookmark, zio, 0, 0); if ((zio->io_error == EIO || !(zio->io_flags & (ZIO_FLAG_SPECULATIVE | ZIO_FLAG_DONT_PROPAGATE))) && diff --git a/usr/src/uts/common/fs/zfs/zio_crypt.c b/usr/src/uts/common/fs/zfs/zio_crypt.c index 22750e5073aa..07475e1630f9 100644 --- a/usr/src/uts/common/fs/zfs/zio_crypt.c +++ b/usr/src/uts/common/fs/zfs/zio_crypt.c @@ -182,9 +182,8 @@ * function. */ #define ZFS_KEY_MAX_SALT_USES_DEFAULT 400000000 -#define ZFS_KEY_MAX_SALT_USES_MAX 800000000 #define ZFS_CURRENT_MAX_SALT_USES \ - (MIN(zfs_key_max_salt_uses, ZFS_KEY_MAX_SALT_USES_MAX)) + (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; zio_crypt_info_t zio_crypt_table[ZIO_CRYPT_FUNCTIONS] = { @@ -1011,6 +1010,7 @@ zio_crypt_copy_dnode_bonus(abd_t *src_abd, uint8_t *dst, uint_t datalen) static void zio_crypt_bp_zero_nonportable_blkprop(blkptr_t *bp) { + int avoidlint = SPA_MINBLOCKSIZE; BP_SET_DEDUP(bp, 0); BP_SET_CHECKSUM(bp, 0); @@ -1018,7 +1018,7 @@ zio_crypt_bp_zero_nonportable_blkprop(blkptr_t *bp) * 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_PSIZE(bp, avoidlint); } static int @@ -1129,7 +1129,6 @@ zio_crypt_do_dnode_hmac_updates(crypto_context_t ctx, boolean_t should_bswap, { int ret, i; dnode_phys_t *adnp; - blkptr_t *bp; boolean_t le_bswap = (should_bswap == ZFS_HOST_BYTEORDER); crypto_data_t cd; uint8_t tmp_dncore[offsetof(dnode_phys_t, dn_blkptr)]; @@ -1159,16 +1158,16 @@ zio_crypt_do_dnode_hmac_updates(crypto_context_t ctx, boolean_t should_bswap, goto error; } - for (i = 0; i < dnp->dn_nblkptr + 1; i++) { - if (i < dnp->dn_nblkptr) { - bp = &dnp->dn_blkptr[i]; - } else if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) { - bp = DN_SPILL_BLKPTR(dnp); - } else { - break; - } + for (i = 0; i < dnp->dn_nblkptr; i++) { + ret = zio_crypt_bp_do_hmac_updates(ctx, + should_bswap, &dnp->dn_blkptr[i]); + if (ret != 0) + goto error; + } - ret = zio_crypt_bp_do_hmac_updates(ctx, should_bswap, bp); + if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) { + ret = zio_crypt_bp_do_hmac_updates(ctx, + should_bswap, DN_SPILL_BLKPTR(dnp)); if (ret != 0) goto error; } @@ -1250,6 +1249,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen, if (should_bswap) intval = BSWAP_64(intval); intval &= OBJSET_CRYPT_PORTABLE_FLAGS_MASK; + /* CONSTCOND */ if (!ZFS_HOST_BYTEORDER) intval = BSWAP_64(intval); @@ -1304,6 +1304,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen, if (should_bswap) intval = BSWAP_64(intval); intval &= ~OBJSET_CRYPT_PORTABLE_FLAGS_MASK; + /* CONSTCOND */ if (!ZFS_HOST_BYTEORDER) intval = BSWAP_64(intval); @@ -1408,9 +1409,9 @@ zio_crypt_do_indirect_mac_checksum_abd(boolean_t generate, abd_t *abd, /* * Special case handling routine for encrypting / decrypting ZIL blocks. - * We do not check for the older ZIL chain because this feature was not - * available before the newer ZIL chain was introduced. The goal here - * is to encrypt everything except the blkptr_t of a lr_write_t and + * We do not check for the older ZIL chain because the encryption feature + * was not available before the newer ZIL chain was introduced. The goal + * here is to encrypt everything except the blkptr_t of a lr_write_t and * the zil_chain_t header. Everything that is not encrypted is authenticated. */ @@ -1431,7 +1432,7 @@ zio_crypt_init_uios_zil(boolean_t encrypt, uint8_t *plainbuf, lr_t *lr; uint8_t *aadbuf = zio_buf_alloc(datalen); - /* if we are decrypting, the plainbuffer needs an extra iovec */ + /* cipherbuf always needs an extra iovec for the MAC */ if (encrypt) { src = plainbuf; dst = cipherbuf; @@ -1617,7 +1618,6 @@ zio_crypt_init_uios_dnode(boolean_t encrypt, uint8_t *plainbuf, boolean_t *no_crypt) { int ret; - blkptr_t *bp; uint_t nr_src, nr_dst, crypt_len; uint_t aad_len = 0, nr_iovecs = 0, total_len = 0; uint_t i, j, max_dnp = datalen >> DNODE_SHIFT; @@ -1713,17 +1713,14 @@ zio_crypt_init_uios_dnode(boolean_t encrypt, uint8_t *plainbuf, aadp += crypt_len; aad_len += crypt_len; - for (j = 0; j < dnp->dn_nblkptr + 1; j++) { - if (j < dnp->dn_nblkptr) { - bp = &dnp->dn_blkptr[j]; - } else if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) { - bp = DN_SPILL_BLKPTR(dnp); - } else { - break; - } + for (j = 0; j < dnp->dn_nblkptr; j++) { + zio_crypt_bp_do_aad_updates(&aadp, &aad_len, + byteswap, &dnp->dn_blkptr[j]); + } + if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) { zio_crypt_bp_do_aad_updates(&aadp, &aad_len, - byteswap, bp); + byteswap, DN_SPILL_BLKPTR(dnp)); } /*