Skip to content

Commit 4416790

Browse files
committed
Implement Redacted Send/Receive
1 parent a7165d7 commit 4416790

File tree

107 files changed

+13567
-4457
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+13567
-4457
lines changed

cmd/zdb/zdb.c

Lines changed: 249 additions & 31 deletions
Large diffs are not rendered by default.

cmd/zfs/zfs_main.c

Lines changed: 158 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include <assert.h>
3434
#include <ctype.h>
35+
#include <sys/debug.h>
3536
#include <errno.h>
3637
#include <getopt.h>
3738
#include <libgen.h>
@@ -116,6 +117,7 @@ static int zfs_do_load_key(int argc, char **argv);
116117
static int zfs_do_unload_key(int argc, char **argv);
117118
static int zfs_do_change_key(int argc, char **argv);
118119
static int zfs_do_project(int argc, char **argv);
120+
static int zfs_do_redact(int argc, char **argv);
119121

120122
/*
121123
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
@@ -170,6 +172,7 @@ typedef enum {
170172
HELP_LOAD_KEY,
171173
HELP_UNLOAD_KEY,
172174
HELP_CHANGE_KEY,
175+
HELP_REDACT,
173176
} zfs_help_t;
174177

175178
typedef struct zfs_command {
@@ -232,6 +235,7 @@ static zfs_command_t command_table[] = {
232235
{ "load-key", zfs_do_load_key, HELP_LOAD_KEY },
233236
{ "unload-key", zfs_do_unload_key, HELP_UNLOAD_KEY },
234237
{ "change-key", zfs_do_change_key, HELP_CHANGE_KEY },
238+
{ "redact", zfs_do_redact, HELP_REDACT },
235239
};
236240

237241
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@@ -273,7 +277,7 @@ get_usage(zfs_help_t idx)
273277
"[filesystem|volume|snapshot] ...\n"));
274278
case HELP_MOUNT:
275279
return (gettext("\tmount\n"
276-
"\tmount [-lvO] [-o opts] <-a | filesystem>\n"));
280+
"\tmount [-flvO] [-o opts] <-a | filesystem>\n"));
277281
case HELP_PROMOTE:
278282
return (gettext("\tpromote <clone-filesystem>\n"));
279283
case HELP_RECEIVE:
@@ -296,6 +300,9 @@ get_usage(zfs_help_t idx)
296300
"<snapshot>\n"
297301
"\tsend [-nvPLecw] [-i snapshot|bookmark] "
298302
"<filesystem|volume|snapshot>\n"
303+
"[-i bookmark] <snapshot> <bookmark_name>\n"
304+
"\tsend [-DnPpvLecr] [-i bookmark|snapshot] "
305+
"--redact <bookmark> <snapshot>\n"
299306
"\tsend [-nvPe] -t <receive_resume_token>\n"));
300307
case HELP_SET:
301308
return (gettext("\tset <property=value> ... "
@@ -378,6 +385,9 @@ get_usage(zfs_help_t idx)
378385
"\t [-o keylocation=<value>] [-o pbkfd2iters=<value>]\n"
379386
"\t <filesystem|volume>\n"
380387
"\tchange-key -i [-l] <filesystem|volume>\n"));
388+
case HELP_REDACT:
389+
return (gettext("\tredact <snapshot> <bookmark> "
390+
"<redaction_snapshot> ..."));
381391
}
382392

383393
abort();
@@ -535,6 +545,8 @@ usage(boolean_t requested)
535545
(void) fprintf(fp, "YES NO <size> | none\n");
536546
(void) fprintf(fp, "\t%-15s ", "written@<snap>");
537547
(void) fprintf(fp, " NO NO <size>\n");
548+
(void) fprintf(fp, "\t%-15s ", "written#<bookmark>");
549+
(void) fprintf(fp, " NO NO <size>\n");
538550

539551
(void) fprintf(fp, gettext("\nSizes are specified in bytes "
540552
"with standard units such as K, M, G, etc.\n"));
@@ -1493,6 +1505,13 @@ zfs_do_destroy(int argc, char **argv)
14931505
return (-1);
14941506
}
14951507

1508+
/*
1509+
* Unfortunately, zfs_bookmark() doesn't honor the
1510+
* casesensitivity setting. However, we can't simply
1511+
* remove this check, because lzc_destroy_bookmarks()
1512+
* ignores non-existent bookmarks, so this is necessary
1513+
* to get a proper error message.
1514+
*/
14961515
if (!zfs_bookmark_exists(argv[0])) {
14971516
(void) fprintf(stderr, gettext("bookmark '%s' "
14981517
"does not exist.\n"), argv[0]);
@@ -3557,6 +3576,73 @@ zfs_do_promote(int argc, char **argv)
35573576
return (ret);
35583577
}
35593578

