]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Avoid retrieving unused snapshot props
authorAlek P <alek-p@users.noreply.github.com>
Tue, 12 Mar 2019 20:13:22 +0000 (13:13 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 12 Mar 2019 20:13:22 +0000 (13:13 -0700)
This patch modifies the zfs_ioc_snapshot_list_next() ioctl to enable it
to take input parameters that alter the way looping through the list of
snapshots is performed. The idea here is to restrict functions that
throw away some of the snapshots returned by the ioctl to a range of
snapshots that these functions actually use. This improves efficiency
and execution speed for some rollback and send operations.

Reviewed-by: Tom Caputi <tcaputi@datto.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Signed-off-by: Alek Pinchuk <apinchuk@datto.com>
Closes #8077

cmd/zfs/zfs_iter.c
cmd/zfs/zfs_main.c
include/libzfs.h
include/sys/fs/zfs.h
lib/libzfs/libzfs_dataset.c
lib/libzfs/libzfs_iter.c
lib/libzfs/libzfs_sendrecv.c
module/zfs/zfs_ioctl.c

index af4e4b4d2d7b5734b4167fba1d00b0e944cf2b3f..9ad6919388aedc6750ca6b78a86e3d66aa721050 100644 (file)
@@ -140,7 +140,7 @@ zfs_callback(zfs_handle_t *zhp, void *data)
                    ZFS_TYPE_BOOKMARK)) == 0) && include_snaps)
                        (void) zfs_iter_snapshots(zhp,
                            (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback,
-                           data);
+                           data, 0, 0);
                if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
                    ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks)
                        (void) zfs_iter_bookmarks(zhp, zfs_callback, data);
index 12a5cf6cf9b98944a62d8b853da350a24484a11d..21c4d4334eb4c2645a5a4ca111d37f4fba6ee1b5 100644 (file)
@@ -27,7 +27,7 @@
  * Copyright (c) 2013 Steven Hartland.  All rights reserved.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
  * Copyright 2016 Nexenta Systems, Inc.
- * Copyright (c) 2018 Datto Inc.
+ * Copyright (c) 2019 Datto Inc.
  */
 
 #include <assert.h>
@@ -1255,7 +1255,7 @@ destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
        int err;
        assert(cb->cb_firstsnap == NULL);
        assert(cb->cb_prevsnap == NULL);
