1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-11 09:50:12 +00:00

MFZoL: Avoid retrieving unused snapshot props

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
zfsonlinux/zfs@4c0883fb4a

MFC after:	2 weeks
This commit is contained in:
Alan Somers 2019-10-26 17:11:02 +00:00
parent c571e05c2c
commit 1af3a11218
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=354116
8 changed files with 183 additions and 55 deletions

View File

@ -139,7 +139,7 @@ zfs_callback(zfs_handle_t *zhp, void *data)
ZFS_TYPE_BOOKMARK)) == 0) && include_snaps) ZFS_TYPE_BOOKMARK)) == 0) && include_snaps)
(void) zfs_iter_snapshots(zhp, (void) zfs_iter_snapshots(zhp,
(cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback, (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback,
data); data, 0, 0);
if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks) ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks)
(void) zfs_iter_bookmarks(zhp, zfs_callback, data); (void) zfs_iter_bookmarks(zhp, zfs_callback, data);

View File

@ -30,7 +30,7 @@
* Copyright (c) 2014 Integros [integros.com] * Copyright (c) 2014 Integros [integros.com]
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
* Copyright 2016 Nexenta Systems, Inc. * Copyright 2016 Nexenta Systems, Inc.
* Copyright (c) 2018 Datto Inc. * Copyright (c) 2019 Datto Inc.
*/ */
#include <assert.h> #include <assert.h>
@ -1174,7 +1174,7 @@ destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
int err = 0; int err = 0;
assert(cb->cb_firstsnap == NULL); assert(cb->cb_firstsnap == NULL);
assert(cb->cb_prevsnap == 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) { if (cb->cb_firstsnap != NULL) {
uint64_t used = 0; uint64_t used = 0;
if (err == 0) { if (err == 0) {
@ -3437,6 +3437,7 @@ zfs_do_promote(int argc, char **argv)
*/ */
typedef struct rollback_cbdata { typedef struct rollback_cbdata {
uint64_t cb_create; uint64_t cb_create;
uint8_t cb_younger_ds_printed;
boolean_t cb_first; boolean_t cb_first;
int cb_doclones; int cb_doclones;
char *cb_target; char *cb_target;
@ -3467,15 +3468,20 @@ rollback_check_dependent(zfs_handle_t *zhp, void *data)
} }
/* /*
* Report any snapshots more recent than the one specified. Used when '-r' is * Report some snapshots/bookmarks more recent than the one specified.
* not specified. We reuse this same callback for the snapshot dependents - if * Used when '-r' is not specified. We reuse this same callback for the
* 'cb_dependent' is set, then this is a dependent and we should report it * snapshot dependents - if 'cb_dependent' is set, then this is a
* without checking the transaction group. * dependent and we should report it without checking the transaction group.
*/ */
static int static int
rollback_check(zfs_handle_t *zhp, void *data) rollback_check(zfs_handle_t *zhp, void *data)
{ {
rollback_cbdata_t *cbp = 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) { if (cbp->cb_doclones) {
zfs_close(zhp); zfs_close(zhp);
@ -3504,9 +3510,24 @@ rollback_check(zfs_handle_t *zhp, void *data)
} else { } else {
(void) fprintf(stderr, "%s\n", (void) fprintf(stderr, "%s\n",
zfs_get_name(zhp)); zfs_get_name(zhp));
cbp->cb_younger_ds_printed++;
} }
} }
zfs_close(zhp); 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); return (0);
} }
@ -3520,6 +3541,7 @@ zfs_do_rollback(int argc, char **argv)
zfs_handle_t *zhp, *snap; zfs_handle_t *zhp, *snap;
char parentname[ZFS_MAX_DATASET_NAME_LEN]; char parentname[ZFS_MAX_DATASET_NAME_LEN];
char *delim; char *delim;
uint64_t min_txg = 0;
/* check options */ /* check options */
while ((c = getopt(argc, argv, "rRf")) != -1) { while ((c = getopt(argc, argv, "rRf")) != -1) {
@ -3575,7 +3597,12 @@ zfs_do_rollback(int argc, char **argv)
cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
cb.cb_first = B_TRUE; cb.cb_first = B_TRUE;
cb.cb_error = 0; 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; goto out;
if ((ret = zfs_iter_bookmarks(zhp, rollback_check, &cb)) != 0) if ((ret = zfs_iter_bookmarks(zhp, rollback_check, &cb)) != 0)
goto out; goto out;

View File

@ -28,7 +28,7 @@
* Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Integros [integros.com] * Copyright (c) 2014 Integros [integros.com]
* Copyright 2016 Nexenta Systems, Inc. * Copyright 2016 Nexenta Systems, Inc.
* Copyright (c) 2017 Datto Inc. * Copyright (c) 2019 Datto Inc.
*/ */
#ifndef _LIBZFS_H #ifndef _LIBZFS_H
@ -570,8 +570,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_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_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_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(zfs_handle_t *, boolean_t, zfs_iter_f, void *,
extern int zfs_iter_snapshots_sorted(zfs_handle_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_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_bookmarks(zfs_handle_t *, zfs_iter_f, void *);

View File

@ -31,6 +31,7 @@
* Copyright 2017 Nexenta Systems, Inc. * Copyright 2017 Nexenta Systems, Inc.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright 2017-2018 RackTop Systems. * Copyright 2017-2018 RackTop Systems.
* Copyright (c) 2019 Datto Inc.
*/ */
#include <ctype.h> #include <ctype.h>
@ -4163,7 +4164,7 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
rollback_data_t cb = { 0 }; rollback_data_t cb = { 0 };
int err; int err;
boolean_t restore_resv = 0; boolean_t restore_resv = 0;
uint64_t old_volsize = 0, new_volsize; uint64_t min_txg = 0, old_volsize = 0, new_volsize;
zfs_prop_t resv_prop; zfs_prop_t resv_prop;
assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
@ -4175,7 +4176,13 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
cb.cb_force = force; cb.cb_force = force;
cb.cb_target = snap->zfs_name; cb.cb_target = snap->zfs_name;
cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); 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); (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
if (cb.cb_error) if (cb.cb_error)

View File

@ -24,6 +24,7 @@
* Copyright (c) 2013, 2015 by Delphix. All rights reserved. * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved. * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2019 Datto Inc.
*/ */
#include <stdio.h> #include <stdio.h>
@ -139,11 +140,12 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
*/ */
int int
zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func, 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_cmd_t zc = { 0 };
zfs_handle_t *nzhp; zfs_handle_t *nzhp;
int ret; int ret;
nvlist_t *range_nvl = NULL;
if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT || if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
zhp->zfs_type == ZFS_TYPE_BOOKMARK) zhp->zfs_type == ZFS_TYPE_BOOKMARK)
@ -153,6 +155,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) if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
return (-1); 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, while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
&zc)) == 0) { &zc)) == 0) {
@ -165,10 +185,12 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
if ((ret = func(nzhp, data)) != 0) { if ((ret = func(nzhp, data)) != 0) {
zcmd_free_nvlists(&zc); zcmd_free_nvlists(&zc);
fnvlist_free(range_nvl);
return (ret); return (ret);
} }
} }
zcmd_free_nvlists(&zc); zcmd_free_nvlists(&zc);
fnvlist_free(range_nvl);
return ((ret < 0) ? ret : 0); return ((ret < 0) ? ret : 0);
} }
@ -276,7 +298,8 @@ zfs_snapshot_compare(const void *larg, const void *rarg)
} }
int 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; int ret = 0;
zfs_node_t *node; zfs_node_t *node;
@ -286,7 +309,8 @@ zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data)
avl_create(&avl, zfs_snapshot_compare, avl_create(&avl, zfs_snapshot_compare,
sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode)); 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)) for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
ret |= callback(node->zn_handle, data); ret |= callback(node->zn_handle, data);
@ -389,7 +413,7 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
} }
err = zfs_iter_snapshots_sorted(fs_zhp, err = zfs_iter_snapshots_sorted(fs_zhp,
snapspec_cb, &ssa); snapspec_cb, &ssa, 0, 0);
if (ret == 0) if (ret == 0)
ret = err; ret = err;
if (ret == 0 && (!ssa.ssa_seenfirst || if (ret == 0 && (!ssa.ssa_seenfirst ||
@ -429,7 +453,7 @@ zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
{ {
int ret; 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 (ret);
return (zfs_iter_filesystems(zhp, func, data)); return (zfs_iter_filesystems(zhp, func, data));
@ -495,7 +519,7 @@ iter_dependents_cb(zfs_handle_t *zhp, void *arg)
err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida); err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida);
if (err == 0) { if (err == 0) {
err = zfs_iter_snapshots(zhp, B_FALSE, err = zfs_iter_snapshots(zhp, B_FALSE,
iter_dependents_cb, ida); iter_dependents_cb, ida, 0, 0);
} }
ida->stack = isf.next; ida->stack = isf.next;
} }

View File

@ -28,6 +28,7 @@
* Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright (c) 2014 Integros [integros.com] * Copyright (c) 2014 Integros [integros.com]
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright (c) 2019 Datto Inc.
*/ */
#include <assert.h> #include <assert.h>
@ -612,6 +613,7 @@ typedef struct send_data {
const char *tosnap; const char *tosnap;
boolean_t recursive; boolean_t recursive;
boolean_t verbose; boolean_t verbose;
boolean_t replicate;
/* /*
* The header nvlist is of the following format: * The header nvlist is of the following format:
@ -789,6 +791,7 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
send_data_t *sd = arg; send_data_t *sd = arg;
nvlist_t *nvfs, *nv; nvlist_t *nvfs, *nv;
int rv = 0; int rv = 0;
uint64_t min_txg = 0, max_txg = 0;
uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid; uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;
uint64_t fromsnap_txg_save = sd->fromsnap_txg; uint64_t fromsnap_txg_save = sd->fromsnap_txg;
uint64_t tosnap_txg_save = sd->tosnap_txg; uint64_t tosnap_txg_save = sd->tosnap_txg;
@ -832,10 +835,10 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
goto out; goto out;
} }
VERIFY(0 == nvlist_alloc(&nvfs, NV_UNIQUE_NAME, 0)); nvfs = fnvlist_alloc();
VERIFY(0 == nvlist_add_string(nvfs, "name", zhp->zfs_name)); fnvlist_add_string(nvfs, "name", zhp->zfs_name);
VERIFY(0 == nvlist_add_uint64(nvfs, "parentfromsnap", fnvlist_add_uint64(nvfs, "parentfromsnap",
sd->parent_fromsnap_guid)); sd->parent_fromsnap_guid);
if (zhp->zfs_dmustats.dds_origin[0]) { if (zhp->zfs_dmustats.dds_origin[0]) {
zfs_handle_t *origin = zfs_open(zhp->zfs_hdl, zfs_handle_t *origin = zfs_open(zhp->zfs_hdl,
@ -855,14 +858,19 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
nvlist_free(nv); nvlist_free(nv);
/* iterate over snaps, and set sd->parent_fromsnap_guid */ /* iterate over snaps, and set sd->parent_fromsnap_guid */
if (!sd->replicate && fromsnap_txg != 0)
min_txg = fromsnap_txg;
if (!sd->replicate && tosnap_txg != 0)
max_txg = tosnap_txg;
sd->parent_fromsnap_guid = 0; sd->parent_fromsnap_guid = 0;
VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0)); VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0)); VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
(void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd); (void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd,
min_txg, max_txg);
VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps)); VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops)); VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
nvlist_free(sd->parent_snaps); fnvlist_free(sd->parent_snaps);
nvlist_free(sd->snapprops); fnvlist_free(sd->snapprops);
/* add this fs to nvlist */ /* add this fs to nvlist */
(void) snprintf(guidstring, sizeof (guidstring), (void) snprintf(guidstring, sizeof (guidstring),
@ -886,11 +894,12 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
static int static int
gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
const char *tosnap, boolean_t recursive, boolean_t verbose, const char *tosnap, boolean_t recursive, boolean_t verbose,
nvlist_t **nvlp, avl_tree_t **avlp) boolean_t replicate, nvlist_t **nvlp, avl_tree_t **avlp)
{ {
zfs_handle_t *zhp; zfs_handle_t *zhp;
send_data_t sd = { 0 };
int error; int error;
uint64_t min_txg = 0, max_txg = 0;
send_data_t sd = { 0 };
zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
if (zhp == NULL) if (zhp == NULL)
@ -902,6 +911,7 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
sd.tosnap = tosnap; sd.tosnap = tosnap;
sd.recursive = recursive; sd.recursive = recursive;
sd.verbose = verbose; sd.verbose = verbose;
sd.replicate = replicate;
if ((error = send_iterate_fs(zhp, &sd)) != 0) { if ((error = send_iterate_fs(zhp, &sd)) != 0) {
nvlist_free(sd.fss); nvlist_free(sd.fss);
@ -1338,6 +1348,7 @@ static int
dump_filesystem(zfs_handle_t *zhp, void *arg) dump_filesystem(zfs_handle_t *zhp, void *arg)
{ {
int rv = 0; int rv = 0;
uint64_t min_txg = 0, max_txg = 0;
send_dump_data_t *sdd = arg; send_dump_data_t *sdd = arg;
boolean_t missingfrom = B_FALSE; boolean_t missingfrom = B_FALSE;
zfs_cmd_t zc = { 0 }; zfs_cmd_t zc = { 0 };
@ -1373,7 +1384,15 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
if (sdd->fromsnap == NULL || missingfrom) if (sdd->fromsnap == NULL || missingfrom)
sdd->seenfrom = B_TRUE; 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) { if (!sdd->seenfrom) {
(void) fprintf(stderr, dgettext(TEXT_DOMAIN, (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
"WARNING: could not send %s@%s:\n" "WARNING: could not send %s@%s:\n"
@ -1834,7 +1853,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
fromsnap, tosnap, flags->replicate, flags->verbose, fromsnap, tosnap, flags->replicate, flags->verbose,
&fss, &fsavl); flags->replicate, &fss, &fsavl);
if (err) if (err)
goto err_out; goto err_out;
VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
@ -2477,7 +2496,7 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0)); VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0));
if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL, if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
recursive, B_FALSE, &local_nv, &local_avl)) != 0) recursive, B_FALSE, B_FALSE, &local_nv, &local_avl)) != 0)
return (error); return (error);
/* /*
@ -3554,7 +3573,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
*/ */
*cp = '\0'; *cp = '\0';
if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, B_FALSE, if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, B_FALSE,
B_FALSE, &local_nv, &local_avl) == 0) { B_FALSE, B_FALSE, &local_nv, &local_avl) == 0) {
*cp = '@'; *cp = '@';
fs = fsavl_find(local_avl, drrb->drr_toguid, NULL); fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
fsavl_destroy(local_avl); fsavl_destroy(local_avl);

View File

@ -33,7 +33,7 @@
* Copyright (c) 2014 Integros [integros.com] * Copyright (c) 2014 Integros [integros.com]
* Copyright 2016 Toomas Soome <tsoome@me.com> * Copyright 2016 Toomas Soome <tsoome@me.com>
* Copyright 2017 RackTop Systems. * Copyright 2017 RackTop Systems.
* Copyright (c) 2017 Datto Inc. * Copyright (c) 2019 Datto Inc.
*/ */
/* /*
@ -2345,7 +2345,8 @@ dataset_name_hidden(const char *name)
* inputs: * inputs:
* zc_name name of filesystem * zc_name name of filesystem
* zc_cookie zap cursor * 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: * outputs:
* zc_name name of next filesystem * zc_name name of next filesystem
@ -2414,8 +2415,23 @@ zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
static int static int
zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
{ {
objset_t *os;
int error; 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); error = dmu_objset_hold(zc->zc_name, FTAG, &os);
if (error != 0) { if (error != 0) {
@ -2432,26 +2448,52 @@ zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
return (SET_ERROR(ESRCH)); return (SET_ERROR(ESRCH));
} }
error = dmu_snapshot_list_next(os, while (error == 0) {
sizeof (zc->zc_name) - strlen(zc->zc_name), if (issig(JUSTLOOKING) && issig(FORREAL)) {
zc->zc_name + strlen(zc->zc_name), &zc->zc_obj, &zc->zc_cookie, error = SET_ERROR(EINTR);
NULL); break;
if (error == 0 && !zc->zc_simple) {
dsl_dataset_t *ds;
dsl_pool_t *dp = os->os_dsl_dataset->ds_dir->dd_pool;
error = dsl_dataset_hold_obj(dp, zc->zc_obj, FTAG, &ds);
if (error == 0) {
objset_t *ossnap;
error = dmu_objset_from_ds(ds, &ossnap);
if (error == 0)
error = zfs_ioc_objset_stats_impl(zc, ossnap);
dsl_dataset_rele(ds, FTAG);
} }
} else if (error == ENOENT) {
error = 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);
if (error == ENOENT) {
error = SET_ERROR(ESRCH);
break;
} else if (error != 0) {
break;
}
error = dsl_dataset_hold_obj(dmu_objset_pool(os), zc->zc_obj,
FTAG, &ds);
if (error != 0)
break;
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;
}
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); dmu_objset_rele(os, FTAG);

View File

@ -26,7 +26,7 @@
* Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>. All rights reserved. * Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2014 Integros [integros.com] * Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 Joyent, Inc. * Copyright 2017 Joyent, Inc.
* Copyright (c) 2017 Datto Inc. * Copyright (c) 2019 Datto Inc.
*/ */
/* Portions Copyright 2010 Robert Milkowski */ /* Portions Copyright 2010 Robert Milkowski */
@ -1123,6 +1123,13 @@ typedef enum {
#define ZCP_DEFAULT_MEMLIMIT (10 * 1024 * 1024) #define ZCP_DEFAULT_MEMLIMIT (10 * 1024 * 1024)
#define ZCP_MAX_MEMLIMIT (10 * ZCP_DEFAULT_MEMLIMIT) #define ZCP_MAX_MEMLIMIT (10 * ZCP_DEFAULT_MEMLIMIT)
/*
* 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"
/* /*
* Sysevent payload members. ZFS will generate the following sysevents with the * Sysevent payload members. ZFS will generate the following sysevents with the
* given payloads: * given payloads: