]> granicus.if.org Git - zfs/commitdiff
Fix intra-pool resumable 'zfs send -t <token>'
authorLOLi <loli10K@users.noreply.github.com>
Tue, 10 Oct 2017 22:22:05 +0000 (00:22 +0200)
committerTony Hutter <hutter2@llnl.gov>
Mon, 16 Oct 2017 17:57:55 +0000 (10:57 -0700)
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

lib/libzfs/libzfs_iter.c
lib/libzfs/libzfs_sendrecv.c
tests/zfs-tests/tests/functional/rsend/rsend.kshlib
tests/zfs-tests/tests/functional/rsend/rsend_019_pos.ksh
tests/zfs-tests/tests/functional/rsend/rsend_020_pos.ksh
tests/zfs-tests/tests/functional/rsend/rsend_021_pos.ksh
tests/zfs-tests/tests/functional/rsend/rsend_022_pos.ksh
tests/zfs-tests/tests/functional/rsend/rsend_024_pos.ksh
tests/zfs-tests/tests/functional/rsend/send-c_resume.ksh

index 57ebdd89d1b8e562cc092c85248ef41305ae3a0d..75267d05368c83ac84eda1ec895abdc6545e7439 100644 (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));
 }
 
 
index ff909f1e35740674d11e7e3dcd83fff74402872b..db8079fb3ec60558638cb55d466c4a2415453054 100644 (file)
@@ -1609,6 +1609,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"));
@@ -1623,9 +1624,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 ||
@@ -1682,7 +1683,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);
        }
 
index fde4123be872e60bde573f58942db36b2c4ce9c7..294d79807571c083db7897630dce9a3401574cdc 100644 (file)
@@ -513,11 +513,13 @@ function test_fs_setup
 {
        typeset sendfs=$1
        typeset recvfs=$2
+       typeset streamfs=$3
        typeset sendpool=${sendfs%%/*}
        typeset recvpool=${recvfs%%/*}
 
        datasetexists $sendfs && log_must zfs destroy -r $sendpool
        datasetexists $recvfs && log_must zfs destroy -r $recvpool
+       datasetexists $streamfs && log_must zfs destroy -r $streamfs
 
        if $(datasetexists $sendfs || zfs create -o compress=lz4 $sendfs); then
                mk_files 1000 256 0 $sendfs &
@@ -546,10 +548,7 @@ function test_fs_setup
                    ">/$sendpool/incremental.zsend"
        fi
 
-       if datasetexists $streamfs; then
-               log_must zfs destroy -r $streamfs
-       fi
-       log_must zfs create -o compress=lz4 $sendpool/stream
+       log_must zfs create -o compress=lz4 $streamfs
 }
 
 #
@@ -663,9 +662,10 @@ function resume_cleanup
 {
        typeset sendfs=$1
        typeset streamfs=$2
+       typeset sendpool=${sendfs%%/*}
 
        datasetexists $sendfs && log_must zfs destroy -r $sendfs
        datasetexists $streamfs && log_must zfs destroy -r $streamfs
        cleanup_pool $POOL2
-       rm -f /$POOL/initial.zsend /$POOL/incremental.zsend
+       rm -f /$sendpool/initial.zsend /$sendpool/incremental.zsend
 }
index 771d7e2f04a03160c4842b4534d1affb76ceffcb..9c95587a2ba43806e1d896c1c72f654783ffd09e 100755 (executable)
@@ -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
index 29bdc4f840ddb2d6c7ed34e7ceebdf27d0c5ac93..b7ecf90916ba8e6b94390faa5b646a37870defd5 100755 (executable)
@@ -42,7 +42,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
 
index d74844890a9242b3c322b8472642fd0cba82be44..50f2b8890a5cc5c6b400aa56079700bb862bea1f 100755 (executable)
@@ -44,7 +44,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
index 487a01426b07cf00dc1cf40fcf63d08d676c376e..dda6602632ba8886514b7aef252c15ff7305cc8a 100755 (executable)
@@ -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 zfs destroy $sendfs@a
 log_must zfs receive -v $recvfs </$POOL/initial.zsend
index e7453a0e1ed2c12351b58365cd031bd81e6ea1ad..406a466b3998be9054b1f7d3eb89120b0800b1a2 100755 (executable)
@@ -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 $sendfs
 resume_test "zfs send $sendfs" $streamfs $recvfs
 file_check $sendfs $recvfs
index 9f43b79297b5c0cab64304c38b61b9100db5ba8a..d8d7c40e49313d39eb3df8ad770a32148359c53d 100755 (executable)
@@ -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