3579+
static int
3580+
zfs_do_redact(int argc, char **argv)
3581+
{
3582+
char *snap = NULL;
3583+
char *bookname = NULL;
3584+
char **rsnaps = NULL;
3585+
int numrsnaps = 0;
3586+
argv++;
3587+
argc--;
3588+
if (argc < 3) {
3589+
(void) fprintf(stderr, gettext("too few arguments"));
3590+
usage(B_FALSE);
3591+
}
3592+
3593+
snap = argv[0];
3594+
bookname = argv[1];
3595+
rsnaps = argv + 2;
3596+
numrsnaps = argc - 2;
3597+
3598+
nvlist_t *rsnapnv = fnvlist_alloc();
3599+
3600+
for (int i = 0; i < numrsnaps; i++) {
3601+
fnvlist_add_boolean(rsnapnv, rsnaps[i]);
3602+
}
3603+
3604+
int err = lzc_redact(snap, bookname, rsnapnv);
3605+
fnvlist_free(rsnapnv);
3606+
3607+
switch (err) {
3608+
case 0:
3609+
break;
3610+
case ENOENT:
3611+
(void) fprintf(stderr,
3612+
gettext("provided snapshot %s does not exist"), snap);
3613+
break;
3614+
case EEXIST:
3615+
(void) fprintf(stderr, gettext("specified redaction bookmark "
3616+
"(%s) provided already exists"), bookname);
3617+
break;
3618+
case ENAMETOOLONG:
3619+
(void) fprintf(stderr, gettext("provided bookmark name cannot "
3620+
"be used, final name would be too long"));
3621+
break;
3622+
case E2BIG:
3623+
(void) fprintf(stderr, gettext("too many redaction snapshots "
3624+
"specified"));
3625+
break;
3626+
case EINVAL:
3627+
(void) fprintf(stderr, gettext("redaction snapshot must be "
3628+
"descendent of snapshot being redacted"));
3629+
break;
3630+
case EALREADY:
3631+
(void) fprintf(stderr, gettext("attempted to redact redacted "
3632+
"dataset or with respect to redacted dataset"));
3633+
break;
3634+
case ENOTSUP:
3635+
(void) fprintf(stderr, gettext("redaction bookmarks feature "
3636+
"not enabled"));
3637+
break;
3638+
default:
3639+
(void) fprintf(stderr, gettext("internal error: %s"),
3640+
strerror(errno));
3641+
}
3642+
3643+
return (err);
3644+
}
3645+
35603646
/*
35613647
* zfs rollback [-rRf] <snapshot>
35623648
*
@@ -3941,6 +4027,9 @@ zfs_do_snapshot(int argc, char **argv)
39414027
return (-1);
39424028
}
39434029

4030+
4031+
#define REDACT_OPT 1024
4032+
39444033
/*
39454034
* Send a backup stream to stdout.
39464035
*/
@@ -3955,10 +4044,11 @@ zfs_do_send(int argc, char **argv)
39554044
sendflags_t flags = { 0 };
39564045
int c, err;
39574046
nvlist_t *dbgnv = NULL;
3958-
boolean_t extraverbose = B_FALSE;
4047+
char *redactbook = NULL;
39594048

39604049
struct option long_options[] = {
39614050
{"replicate", no_argument, NULL, 'R'},
4051+
{"redact-bookmark", required_argument, NULL, REDACT_OPT},
39624052
{"props", no_argument, NULL, 'p'},
39634053
{"parsable", no_argument, NULL, 'P'},
39644054
{"dedup", no_argument, NULL, 'D'},
@@ -3991,6 +4081,9 @@ zfs_do_send(int argc, char **argv)
39914081
case 'R':
39924082
flags.replicate = B_TRUE;
39934083
break;
4084+
case REDACT_OPT:
4085+
redactbook = optarg;
4086+
break;
39944087
case 'p':
39954088
flags.props = B_TRUE;
39964089
break;
@@ -3999,12 +4092,9 @@ zfs_do_send(int argc, char **argv)
39994092
break;
40004093
case 'P':
40014094
flags.parsable = B_TRUE;
4002-
flags.verbose = B_TRUE;
40034095
break;
40044096
case 'v':
4005-
if (flags.verbose)
4006-
extraverbose = B_TRUE;
4007-
flags.verbose = B_TRUE;
4097+
flags.verbosity++;
40084098
flags.progress = B_TRUE;
40094099
break;
40104100
case 'D':
@@ -4072,19 +4162,21 @@ zfs_do_send(int argc, char **argv)
40724162
}
40734163
}
40744164

