Skip to content

Commit 8c4ff60

Browse files
committed
Add --no-preserve-encryption flag
Add an option to send datasets with params without preserving encryption Signed-off-by: Chris Jacobs <idefix2020dev@gmail.com>
1 parent aeb9fb3 commit 8c4ff60

File tree

4 files changed

+54
-22
lines changed

4 files changed

+54
-22
lines changed

cmd/zfs/zfs_main.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,10 @@ get_usage(zfs_help_t idx)
344344
case HELP_ROLLBACK:
345345
return (gettext("\trollback [-rRf] <snapshot>\n"));
346346
case HELP_SEND:
347-
return (gettext("\tsend [-DLPbcehnpsVvw] "
347+
return (gettext("\tsend [-DLPbcehnpsUVvw] "
348348
"[-i|-I snapshot]\n"
349349
"\t [-R [-X dataset[,dataset]...]] <snapshot>\n"
350-
"\tsend [-DnVvPLecw] [-i snapshot|bookmark] "
350+
"\tsend [-DnVvPLecwU] [-i snapshot|bookmark] "
351351
"<filesystem|volume|snapshot>\n"
352352
"\tsend [-DnPpVvLec] [-i bookmark|snapshot] "
353353
"--redact <bookmark> <snapshot>\n"
@@ -4759,11 +4759,12 @@ zfs_do_send(int argc, char **argv)
47594759
{"holds", no_argument, NULL, 'h'},
47604760
{"saved", no_argument, NULL, 'S'},
47614761
{"exclude", required_argument, NULL, 'X'},
4762+
{"no-preserve-encryption", no_argument, NULL, 'U'},
47624763
{0, 0, 0, 0}
47634764
};
47644765

47654766
/* check options */
4766-
while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:SX:",
4767+
while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:SX:U",
47674768
long_options, NULL)) != -1) {
47684769
switch (c) {
47694770
case 'X':
@@ -4849,6 +4850,9 @@ zfs_do_send(int argc, char **argv)
48494850
case 'S':
48504851
flags.saved = B_TRUE;
48514852
break;
4853+
case 'U':
4854+
flags.no_preserve_encryption = B_TRUE;
4855+
break;
48524856
case ':':
48534857
/*
48544858
* If a parameter was not passed, optopt contains the

include/libzfs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,9 @@ typedef struct sendflags {
844844

845845
/* stream represents a partially received dataset */
846846
boolean_t saved;
847+
848+
/* allow sending datasets with props, without preserving encryption */
849+
boolean_t no_preserve_encryption;
847850
} sendflags_t;
848851

849852
typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);

lib/libzfs/libzfs_sendrecv.c

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ typedef struct send_data {
258258
boolean_t seento;
259259
boolean_t holds; /* were holds requested with send -h */
260260
boolean_t props;
261+
boolean_t no_preserve_encryption;
261262

262263
/*
263264
* The header nvlist is of the following format:
@@ -587,20 +588,32 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
587588
fnvlist_add_boolean(nvfs, "is_encroot");
588589

589590
/*
590-
* Encrypted datasets can only be sent with properties if
591-
* the raw flag is specified because the receive side doesn't
592-
* currently have a mechanism for recursively asking the user
593-
* for new encryption parameters.
591+
* Encrypted datasets can only be sent with properties if the
592+
* raw flag or the no-preserve-encryption flag are specified
593+
* because the receive side doesn't currently have a mechanism
594+
* for recursively asking the user for new encryption
595+
* parameters.
596+
* We allow sending the dataset unencrypted only if the user
597+
* explicitly sets the no-preserve-encryption flag.
594598
*/
595-
if (!sd->raw) {
599+
if (!sd->raw && !sd->no_preserve_encryption) {
596600
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
597601
"cannot send %s@%s: encrypted dataset %s may not "
598-
"be sent with properties without the raw flag\n"),
602+
"be sent with properties without the raw flag or "
603+
"no-preserve-encryption flag\n"),
599604
sd->fsname, sd->tosnap, zhp->zfs_name);
600605
rv = -1;
601606
goto out;
602607
}
603608

609+
/* If no-preserve-encryption flag is set, warn the user again */
610+
if (sd->no_preserve_encryption) {
611+
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
612+
"WARNING: no-preserve-encryption flag set, sending "
613+
"dataset %s without encryption\n"),
614+
zhp->zfs_name);
615+
}
616+
604617
}
605618