-       err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
+       err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb, 0, 0);
        if (cb->cb_firstsnap != NULL) {
                uint64_t used = 0;
                if (err == 0) {
@@ -3581,6 +3581,7 @@ zfs_do_promote(int argc, char **argv)
  */
 typedef struct rollback_cbdata {
        uint64_t        cb_create;
+       uint8_t         cb_younger_ds_printed;
        boolean_t       cb_first;
        int             cb_doclones;
        char            *cb_target;
@@ -3612,15 +3613,20 @@ rollback_check_dependent(zfs_handle_t *zhp, void *data)
 
 
 /*
- * Report any snapshots more recent than the one specified.  Used when '-r' is
- * not specified.  We reuse this same callback for the snapshot dependents - if
- * 'cb_dependent' is set, then this is a dependent and we should report it
- * without checking the transaction group.
+ * Report some snapshots/bookmarks more recent than the one specified.
+ * Used when '-r' is not specified. We reuse this same callback for the
+ * snapshot dependents - if 'cb_dependent' is set, then this is a
+ * dependent and we should report it without checking the transaction group.
  */
 static int
 rollback_check(zfs_handle_t *zhp, void *data)
 {
        rollback_cbdata_t *cbp = data;
+       /*
+        * Max number of younger snapshots and/or bookmarks to display before
+        * we stop the iteration.
+        */
+       const uint8_t max_younger = 32;
 
        if (cbp->cb_doclones) {
                zfs_close(zhp);
@@ -3649,9 +3655,24 @@ rollback_check(zfs_handle_t *zhp, void *data)
                } else {
                        (void) fprintf(stderr, "%s\n",
                            zfs_get_name(zhp));
+                       cbp->cb_younger_ds_printed++;
                }
        }
        zfs_close(zhp);
+
+       if (cbp->cb_younger_ds_printed == max_younger) {
+               /*
+                * This non-recursive rollback is going to fail due to the
+                * presence of snapshots and/or bookmarks that are younger than
+                * the rollback target.
+                * We printed some of the offending objects, now we stop
+                * zfs_iter_snapshot/bookmark iteration so we can fail fast and
+                * avoid iterating over the rest of the younger objects
+                */
+               (void) fprintf(stderr, gettext("Output limited to %d "
+                   "snapshots/bookmarks\n"), max_younger);
+               return (-1);
+       }
        return (0);
 }
 
@@ -3665,6 +3686,7 @@ zfs_do_rollback(int argc, char **argv)
        zfs_handle_t *zhp, *snap;
        char parentname[ZFS_MAX_DATASET_NAME_LEN];
        char *delim;
+       uint64_t min_txg = 0;
 
        /* check options */
        while ((c = getopt(argc, argv, "rRf")) != -1) {
@@ -3720,7 +3742,12 @@ zfs_do_rollback(int argc, char **argv)
        cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
        cb.cb_first = B_TRUE;
        cb.cb_error = 0;
-       if ((ret = zfs_iter_snapshots(zhp, B_FALSE, rollback_check, &cb)) != 0)
+
+       if (cb.cb_create > 0)
+               min_txg = cb.cb_create;
+
+       if ((ret = zfs_iter_snapshots(zhp, B_FALSE, rollback_check, &cb,
+           min_txg, 0)) != 0)
                goto out;
        if ((ret = zfs_iter_bookmarks(zhp, rollback_check, &cb)) != 0)
                goto out;
index 65b06f7a806c804820adefd0b9620169b13de46e..3405bb99bb4fd4abe144ef5efa597cb30862abf3 100644 (file)
@@ -27,7 +27,7 @@
  * Copyright (c) 2016, Intel Corporation.
  * Copyright 2016 Nexenta Systems, Inc.
  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
- * Copyright (c) 2018 Datto Inc.
+ * Copyright (c) 2019 Datto Inc.
  */
 
 #ifndef        _LIBZFS_H
@@ -571,8 +571,10 @@ extern int zfs_iter_root(libzfs_handle_t *, zfs_iter_f, void *);
 extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
 extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
 extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
-extern int zfs_iter_snapshots(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
-extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_snapshots(zfs_handle_t *, boolean_t, zfs_iter_f, void *,
+    uint64_t, uint64_t);
+extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *,
+    uint64_t, uint64_t);
 extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *);
 extern int zfs_iter_bookmarks(zfs_handle_t *, zfs_iter_f, void *);
 extern int zfs_iter_mounted(zfs_handle_t *, zfs_iter_f, void *);
index 8a86480a699a6b20530e9c1182156c20c6f4ec09..c4d26eb8788e1bf56d52ee78dd634261c91a03ca 100644 (file)
@@ -25,8 +25,8 @@
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2013, 2017 Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
- * Copyright (c) 2017 Datto Inc.
  * Copyright (c) 2017, Intel Corporation.
+ * Copyright (c) 2019 Datto Inc.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -1076,7 +1076,7 @@ typedef enum pool_initialize_func {
  * is passed between kernel and userland as an nvlist uint64 array.
  */
 typedef struct ddt_object {
-       uint64_t        ddo_count;      /* number of elements in ddt    */
+       uint64_t        ddo_count;      /* number of elements in ddt    */
        uint64_t        ddo_dspace;     /* size of ddt on disk          */
        uint64_t        ddo_mspace;     /* size of ddt in-core          */
 } ddt_object_t;
@@ -1123,6 +1123,13 @@ typedef enum {
        VDEV_INITIALIZE_COMPLETE
 } vdev_initializing_state_t;
 
+/*
+ * nvlist name constants. Facilitate restricting snapshot iteration range for
+ * the "list next snapshot" ioctl
+ */
+#define        SNAP_ITER_MIN_TXG       "snap_iter_min_txg"
+#define        SNAP_ITER_MAX_TXG       "snap_iter_max_txg"
+
 /*
  * /dev/zfs ioctl numbers.
  *
index 0537b631e5c09a42c35994d632bb1c158f3e3576..de94021a675847834ad8addc5a58192a0e7dc3d3 100644 (file)
@@ -30,7 +30,7 @@
  * Copyright 2017 Nexenta Systems, Inc.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  * Copyright 2017-2018 RackTop Systems.
- * Copyright (c) 2018 Datto Inc.
+ * Copyright (c) 2019 Datto Inc.
  */
 
 #include <ctype.h>
@@ -4367,6 +4367,7 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
        boolean_t restore_resv = 0;
        uint64_t old_volsize = 0, new_volsize;
        zfs_prop_t resv_prop = { 0 };
+       uint64_t min_txg = 0;
 
        assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
            zhp->zfs_type == ZFS_TYPE_VOLUME);
@@ -4377,7 +4378,13 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
        cb.cb_force = force;
        cb.cb_target = snap->zfs_name;
        cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
-       (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb);
+
+       if (cb.cb_create > 0)
+               min_txg = cb.cb_create;
+
+       (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb,
+           min_txg, 0);
+
        (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
 
        if (cb.cb_error)
index b1bdc4a6d9e3eac3597a3f7e6bec151b0c36e31d..e765a7ee74f9659abfdb2764f60dd67c4cd7a717 100644 (file)
@@ -23,7 +23,7 @@
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
- * Copyright (c) 2018 Datto Inc.
+ * Copyright (c) 2019 Datto Inc.
  */
 
 #include <stdio.h>
@@ -141,11 +141,12 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
  */
 int
 zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
-    void *data)
+    void *data, uint64_t min_txg, uint64_t max_txg)
 {
        zfs_cmd_t zc = {"\0"};
        zfs_handle_t *nzhp;
        int ret;
+       nvlist_t *range_nvl = NULL;
 
        if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
            zhp->zfs_type == ZFS_TYPE_BOOKMARK)
@@ -155,6 +156,24 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
 
        if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
                return (-1);
+
+       if (min_txg != 0) {
+               range_nvl = fnvlist_alloc();
+               fnvlist_add_uint64(range_nvl, SNAP_ITER_MIN_TXG, min_txg);
+       }
+       if (max_txg != 0) {
+               if (range_nvl == NULL)
+                       range_nvl = fnvlist_alloc();
+               fnvlist_add_uint64(range_nvl, SNAP_ITER_MAX_TXG, max_txg);
+       }
+
+       if (range_nvl != NULL &&
+           zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, range_nvl) != 0) {
+               zcmd_free_nvlists(&zc);
+               fnvlist_free(range_nvl);
+               return (-1);
+       }
+
        while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
            &zc)) == 0) {
 
@@ -167,10 +186,12 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
 
                if ((ret = func(nzhp, data)) != 0) {
                        zcmd_free_nvlists(&zc);
+                       fnvlist_free(range_nvl);
                        return (ret);
                }
        }
        zcmd_free_nvlists(&zc);
+       fnvlist_free(range_nvl);
        return ((ret < 0) ? ret : 0);
 }
 
@@ -282,7 +303,8 @@ zfs_snapshot_compare(const void *larg, const void *rarg)
 }
 
 int
-zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data)
+zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data,
+    uint64_t min_txg, uint64_t max_txg)
 {
        int ret = 0;
        zfs_node_t *node;
@@ -292,7 +314,8 @@ zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data)
        avl_create(&avl, zfs_snapshot_compare,
            sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
 
-       ret = zfs_iter_snapshots(zhp, B_FALSE, zfs_sort_snaps, &avl);
+       ret = zfs_iter_snapshots(zhp, B_FALSE, zfs_sort_snaps, &avl, min_txg,
+           max_txg);
 
        for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
                ret |= callback(node->zn_handle, data);
@@ -395,7 +418,7 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
                        }
 
                        err = zfs_iter_snapshots_sorted(fs_zhp,
-                           snapspec_cb, &ssa);
+                           snapspec_cb, &ssa, 0, 0);
                        if (ret == 0)
                                ret = err;
                        if (ret == 0 && (!ssa.ssa_seenfirst ||
@@ -435,7 +458,7 @@ zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
 {
        int ret;
 
-       if ((ret = zfs_iter_snapshots(zhp, B_FALSE, func, data)) != 0)
+       if ((ret = zfs_iter_snapshots(zhp, B_FALSE, func, data, 0, 0)) != 0)
                return (ret);
 
        return (zfs_iter_filesystems(zhp, func, data));
@@ -501,7 +524,7 @@ iter_dependents_cb(zfs_handle_t *zhp, void *arg)
                err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida);
                if (err == 0)
                        err = zfs_iter_snapshots(zhp, B_FALSE,
-                           iter_dependents_cb, ida);
+                           iter_dependents_cb, ida, 0, 0);
                ida->stack = isf.next;
        }
 
index 2aa0fd222514c1c047d41158bc492ecfa2e9154d..8096089f62c0b7ace8d0ba495bc1e587f4e46acc 100644 (file)
@@ -29,7 +29,7 @@
  * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
- * Copyright (c) 2018 Datto Inc.
+ * Copyright (c) 2019 Datto Inc.
  */
 
 #include <assert.h>
@@ -623,10 +623,11 @@ typedef struct send_data {
        const char *fsname;
        const char *fromsnap;
        const char *tosnap;
-       boolean_t raw;
-       boolean_t backup;
        boolean_t recursive;
+       boolean_t raw;
+       boolean_t replicate;
        boolean_t verbose;
+       boolean_t backup;
        boolean_t seenfrom;
        boolean_t seento;
        boolean_t holds;        /* were holds requested with send -h */
@@ -845,6 +846,7 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
        send_data_t *sd = arg;
        nvlist_t *nvfs = NULL, *nv = NULL;
        int rv = 0;
+       uint64_t min_txg = 0, max_txg = 0;
        uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;
        uint64_t fromsnap_txg_save = sd->fromsnap_txg;
        uint64_t tosnap_txg_save = sd->tosnap_txg;
@@ -888,10 +890,10 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
                goto out;
        }
 
-       VERIFY(0 == nvlist_alloc(&nvfs, NV_UNIQUE_NAME, 0));
-       VERIFY(0 == nvlist_add_string(nvfs, "name", zhp->zfs_name));
-       VERIFY(0 == nvlist_add_uint64(nvfs, "parentfromsnap",
-           sd->parent_fromsnap_guid));
+       nvfs = fnvlist_alloc();
+       fnvlist_add_string(nvfs, "name", zhp->zfs_name);
+       fnvlist_add_uint64(nvfs, "parentfromsnap",
+           sd->parent_fromsnap_guid);
 
        if (zhp->zfs_dmustats.dds_origin[0]) {
                zfs_handle_t *origin = zfs_open(zhp->zfs_hdl,
@@ -900,15 +902,15 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
                        rv = -1;
                        goto out;
                }
-               VERIFY(0 == nvlist_add_uint64(nvfs, "origin",
-                   origin->zfs_dmustats.dds_guid));
+               fnvlist_add_uint64(nvfs, "origin",
+                   origin->zfs_dmustats.dds_guid);
 
                zfs_close(origin);
        }
 
        /* iterate over props */
        if (sd->props || sd->backup || sd->recursive) {
-               VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
+               nv = fnvlist_alloc();
                send_iterate_prop(zhp, sd->backup, nv);
        }
        if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) != ZIO_CRYPT_OFF) {
@@ -921,7 +923,7 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
                }
 
                if (encroot)
-                       VERIFY(0 == nvlist_add_boolean(nvfs, "is_encroot"));
+                       fnvlist_add_boolean(nvfs, "is_encroot");
 
                /*
                 * Encrypted datasets can only be sent with properties if
@@ -941,28 +943,32 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
        }
 
        if (nv != NULL)
-               VERIFY(0 == nvlist_add_nvlist(nvfs, "props", nv));
+               fnvlist_add_nvlist(nvfs, "props", nv);
 
        /* iterate over snaps, and set sd->parent_fromsnap_guid */
        sd->parent_fromsnap_guid = 0;
-       VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
-       VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
+       sd->parent_snaps = fnvlist_alloc();
+       sd->snapprops = fnvlist_alloc();
+       if (!sd->replicate && fromsnap_txg != 0)
+               min_txg = fromsnap_txg;
+       if (!sd->replicate && tosnap_txg != 0)
+               max_txg = tosnap_txg;
        if (sd->holds)
                VERIFY(0 == nvlist_alloc(&sd->snapholds, NV_UNIQUE_NAME, 0));
-       (void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd);
-       VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
-       VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
+       (void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd,
+           min_txg, max_txg);
+       fnvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps);
+       fnvlist_add_nvlist(nvfs, "snapprops", sd->snapprops);
        if (sd->holds)