4165+
if (flags.parsable && flags.verbosity == 0)
4166+
flags.verbosity = 1;
4167+
40754168
argc -= optind;
40764169
argv += optind;
40774170

40784171
if (resume_token != NULL) {
40794172
if (fromname != NULL || flags.replicate || flags.props ||
4080-
flags.backup || flags.dedup) {
4173+
flags.backup || flags.dedup || redactbook != NULL) {
40814174
(void) fprintf(stderr,
40824175
gettext("invalid flags combined with -t\n"));
40834176
usage(B_FALSE);
40844177
}
4085-
if (argc != 0) {
4086-
(void) fprintf(stderr, gettext("no additional "
4087-
"arguments are permitted with -t\n"));
4178+
if (argc > 0) {
4179+
(void) fprintf(stderr, gettext("too many arguments\n"));
40884180
usage(B_FALSE);
40894181
}
40904182
} else {
@@ -4112,43 +4204,70 @@ zfs_do_send(int argc, char **argv)
41124204
}
41134205

41144206
/*
4115-
* Special case sending a filesystem, or from a bookmark.
4207+
* For everything except -R and -I, use the new, cleaner code path.
41164208
*/
4117-
if (strchr(argv[0], '@') == NULL ||
4118-
(fromname && strchr(fromname, '#') != NULL)) {
4209+
if (!(flags.replicate || flags.doall)) {
41194210
char frombuf[ZFS_MAX_DATASET_NAME_LEN];
41204211

4121-
if (flags.replicate || flags.doall || flags.props ||
4122-
flags.backup || flags.dedup ||
4123-
(strchr(argv[0], '@') == NULL &&
4124-
(flags.dryrun || flags.verbose || flags.progress))) {
4125-
(void) fprintf(stderr, gettext("Error: "
4126-
"Unsupported flag with filesystem or bookmark.\n"));
4127-
return (1);
4212+
if (redactbook != NULL) {
4213+
if (strchr(argv[0], '@') == NULL) {
4214+
(void) fprintf(stderr, gettext("Error: Cannot "
4215+
"do a redacted send to a filesystem.\n"));
4216+
return (1);
4217+
}
41284218
}
41294219

41304220
zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET);
41314221
if (zhp == NULL)
41324222
return (1);
41334223

4224+
if (fromname != NULL && (strchr(fromname, '#') == NULL &&
4225+
strchr(fromname, '@') == NULL)) {
4226+
/*
4227+
* Neither bookmark or snapshot was specified. Print a
4228+
* warning, and assume snapshot.
4229+
*/
4230+
(void) fprintf(stderr, "Warning: incremental source "
4231+
"didn't specify type, assuming snapshot. Use '@' "
4232+
"or '#' prefix to avoid ambiguity.\n");
4233+
(void) snprintf(frombuf, sizeof (frombuf), "@%s",
4234+
fromname);
4235+
fromname = frombuf;
4236+
}
41344237
if (fromname != NULL &&
41354238
(fromname[0] == '#' || fromname[0] == '@')) {
41364239
/*
41374240
* Incremental source name begins with # or @.
41384241
* Default to same fs as target.
41394242
*/
4243+
char tmpbuf[ZFS_MAX_DATASET_NAME_LEN];
4244+
(void) strlcpy(tmpbuf, fromname, sizeof (tmpbuf));
41404245
(void) strlcpy(frombuf, argv[0], sizeof (frombuf));
41414246
cp = strchr(frombuf, '@');
41424247
if (cp != NULL)
41434248
*cp = '\0';
4144-
(void) strlcat(frombuf, fromname, sizeof (frombuf));
4249+
(void) strlcat(frombuf, tmpbuf, sizeof (frombuf));
41454250
fromname = frombuf;
41464251
}
4147-
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, flags);
4252+
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags,
4253+
redactbook);
41484254
zfs_close(zhp);
41494255
return (err != 0);
41504256
}
41514257

