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:
parent
70f02287f8
commit
aee1dd4d98
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -505,11 +505,13 @@ function test_fs_setup
|
|||
{
|
||||
typeset sendfs=$1
|
||||
typeset recvfs=$2
|
||||
typeset streamfs=$3
|
||||
typeset sendpool=${sendfs%%/*}
|
||||
typeset recvpool=${recvfs%%/*}
|
||||
|
||||
datasetexists $sendfs && log_must_busy zfs destroy -r $sendpool
|
||||
datasetexists $recvfs && log_must_busy zfs destroy -r $recvpool
|
||||
datasetexists $streamfs && log_must_busy zfs destroy -r $streamfs
|
||||
|
||||
if $(datasetexists $sendfs || zfs create -o compress=lz4 $sendfs); then
|
||||
mk_files 1000 256 0 $sendfs &
|
||||
|
@ -538,10 +540,7 @@ function test_fs_setup
|
|||
">/$sendpool/incremental.zsend"
|
||||
fi
|
||||
|
||||
if datasetexists $streamfs; then
|
||||
log_must_busy zfs destroy -r $streamfs
|
||||
fi
|
||||
log_must zfs create -o compress=lz4 $sendpool/stream
|
||||
log_must zfs create -o compress=lz4 $streamfs
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -655,9 +654,10 @@ function resume_cleanup
|
|||
{
|
||||
typeset sendfs=$1
|
||||
typeset streamfs=$2
|
||||
typeset sendpool=${sendfs%%/*}
|
||||
|
||||
datasetexists $sendfs && log_must_busy zfs destroy -r $sendfs
|
||||
datasetexists $streamfs && log_must_busy zfs destroy -r $streamfs
|
||||
cleanup_pool $POOL2
|
||||
rm -f /$POOL/initial.zsend /$POOL/incremental.zsend
|
||||
rm -f /$sendpool/initial.zsend /$sendpool/incremental.zsend
|
||||
}
|
||||
|
|
|
@ -48,8 +48,8 @@ sendfs=$POOL/sendfs
|
|||
recvfs=$POOL3/recvfs
|
||||
streamfs=$POOL2/stream
|
||||
|
||||
for sendfs in $POOL2/sendfs $POOL2; do
|
||||
test_fs_setup $sendfs $recvfs
|
||||
for sendfs in $POOL2/sendfs $POOL3; do
|
||||
test_fs_setup $sendfs $recvfs $streamfs
|
||||
resume_test "zfs send -v $sendfs@a" $streamfs $recvfs
|
||||
resume_test "zfs send -v -i @a $sendfs@b" $streamfs $recvfs
|
||||
file_check $sendfs $recvfs
|
||||
|
|
|
@ -47,7 +47,7 @@ streamfs=$POOL/stream
|
|||
|
||||
log_onexit resume_cleanup $sendfs $streamfs
|
||||
|
||||
test_fs_setup $sendfs $recvfs
|
||||
test_fs_setup $sendfs $recvfs $streamfs
|
||||
resume_test "zfs send -D -v $sendfs@a" $streamfs $recvfs
|
||||
file_check $sendfs $recvfs
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ streamfs=$POOL/stream
|
|||
|
||||
log_onexit resume_cleanup $sendfs $streamfs
|
||||
|
||||
test_fs_setup $sendfs $recvfs
|
||||
test_fs_setup $sendfs $recvfs $streamfs
|
||||
resume_test "zfs send -v -e $sendfs@a" $streamfs $recvfs
|
||||
resume_test "zfs send -v -e -i @a $sendfs@b" $streamfs $recvfs
|
||||
file_check $sendfs $recvfs
|
||||
|
|
|
@ -52,7 +52,7 @@ streamfs=$POOL/stream
|
|||
|
||||
log_onexit resume_cleanup $sendfs $streamfs
|
||||
|
||||
test_fs_setup $sendfs $recvfs
|
||||
test_fs_setup $sendfs $recvfs $streamfs
|
||||
log_must zfs bookmark $sendfs@a $sendfs#bm_a
|
||||
log_must_busy zfs destroy $sendfs@a
|
||||
log_must zfs receive -v $recvfs </$POOL/initial.zsend
|
||||
|
|
|
@ -49,7 +49,7 @@ streamfs=$POOL/stream
|
|||
|
||||
log_onexit resume_cleanup $sendfs $streamfs
|
||||
|
||||
test_fs_setup $sendfs $recvfs
|
||||
test_fs_setup $sendfs $recvfs $streamfs
|
||||
log_must zfs unmount -f $sendfs
|
||||
resume_test "zfs send $sendfs" $streamfs $recvfs
|
||||
file_check $sendfs $recvfs
|
||||
|
|
|
@ -41,7 +41,7 @@ streamfs=$POOL/stream
|
|||
log_assert "Verify compressed send streams can be resumed if interrupted"
|
||||
log_onexit resume_cleanup $sendfs $streamfs
|
||||
|
||||
test_fs_setup $sendfs $recvfs
|
||||
test_fs_setup $sendfs $recvfs $streamfs
|
||||
resume_test "zfs send -c -v $sendfs@a" $streamfs $recvfs
|
||||
resume_test "zfs send -c -v -i @a $sendfs@b" $streamfs $recvfs
|
||||
file_check $sendfs $recvfs
|
||||
|
|
Loading…
Reference in New Issue