summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/zfs/zfs_iter.c2
-rw-r--r--cmd/zfs/zfs_main.c41
-rw-r--r--include/libzfs.h8
-rw-r--r--include/sys/fs/zfs.h11
-rw-r--r--lib/libzfs/libzfs_dataset.c11
-rw-r--r--lib/libzfs/libzfs_iter.c37
-rw-r--r--lib/libzfs/libzfs_sendrecv.c85
-rw-r--r--module/zfs/zfs_ioctl.c78
8 files changed, 199 insertions, 74 deletions
diff --git a/cmd/zfs/zfs_iter.c b/cmd/zfs/zfs_iter.c
index af4e4b4d2..9ad691938 100644
--- a/cmd/zfs/zfs_iter.c
+++ b/cmd/zfs/zfs_iter.c
@@ -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);
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c
index 12a5cf6cf..21c4d4334 100644
--- a/cmd/zfs/zfs_main.c
+++ b/cmd/zfs/zfs_main.c
@@ -27,7 +27,7 @@
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright 2016 Igor Kozhukhov <[email protected]>.
* 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;
diff --git a/include/libzfs.h b/include/libzfs.h
index 65b06f7a8..3405bb99b 100644
--- a/include/libzfs.h
+++ b/include/libzfs.h
@@ -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 *);
diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h
index 8a86480a6..c4d26eb87 100644
--- a/include/sys/fs/zfs.h
+++ b/include/sys/fs/zfs.h
@@ -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;
@@ -1124,6 +1124,13 @@ typedef enum {
} 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.
*
* These numbers cannot change over time. New ioctl numbers must be appended.
diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c
index 0537b631e..de94021a6 100644
--- a/lib/libzfs/libzfs_dataset.c
+++ b/lib/libzfs/libzfs_dataset.c
@@ -30,7 +30,7 @@
* Copyright 2017 Nexenta Systems, Inc.
* Copyright 2016 Igor Kozhukhov <[email protected]>
* 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)
diff --git a/lib/libzfs/libzfs_iter.c b/lib/libzfs/libzfs_iter.c
index b1bdc4a6d..e765a7ee7 100644
--- a/lib/libzfs/libzfs_iter.c
+++ b/lib/libzfs/libzfs_iter.c
@@ -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;
}
diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
index 2aa0fd222..8096089f6 100644
--- a/lib/libzfs/libzfs_sendrecv.c
+++ b/lib/libzfs/libzfs_sendrecv.c
@@ -29,7 +29,7 @@
* Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright 2016 Igor Kozhukhov <[email protected]>
* Copyright (c) 2018, loli10K <[email protected]>. 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);
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index ab40ae185..047193c61 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -34,9 +34,9 @@
* Copyright 2016 Toomas Soome <[email protected]>
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
* Copyright (c) 2018, loli10K <[email protected]>. 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);