Fix intra-pool resumable 'zfs send -t <token>'

Because resuming from a token requires "guid" -> "snapshot" mapping
we have to walk the whole dataset hierarchy to find the right snapshot
to send; when both source and destination exists, for an incremental
resumable stream, libzfs gets confused and picks up the wrong snapshot
to send from: this results in attempting to send

   "destination@snap1 -> source@snap2"

instead of

   "source@snap1 -> source@snap2"

which fails with a "Invalid cross-device link" error (EXDEV).

Fix this by adjusting the logic behind dataset traversal in
zfs_iter_children() to pick the right snapshot to send from.

Additionally update dry-run 'zfs send -t' to print its output to
stderr: this is consistent with other dry-run commands.

Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #6618
Closes #6619
Closes #6623
This commit is contained in:
LOLi
2017-10-11 00:22:05 +02:00
committed by Brian Behlendorf
parent 70f02287f8
commit aee1dd4d98
9 changed files with 18 additions and 17 deletions
+2 -2
View File
@@ -428,10 +428,10 @@ zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
{
int ret;
if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
if ((ret = zfs_iter_snapshots(zhp, B_FALSE, func, data)) != 0)
return (ret);
return (zfs_iter_snapshots(zhp, B_FALSE, func, data));
return (zfs_iter_filesystems(zhp, func, data));
}
+4 -3
View File
@@ -1654,6 +1654,7 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
int error = 0;
char name[ZFS_MAX_DATASET_NAME_LEN];
enum lzc_send_flags lzc_flags = 0;
FILE *fout = (flags->verbose && flags->dryrun) ? stdout : stderr;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot resume send"));
@@ -1668,9 +1669,9 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
return (zfs_error(hdl, EZFS_FAULT, errbuf));
}
if (flags->verbose) {
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
"resume token contents:\n"));
nvlist_print(stderr, resume_nvl);
nvlist_print(fout, resume_nvl);
}
if (nvlist_lookup_string(resume_nvl, "toname", &toname) != 0 ||
@@ -1729,7 +1730,7 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
lzc_flags, &size);
if (error == 0)
size = MAX(0, (int64_t)(size - bytes));
send_print_verbose(stderr, zhp->zfs_name, fromname,
send_print_verbose(fout, zhp->zfs_name, fromname,
size, flags->parsable);
}