-               VERIFY(0 == nvlist_add_nvlist(nvfs, "snapholds",
-                   sd->snapholds));
-       nvlist_free(sd->parent_snaps);
-       nvlist_free(sd->snapprops);
-       nvlist_free(sd->snapholds);
+               fnvlist_add_nvlist(nvfs, "snapholds", sd->snapholds);
+       fnvlist_free(sd->parent_snaps);
+       fnvlist_free(sd->snapprops);
+       fnvlist_free(sd->snapholds);
 
        /* add this fs to nvlist */
        (void) snprintf(guidstring, sizeof (guidstring),
            "0x%llx", (longlong_t)guid);
-       VERIFY(0 == nvlist_add_nvlist(sd->fss, guidstring, nvfs));
+       fnvlist_add_nvlist(sd->fss, guidstring, nvfs);
 
        /* iterate over children */
        if (sd->recursive)
@@ -972,8 +978,8 @@ out:
        sd->parent_fromsnap_guid = parent_fromsnap_guid_save;
        sd->fromsnap_txg = fromsnap_txg_save;
        sd->tosnap_txg = tosnap_txg_save;
-       nvlist_free(nv);
-       nvlist_free(nvfs);
+       fnvlist_free(nv);
+       fnvlist_free(nvfs);
 
        zfs_close(zhp);
        return (rv);
@@ -981,8 +987,9 @@ out:
 
 static int
 gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
-    const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t verbose,
-    boolean_t backup, boolean_t holds, boolean_t props, nvlist_t **nvlp,
+    const char *tosnap, boolean_t recursive, boolean_t raw, boolean_t replicate,
+    boolean_t verbose, boolean_t backup, boolean_t holds, boolean_t props,
+    nvlist_t **nvlp,
     avl_tree_t **avlp)
 {
        zfs_handle_t *zhp;
@@ -999,6 +1006,7 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
        sd.tosnap = tosnap;
        sd.recursive = recursive;
        sd.raw = raw;
+       sd.replicate = replicate;
        sd.verbose = verbose;
        sd.backup = backup;
        sd.holds = holds;
@@ -1437,6 +1445,7 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
        send_dump_data_t *sdd = arg;
        boolean_t missingfrom = B_FALSE;
        zfs_cmd_t zc = {"\0"};
+       uint64_t min_txg = 0, max_txg = 0;
 
        (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
            zhp->zfs_name, sdd->tosnap);
@@ -1469,7 +1478,15 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
        if (sdd->fromsnap == NULL || missingfrom)
                sdd->seenfrom = B_TRUE;
 
-       rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg);
+       if (!sdd->replicate && sdd->fromsnap != NULL)
+               min_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
+                   sdd->fromsnap);
+       if (!sdd->replicate && sdd->tosnap != NULL)
+               max_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name,
+                   sdd->tosnap);
+
+       rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg,
+           min_txg, max_txg);
        if (!sdd->seenfrom) {
                (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
                    "WARNING: could not send %s@%s:\n"
@@ -1948,8 +1965,8 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
 
                        err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
                            fromsnap, tosnap, flags->replicate, flags->raw,
-                           flags->verbose, flags->backup, flags->holds,
-                           flags->props, &fss, &fsavl);
+                           flags->replicate, flags->verbose, flags->backup,
+                           flags->holds, flags->props, &fss, &fsavl);
                        if (err)
                                goto err_out;
                        VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
@@ -2853,8 +2870,8 @@ again:
        VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0));
 
        if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
-           recursive, B_TRUE, B_FALSE, B_FALSE, B_FALSE, B_TRUE, &local_nv,
-           &local_avl)) != 0)
+           recursive, B_TRUE, recursive, B_FALSE, B_FALSE, B_FALSE, B_TRUE,
+           &local_nv, &local_avl)) != 0)
                return (error);
 
        /*
@@ -4287,8 +4304,8 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
                 */
                *cp = '\0';
                if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE, B_TRUE,
-                   B_FALSE, B_FALSE, B_FALSE, B_TRUE, &local_nv, &local_avl)
-                   == 0) {
+                   B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_TRUE, &local_nv,
+                   &local_avl) == 0) {
                        *cp = '@';
                        fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
                        fsavl_destroy(local_avl);
index ab40ae18556f8f6c8837c048e106c64b2cc097c8..047193c61412ef6678143f724cf83085f4c96384 100644 (file)
@@ -34,9 +34,9 @@
  * Copyright 2016 Toomas Soome <tsoome@me.com>
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
- * Copyright (c) 2017 Datto Inc. All rights reserved.
  * Copyright 2017 RackTop Systems.
  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
+ * Copyright (c) 2019 Datto Inc.
  */
 
 /*
@@ -2315,7 +2315,8 @@ top:
  * inputs:
  * zc_name             name of filesystem
  * zc_cookie           zap cursor
- * zc_nvlist_dst_size  size of buffer for property nvlist
+ * zc_nvlist_src       iteration range nvlist
+ * zc_nvlist_src_size  size of iteration range nvlist
  *
  * outputs:
  * zc_name             name of next snapshot
@@ -2326,8 +2327,23 @@ top:
 static int
 zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
 {
-       objset_t *os;
        int error;
+       objset_t *os, *ossnap;
+       dsl_dataset_t *ds;
+       uint64_t min_txg = 0, max_txg = 0;
+
+       if (zc->zc_nvlist_src_size != 0) {
+               nvlist_t *props = NULL;
+               error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+                   zc->zc_iflags, &props);
+               if (error != 0)
+                       return (error);
+               (void) nvlist_lookup_uint64(props, SNAP_ITER_MIN_TXG,
+                   &min_txg);
+               (void) nvlist_lookup_uint64(props, SNAP_ITER_MAX_TXG,
+                   &max_txg);
+               nvlist_free(props);
+       }
 
        error = dmu_objset_hold(zc->zc_name, FTAG, &os);
        if (error != 0) {
@@ -2344,26 +2360,52 @@ zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
                return (SET_ERROR(ESRCH));
        }
 
-       error = dmu_snapshot_list_next(os,
-           sizeof (zc->zc_name) - strlen(zc->zc_name),
-           zc->zc_name + strlen(zc->zc_name), &zc->zc_obj, &zc->zc_cookie,
-           NULL);
+       while (error == 0) {
+               if (issig(JUSTLOOKING) && issig(FORREAL)) {
+                       error = SET_ERROR(EINTR);
+                       break;
+               }
 
-       if (error == 0 && !zc->zc_simple) {
-               dsl_dataset_t *ds;
-               dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool;
+               error = dmu_snapshot_list_next(os,
+                   sizeof (zc->zc_name) - strlen(zc->zc_name),
+                   zc->zc_name + strlen(zc->zc_name), &zc->zc_obj,
+                   &zc->zc_cookie, NULL);
+               if (error == ENOENT) {
+                       error = SET_ERROR(ESRCH);
+                       break;
+               } else if (error != 0) {
+                       break;
+               }
 
-               error = dsl_dataset_hold_obj(dp, zc->zc_obj, FTAG, &ds);
-               if (error == 0) {
-                       objset_t *ossnap;
+               error = dsl_dataset_hold_obj(dmu_objset_pool(os), zc->zc_obj,
+                   FTAG, &ds);
+               if (error != 0)
+                       break;
 
-                       error = dmu_objset_from_ds(ds, &ossnap);
-                       if (error == 0)
-                               error = zfs_ioc_objset_stats_impl(zc, ossnap);
+               if ((min_txg != 0 && dsl_get_creationtxg(ds) < min_txg) ||
+                   (max_txg != 0 && dsl_get_creationtxg(ds) > max_txg)) {
                        dsl_dataset_rele(ds, FTAG);
+                       /* undo snapshot name append */
+                       *(strchr(zc->zc_name, '@') + 1) = '\0';
+                       /* skip snapshot */
+                       continue;
                }
-       } else if (error == ENOENT) {
-               error = SET_ERROR(ESRCH);
+
+               if (zc->zc_simple) {
+                       dsl_dataset_rele(ds, FTAG);
+                       break;
+               }
+
+               if ((error = dmu_objset_from_ds(ds, &ossnap)) != 0) {
+                       dsl_dataset_rele(ds, FTAG);
+                       break;
+               }
+               if ((error = zfs_ioc_objset_stats_impl(zc, ossnap)) != 0) {
+                       dsl_dataset_rele(ds, FTAG);
+                       break;
+               }
+               dsl_dataset_rele(ds, FTAG);
+               break;
        }
 
        dmu_objset_rele(os, FTAG);