diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 51a0fbd43c..365a8c90f2 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -4737,11 +4737,12 @@ zfs_do_send(int argc, char **argv) {"holds", no_argument, NULL, 'h'}, {"saved", no_argument, NULL, 'S'}, {"exclude", required_argument, NULL, 'X'}, + {"props-dropenc", no_argument, NULL, 'C'}, {0, 0, 0, 0} }; /* check options */ - while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:SX:", + while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:SX:C", long_options, NULL)) != -1) { switch (c) { case 'X': @@ -4778,6 +4779,9 @@ zfs_do_send(int argc, char **argv) case 'd': redactbook = optarg; break; + case 'C': + flags.dropenc = B_TRUE; + // fall through case 'p': flags.props = B_TRUE; break; @@ -4869,6 +4873,14 @@ zfs_do_send(int argc, char **argv) } } + if (flags.dropenc && flags.raw) { + free(excludes.list); + (void) fprintf(stderr, + gettext("Cannot specify both --raw and " + "--props-dropenc.\n")); + usage(B_FALSE); + } + if ((flags.parsable || flags.progressastitle) && flags.verbosity == 0) flags.verbosity = 1; diff --git a/include/libzfs.h b/include/libzfs.h index 01d51999f4..2e60cdd68c 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -826,6 +826,9 @@ typedef struct sendflags { /* stream represents a partially received dataset */ boolean_t saved; + + /* Drop encryption flags for a property send. */ + boolean_t dropenc; } sendflags_t; typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *); diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index ee01ee9b21..7edb1c1853 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -256,6 +256,7 @@ typedef struct send_data { boolean_t seento; boolean_t holds; /* were holds requested with send -h */ boolean_t props; + boolean_t dropenc; /* * The header nvlist is of the following format: @@ -284,7 +285,8 @@ typedef struct send_data { } send_data_t; static void -send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, nvlist_t *nv); +send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, boolean_t dropenc, +nvlist_t *nv); /* * Collect guid, valid props, optionally holds, etc. of a snapshot. @@ -353,7 +355,7 @@ send_iterate_snap(zfs_handle_t *zhp, void *arg) } nvlist_t *nv = fnvlist_alloc(); - send_iterate_prop(zhp, sd->backup, nv); + send_iterate_prop(zhp, sd->backup, sd->dropenc, nv); fnvlist_add_nvlist(sd->snapprops, snapname, nv); fnvlist_free(nv); @@ -373,7 +375,8 @@ send_iterate_snap(zfs_handle_t *zhp, void *arg) * Collect all valid props from the handle snap into an nvlist. */ static void -send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, nvlist_t *nv) +send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, boolean_t dropenc, + nvlist_t *nv) { nvlist_t *props; @@ -412,6 +415,19 @@ send_iterate_prop(zfs_handle_t *zhp, boolean_t received_only, nvlist_t *nv) if (isspacelimit && zhp->zfs_type == ZFS_TYPE_SNAPSHOT) continue; + boolean_t isencprop = (prop == ZFS_PROP_IVSET_GUID || + prop == ZFS_PROP_ENCRYPTION || + prop == ZFS_PROP_KEYLOCATION || + prop == ZFS_PROP_KEYFORMAT || + prop == ZFS_PROP_PBKDF2_SALT || + prop == ZFS_PROP_PBKDF2_ITERS || + prop == ZFS_PROP_ENCRYPTION_ROOT || + prop == ZFS_PROP_KEY_GUID || + prop == ZFS_PROP_KEYSTATUS); + + if (isencprop && dropenc) + continue; + const char *source; if (nvlist_lookup_string(propnv, ZPROP_SOURCE, &source) == 0) { if (strcmp(source, zhp->zfs_name) != 0 && @@ -569,10 +585,11 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg) /* Iterate over props. */ if (sd->props || sd->backup || sd->recursive) { nv = fnvlist_alloc(); - send_iterate_prop(zhp, sd->backup, nv); + send_iterate_prop(zhp, sd->backup, sd->dropenc, nv); fnvlist_add_nvlist(nvfs, "props", nv); } - if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) != ZIO_CRYPT_OFF) { + if ((zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) != ZIO_CRYPT_OFF) && + sd->dropenc == B_FALSE) { boolean_t encroot; /* Determine if this dataset is an encryption root. */ @@ -681,8 +698,8 @@ static int gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t doall, boolean_t replicate, boolean_t skipmissing, boolean_t verbose, - boolean_t backup, boolean_t holds, boolean_t props, nvlist_t **nvlp, - avl_tree_t **avlp) + boolean_t backup, boolean_t holds, boolean_t props, boolean_t dropenc, + nvlist_t **nvlp, avl_tree_t **avlp) { zfs_handle_t *zhp; send_data_t sd = { 0 }; @@ -705,6 +722,7 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, sd.backup = backup; sd.holds = holds; sd.props = props; + sd.dropenc = dropenc; if ((error = send_iterate_fs(zhp, &sd)) != 0) { fnvlist_free(sd.fss); @@ -2196,7 +2214,7 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd, boolean_t gather_props, boolean_t recursive, boolean_t verbose, boolean_t dryrun, boolean_t raw, boolean_t replicate, boolean_t skipmissing, boolean_t backup, boolean_t holds, boolean_t props, boolean_t doall, - nvlist_t **fssp, avl_tree_t **fsavlp) + boolean_t dropenc, nvlist_t **fssp, avl_tree_t **fsavlp) { int err = 0; char *packbuf = NULL; @@ -2242,7 +2260,8 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd, if (gather_nvlist(zhp->zfs_hdl, tofs, from, tosnap, recursive, raw, doall, replicate, skipmissing, - verbose, backup, holds, props, &fss, fsavlp) != 0) { + verbose, backup, holds, props, dropenc, + &fss, fsavlp) != 0) { return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP, errbuf)); } @@ -2389,7 +2408,7 @@ zfs_send_cb_impl(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, flags->replicate, flags->verbosity > 0, flags->dryrun, flags->raw, flags->replicate, flags->skipmissing, flags->backup, flags->holds, flags->props, flags->doall, - &fss, &fsavl); + flags->dropenc, &fss, &fsavl); zfs_close(tosnap); if (err != 0) goto err_out; @@ -2732,7 +2751,7 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd, err = send_prelim_records(zhp, NULL, fd, B_TRUE, B_FALSE, flags->verbosity > 0, flags->dryrun, flags->raw, flags->replicate, B_FALSE, flags->backup, flags->holds, - flags->props, flags->doall, NULL, NULL); + flags->props, flags->doall, flags->dropenc, NULL, NULL); if (err != 0) return (err); } @@ -3527,7 +3546,7 @@ again: if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL, recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE, - B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0) + B_FALSE, B_TRUE, B_FALSE, &local_nv, &local_avl)) != 0) return (error); /* @@ -5118,7 +5137,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, *cp = '\0'; if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, - B_TRUE, &local_nv, &local_avl) == 0) { + B_TRUE, B_FALSE, &local_nv, &local_avl) == 0) { *cp = '@'; fs = fsavl_find(local_avl, drrb->drr_toguid, NULL); fsavl_destroy(local_avl);