diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 9dbfb1641ac6..ba9a0998ed27 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -638,8 +638,14 @@ send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv) */ if (prop == ZPROP_INVAL) continue; - - if (zfs_prop_readonly(prop)) + /* + * Encryption is setonce so readonly will return + * true, but we need it in the stream to make + * the set of stream props encryption,checksum,keysource + * all consistent. + */ + if (prop != ZFS_PROP_ENCRYPTION && + zfs_prop_readonly(prop)) continue; } @@ -1402,11 +1408,15 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, } if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM) { - uint64_t version; + uint64_t version, crypt; version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); if (version >= ZPL_VERSION_SA) { featureflags |= DMU_BACKUP_FEATURE_SA_SPILL; } + crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION); + if (crypt != ZIO_CRYPT_OFF) { + featureflags |= DMU_BACKUP_FEATURE_ENCRYPT; + } } if (flags->dedup && !flags->dryrun) { @@ -2559,6 +2569,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, VERIFY(0 == nvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0)); } + ret = zcmd_write_src_nvlist(hdl, &zc, props); if (err) nvlist_free(props); @@ -2835,6 +2846,14 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, zc.zc_begin_record = drr_noswap->drr_u.drr_begin; zc.zc_cookie = infd; zc.zc_guid = flags->force; + + // This will most likely fail for recv VOLUMES. + if (!flags->dryrun && + zfs_crypto_zckey(hdl, ZFS_CRYPTO_RECV, NULL, &zc, + ZFS_TYPE_FILESYSTEM) != 0) { + return zfs_error(hdl, EZFS_KEYERR, errbuf); + } + if (flags->verbose) { (void) printf("%s %s stream of %s into %s\n", flags->dryrun ? "would receive" : "receiving", @@ -2856,7 +2875,6 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, err = ioctl_err = zfs_ioctl(hdl, ZFS_IOC_RECV, &zc); ioctl_errno = errno; prop_errflags = (zprop_errflags_t)zc.zc_obj; - if (err == 0) { nvlist_t *prop_errors; VERIFY(0 == nvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst, diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index a4e1255bb75e..e71687c13477 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -228,6 +228,8 @@ libzfs_error_description(libzfs_handle_t *hdl) return (dgettext(TEXT_DOMAIN, "invalid diff data")); case EZFS_POOLREADONLY: return (dgettext(TEXT_DOMAIN, "pool is read-only")); + case EZFS_KEYERR: + return (dgettext(TEXT_DOMAIN, "crypto key operation failure")); case EZFS_UNKNOWN: return (dgettext(TEXT_DOMAIN, "unknown error")); default: diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 677380c58f65..9c4a7119e018 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -900,7 +900,7 @@ dmu_recv_begin(char *tofs, char *tosnap, char *top_ds, struct drr_begin *drrb, /* open the dataset we are logically receiving into */ err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds); if (err == 0) { - if (dmu_recv_verify_features(ds, drrb)) { + if (!dmu_recv_verify_features(ds, drrb)) { dsl_dataset_rele(ds, dmu_recv_tag); return (ENOTSUP); } @@ -951,7 +951,7 @@ dmu_recv_begin(char *tofs, char *tosnap, char *top_ds, struct drr_begin *drrb, if (err) return (err); - if (dmu_recv_verify_features(ds, drrb)) { + if (!dmu_recv_verify_features(ds, drrb)) { dsl_dataset_rele(ds, FTAG); return (ENOTSUP); } diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index c5aa4ab698bf..a711bb156c93 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -4308,8 +4308,9 @@ zfs_ioc_recv(zfs_cmd_t *zc) zc->zc_iflags, &cmdprops)) != 0) goto out; - if ((error = zfs_get_crypto_ctx(zc, &dcc)) != 0) + if ((error = zfs_get_crypto_ctx(zc, &dcc)) != 0) { return (error); + } VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0);