Skip to content

Commit

Permalink
zdb: add -B option to generate backup stream
Browse files Browse the repository at this point in the history
This is more-or-less like `zfs send`, but specifying the snapshot by its
objset id for situations where it can't be referenced any other way.

Sponsored-By: Klara, Inc.
Signed-off-by: Rob Norris <[email protected]>
  • Loading branch information
robn committed Mar 21, 2023
1 parent fa46802 commit 4933fb9
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 4 deletions.
94 changes: 90 additions & 4 deletions cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,9 @@ usage(void)
"\t\t[<poolname>[/<dataset | objset id>] [<object | range> ...]]\n"
"\t%s [-AdiPv] [-e [-V] [-p <path> ...]] [-U <cache>] [-K <key>]\n"
"\t\t[<poolname>[/<dataset | objset id>] [<object | range> ...]\n"
"\t%s -B [-e [-V] [-p <path> ...]] [-I <inflight I/Os>]\n"
"\t\t[-o <var>=<value>]... [-t <txg>] [-U <cache>] [-x <dumpdir>]\n"
"\t\t[-K <key>] <poolname>/<objset id> [<backupflags>]\n"
"\t%s [-v] <bookmark>\n"
"\t%s -C [-A] [-U <cache>]\n"
"\t%s -l [-Aqu] <device>\n"
Expand All @@ -802,7 +805,7 @@ usage(void)
"\t%s -S [-AP] [-e [-V] [-p <path> ...]] [-U <cache>] "
"<poolname>\n\n",
cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname,
cmdname, cmdname, cmdname, cmdname);
cmdname, cmdname, cmdname, cmdname, cmdname);

(void) fprintf(stderr, " Dataset name must include at least one "
"separator character '/' or '@'\n");
Expand All @@ -825,6 +828,8 @@ usage(void)
(void) fprintf(stderr, " Options to control amount of output:\n");
(void) fprintf(stderr, " -b --block-stats "
"block statistics\n");
(void) fprintf(stderr, " -B --backup "
"backup stream\n");
(void) fprintf(stderr, " -c --checksum "
"checksum all metadata (twice for all data) blocks\n");
(void) fprintf(stderr, " -C --config "
Expand Down Expand Up @@ -4866,6 +4871,81 @@ dump_path(char *ds, char *path, uint64_t *retobj)
return (err);
}

static int
dump_backup_bytes(objset_t *os, void *buf, int len, void *arg)
{
const char *p = (const char *)buf;
ssize_t nwritten;

(void) os;
(void) arg;

/* Write the data out, handling short writes and signals. */
while ((nwritten = write(STDOUT_FILENO, p, len)) < len) {
if (nwritten < 0) {
if (errno == EINTR)
continue;
return (errno);
}
p += nwritten;
len -= nwritten;
}

return (0);
}

static void
dump_backup(const char *pool, uint64_t objset_id, const char *flagstr)
{
boolean_t embed = B_FALSE;
boolean_t large_block = B_FALSE;
boolean_t compress = B_FALSE;
boolean_t raw = B_FALSE;

const char *c;
for (c = flagstr; c != NULL && *c != '\0'; c++) {
switch (*c) {
case 'e':
embed = B_TRUE;
break;
case 'L':
large_block = B_TRUE;
break;
case 'c':
compress = B_TRUE;
break;
case 'w':
raw = B_TRUE;
break;
default:
fprintf(stderr, "dump_backup: invalid flag "
"'%c'\n", *c);
return;
}
}

if (isatty(STDOUT_FILENO)) {
fprintf(stderr, "dump_backup: stream cannot be written "
"to a terminal\n");
return;
}

offset_t off = 0;
dmu_send_outparams_t out = {
.dso_outfunc = dump_backup_bytes,
.dso_dryrun = B_FALSE,
};

int err = dmu_send_obj(pool, objset_id, /* fromsnap */0, embed,
large_block, compress, raw, /* saved */ B_FALSE, STDOUT_FILENO,
&off, &out);
if (err != 0) {
fprintf(stderr, "dump_backup: dmu_send_obj: %s\n",
strerror(err));
return;
}
}

static int
zdb_copy_object(objset_t *os, uint64_t srcobj, char *destfile)
{
Expand Down Expand Up @@ -8651,6 +8731,7 @@ main(int argc, char **argv)
struct option long_options[] = {
{"ignore-assertions", no_argument, NULL, 'A'},
{"block-stats", no_argument, NULL, 'b'},
{"backup", no_argument, NULL, 'B'},
{"checksum", no_argument, NULL, 'c'},
{"config", no_argument, NULL, 'C'},
{"datasets", no_argument, NULL, 'd'},
Expand Down Expand Up @@ -8692,10 +8773,11 @@ main(int argc, char **argv)
};

while ((c = getopt_long(argc, argv,
"AbcCdDeEFGhiI:kK:lLmMNo:Op:PqrRsSt:uU:vVx:XYyZ",
"AbBcCdDeEFGhiI:kK:lLmMNo:Op:PqrRsSt:uU:vVx:XYyZ",
long_options, NULL)) != -1) {
switch (c) {
case 'b':
case 'B':
case 'c':
case 'C':
case 'd':
Expand Down Expand Up @@ -9029,7 +9111,8 @@ main(int argc, char **argv)
checkpoint_pool, error);
}

} else if (target_is_spa || dump_opt['R'] || objset_id == 0) {
} else if (target_is_spa || dump_opt['R'] || dump_opt['B'] ||
objset_id == 0) {
zdb_set_skip_mmp(target);
error = spa_open_rewind(target, &spa, FTAG, policy,
NULL);
Expand Down Expand Up @@ -9165,7 +9248,10 @@ main(int argc, char **argv)
strerror(errno));
}
}
if (os != NULL) {
if (dump_opt['B']) {
dump_backup(target, objset_id,
argc > 0 ? argv[0] : NULL);
} else if (os != NULL) {
dump_objset(os);
} else if (zopt_object_args > 0 && !dump_opt['m']) {
dump_objset(spa->spa_meta_objset);
Expand Down
22 changes: 22 additions & 0 deletions man/man8/zdb.8
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@
.Ar poolname Ns Op Ar / Ns Ar dataset Ns | Ns Ar objset-ID
.Op Ar object Ns | Ns Ar range Ns
.Nm
.Fl B
.Op Fl e Oo Fl V Oc Oo Fl p Ar path Oc Ns
.Op Fl U Ar cache
.Op Fl K Ar key
.Ar poolname Ns Ar / Ns Ar objset-ID
.Op Ar backup-flags
.Nm
.Fl C
.Op Fl A
.Op Fl U Ar cache
Expand Down Expand Up @@ -123,6 +130,21 @@ Display options:
Display statistics regarding the number, size
.Pq logical, physical and allocated
and deduplication of blocks.
.It Fl B , -backup
Generate a backup stream, similar to
.Nm zfs Cm send ,
but for the numeric objset ID, and without opening the snapshot.
This is useful if the snapshot metadata has become corrupted.
The optional
.Ar flags
argument is a string of one or more of the letters
.Sy e ,
.Sy L ,
.Sy c ,
and
.Sy w ,
which correspond to the same flags in
.Xr zfs-send 8 .
.It Fl c , -checksum
Verify the checksum of all metadata blocks while printing block statistics
.Po see
Expand Down

0 comments on commit 4933fb9

Please sign in to comment.