4258+
if (fromname != NULL && strchr(fromname, '#')) {
4259+
(void) fprintf(stderr,
4260+
gettext("Error: multiple snapshots cannot be "
4261+
"sent from a bookmark.\n"));
4262+
return (1);
4263+
}
4264+
4265+
if (redactbook != NULL) {
4266+
(void) fprintf(stderr, gettext("Error: multiple snapshots "
4267+
"cannot be sent redacted.\n"));
4268+
return (1);
4269+
}
4270+
41524271
cp = strchr(argv[0], '@');
41534272
*cp = '\0';
41544273
toname = cp + 1;
@@ -4192,9 +4311,9 @@ zfs_do_send(int argc, char **argv)
41924311
flags.doall = B_TRUE;
41934312

41944313
err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0,
4195-
extraverbose ? &dbgnv : NULL);
4314+
flags.verbosity >= 3 ? &dbgnv : NULL);
41964315

4197-
if (extraverbose && dbgnv != NULL) {
4316+
if (flags.verbosity >= 3 && dbgnv != NULL) {
41984317
/*
41994318
* dump_nvlist prints to stdout, but that's been
42004319
* redirected to a file. Make it print to stderr
@@ -6278,6 +6397,17 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
62786397
return (1);
62796398
}
62806399

6400+
if (zfs_prop_get_int(zhp, ZFS_PROP_REDACTED) && !(flags & MS_FORCE)) {
6401+
if (!explicit)
6402+
return (0);
6403+
6404+
(void) fprintf(stderr, gettext("cannot %s '%s': "
6405+
"Dataset is not complete, was created by receiving "
6406+
"a redacted zfs send stream.\n"), cmdname,
6407+
zfs_get_name(zhp));
6408+
return (1);
6409+
}
6410+
62816411
/*
62826412
* At this point, we have verified that the mountpoint and/or
62836413
* shareopts are appropriate for auto management. If the
@@ -6413,7 +6543,7 @@ share_mount(int op, int argc, char **argv)
64136543
int flags = 0;
64146544

64156545
/* check options */
6416-
while ((c = getopt(argc, argv, op == OP_MOUNT ? ":alvo:O" : "al"))
6546+
while ((c = getopt(argc, argv, op == OP_MOUNT ? ":alvo:Of" : "al"))
64176547
!= -1) {
64186548
switch (c) {
64196549
case 'a':
@@ -6441,6 +6571,9 @@ share_mount(int op, int argc, char **argv)
64416571
case 'O':
64426572
flags |= MS_OVERLAY;
64436573
break;
6574+
case 'f':
6575+
flags |= MS_FORCE;
6576+
break;
64446577
case ':':
64456578
(void) fprintf(stderr, gettext("missing argument for "
64466579
"'%c' option\n"), optopt);

cmd/zstreamdump/zstreamdump.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ main(int argc, char *argv[])
236236
struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
237237
struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded;
238238
struct drr_object_range *drror = &thedrr.drr_u.drr_object_range;
239+
struct drr_redact *drrr = &thedrr.drr_u.drr_redact;
239240
struct drr_checksum *drrc = &thedrr.drr_u.drr_checksum;
240241
char c;
241242
boolean_t verbose = B_FALSE;
@@ -707,6 +708,21 @@ main(int argc, char *argv[])
707708
mac);
708709
}
709710
break;
711+
case DRR_REDACT:
712+
if (do_byteswap) {
713+
drrr->drr_object = BSWAP_64(drrr->drr_object);
714+
drrr->drr_offset = BSWAP_64(drrr->drr_offset);
715+
drrr->drr_length = BSWAP_64(drrr->drr_length);
716+
drrr->drr_toguid = BSWAP_64(drrr->drr_toguid);
717+
}
718+
if (verbose) {
719+
(void) printf("REDACT object = %llu offset = "
720+
"%llu length = %llu\n",
721+
(u_longlong_t)drrr->drr_object,
722+
(u_longlong_t)drrr->drr_offset,
723+
(u_longlong_t)drrr->drr_length);
724+
}
725+
break;
710726
case DRR_NUMTYPES:
711727
/* should never be reached */
712728
exit(1);

0 commit comments

Comments
 (0)