606619
/*
@@ -683,8 +696,8 @@ static int
683696
gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
684697
const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t doall,
685698
boolean_t replicate, boolean_t skipmissing, boolean_t verbose,
686-
boolean_t backup, boolean_t holds, boolean_t props, nvlist_t **nvlp,
687-
avl_tree_t **avlp)
699+
boolean_t backup, boolean_t holds, boolean_t props,
700+
boolean_t no_preserve_encryption, nvlist_t **nvlp, avl_tree_t **avlp)
688701
{
689702
zfs_handle_t *zhp;
690703
send_data_t sd = { 0 };
@@ -707,6 +720,7 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
707720
sd.backup = backup;
708721
sd.holds = holds;
709722
sd.props = props;
723+
sd.no_preserve_encryption = no_preserve_encryption;
710724

711725
if ((error = send_iterate_fs(zhp, &sd)) != 0) {
712726
fnvlist_free(sd.fss);
@@ -2199,7 +2213,7 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,
21992213
boolean_t gather_props, boolean_t recursive, boolean_t verbose,
22002214
boolean_t dryrun, boolean_t raw, boolean_t replicate, boolean_t skipmissing,
22012215
boolean_t backup, boolean_t holds, boolean_t props, boolean_t doall,
2202-
nvlist_t **fssp, avl_tree_t **fsavlp)
2216+
boolean_t no_preserve_encryption, nvlist_t **fssp, avl_tree_t **fsavlp)
22032217
{
22042218
int err = 0;
22052219
char *packbuf = NULL;
@@ -2245,7 +2259,8 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,
22452259

22462260
if (gather_nvlist(zhp->zfs_hdl, tofs,
22472261
from, tosnap, recursive, raw, doall, replicate, skipmissing,
2248-
verbose, backup, holds, props, &fss, fsavlp) != 0) {
2262+
verbose, backup, holds, props, no_preserve_encryption,
2263+
&fss, fsavlp) != 0) {
22492264
return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP,
22502265
errbuf));
22512266
}
@@ -2392,7 +2407,7 @@ zfs_send_cb_impl(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
23922407
flags->replicate, flags->verbosity > 0, flags->dryrun,
23932408
flags->raw, flags->replicate, flags->skipmissing,
23942409
flags->backup, flags->holds, flags->props, flags->doall,
2395-
&fss, &fsavl);
2410+
flags->no_preserve_encryption, &fss, &fsavl);
23962411
zfs_close(tosnap);
23972412
if (err != 0)
23982413
goto err_out;
@@ -2735,7 +2750,8 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
27352750
err = send_prelim_records(zhp, NULL, fd, B_TRUE, B_FALSE,
27362751
flags->verbosity > 0, flags->dryrun, flags->raw,
27372752
flags->replicate, B_FALSE, flags->backup, flags->holds,
2738-
flags->props, flags->doall, NULL, NULL);
2753+
flags->props, flags->doall, flags->no_preserve_encryption,
2754+
NULL, NULL);
27392755
if (err != 0)
27402756
return (err);
27412757
}
@@ -3392,7 +3408,7 @@ recv_fix_encryption_hierarchy(libzfs_handle_t *hdl, const char *top_zfs,
33923408
/* Using top_zfs, gather the nvlists for all local filesystems. */
33933409
if ((err = gather_nvlist(hdl, top_zfs, NULL, NULL,
33943410
recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,
3395-
B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)
3411+
B_FALSE, B_TRUE, B_FALSE, &local_nv, &local_avl)) != 0)
33963412
return (err);
33973413

33983414
/*
@@ -3547,7 +3563,7 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
35473563

35483564
if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
35493565
recursive, B_TRUE, B_FALSE, recursive, B_FALSE, B_FALSE, B_FALSE,
3550-
B_FALSE, B_TRUE, &local_nv, &local_avl)) != 0)
3566+
B_FALSE, B_TRUE, B_FALSE, &local_nv, &local_avl)) != 0)
35513567
return (error);
35523568

35533569
/*
@@ -5138,7 +5154,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
51385154
*cp = '\0';
51395155
if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE,
51405156
B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_FALSE,
5141-
B_TRUE, &local_nv, &local_avl) == 0) {
5157+
B_TRUE, B_FALSE, &local_nv, &local_avl) == 0) {
51425158
*cp = '@';
51435159
fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
51445160
fsavl_destroy(local_avl);

man/man8/zfs-send.8

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
.\" Copyright 2019 Joyent, Inc.
3232
.\" Copyright (c) 2024, Klara, Inc.
3333
.\"
34-
.Dd August 29, 2025
34+
.Dd February 20, 2026
3535
.Dt ZFS-SEND 8
3636
.Os
3737
.
@@ -41,13 +41,13 @@
4141
.Sh SYNOPSIS
4242
.Nm zfs
4343
.Cm send
44-
.Op Fl DLPVbcehnpsvw
44+
.Op Fl DLPUVbcehnpsvw
4545
.Op Fl R Op Fl X Ar dataset Ns Oo , Ns Ar dataset Oc Ns
4646
.Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot
4747
.Ar snapshot
4848
.Nm zfs
4949
.Cm send
50-
.Op Fl DLPVcensvw
50+
.Op Fl DLPUVcensvw
5151
.Op Fl i Ar snapshot Ns | Ns Ar bookmark
5252
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
5353
.Nm zfs
@@ -75,7 +75,7 @@
7575
.It Xo
7676
.Nm zfs
7777
.Cm send
78-
.Op Fl DLPVbcehnpsvw
78+
.Op Fl DLPUVbcehnpsvw
7979
.Op Fl R Op Fl X Ar dataset Ns Oo , Ns Ar dataset Oc Ns
8080
.Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot
8181
.Ar snapshot
@@ -146,6 +146,8 @@ If the
146146
.Fl R
147147
flag is used to send encrypted datasets, then
148148
.Fl w
149+
or
150+
.Fl U
149151
must also be specified.
150152
.It Fl V , -proctitle
151153
Set the process title to a per-second report of how much data has been sent.
@@ -293,6 +295,8 @@ is specified.
293295
The receiving system must also support this feature.
294296
Sends of encrypted datasets must use
295297
.Fl w
298+
or
299+
.Fl U
296300
when using this flag.
297301
.It Fl s , -skip-missing
298302
Allows sending a replication stream even when there are snapshots missing in the
@@ -303,6 +307,11 @@ belongs
303307
and its descendants are skipped.
304308
This flag can only be used in conjunction with
305309
.Fl R .
310+
.It Fl U , -no-preserve-encryption
311+
Allow sending an encrypted dataset with properties, but without keeping
312+
encryption.
313+
When this flag is specified, encrypted datasets that would otherwise be blocked
314+
from sending are sent as unencrypted data.
306315
.It Fl v , -verbose
307316
Print verbose information about the stream package generated.
308317
This information includes a per-second report of how much data has been sent.

0 commit comments

Comments
 (0)