Author: mav
Date: Thu Feb 22 04:01:55 2018
New Revision: 329808
URL: https://svnweb.freebsd.org/changeset/base/329808

Log:
  MFV r329807:
  8940 Sending an intra-pool resumable send stream may result in EXDEV
  
  illumos/illumos-gate@544132fce3fa6583f01318f9559adc46614343a7
  
  "zfs send -t <token>" for an incremental send should be able to resume
  successfully when sending to the same pool: a subtle issue in
  zfs_iter_children() doesn't currently allow this.
  
  Because resuming from a token requires "guid" -> "dataset" mapping
  (guid_to_name()), we have to walk the whole hierarchy to find the right
  snapshots to send.
  When resuming an incremental send both source and destination live in the
  same pool and have the same guid: this is where zfs_iter_children() gets
  confused and picks up the wrong snapshot, so we end up trying to send an
  incremental "destination@snap1 -> source@snap2" stream instead of
  "source@snap1 -> source@snap2": this fails with an "Invalid cross-device
  link" (EXDEV) error.
  
  Reviewed by: Paul Dagnelie <[email protected]>
  Reviewed by: Matthew Ahrens <[email protected]>
  Approved by: Hans Rosenfeld <[email protected]>
  Author: loli10K <[email protected]>

Modified:
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
Directory Properties:
  head/cddl/contrib/opensolaris/   (props changed)
  head/cddl/contrib/opensolaris/lib/libzfs/   (props changed)

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c       Thu Feb 
22 04:01:05 2018        (r329807)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c       Thu Feb 
22 04:01:55 2018        (r329808)
@@ -424,16 +424,20 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *sp
 
 /*
  * Iterate over all children, snapshots and filesystems
+ * Process snapshots before filesystems because they are nearer the input
+ * handle: this is extremely important when used with zfs_iter_f functions
+ * looking for data, following the logic that we would like to find it as soon
+ * and as close as possible.
  */
 int
 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));
 }
 
 

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c   Thu Feb 
22 04:01:05 2018        (r329807)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c   Thu Feb 
22 04:01:55 2018        (r329808)
@@ -1585,6 +1585,7 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *fla
        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"));
@@ -1599,9 +1600,9 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *fla
                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 ||
@@ -1658,7 +1659,7 @@ zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *fla
                    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);
        }
 
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to