Skip to content

Commit

Permalink
avoid retrieving unused snapshot props
Browse files Browse the repository at this point in the history
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.

Signed-off-by: Alek Pinchuk <apinchuk@datto.com>
  • Loading branch information
alek-p committed Feb 7, 2019
1 parent 0902c45 commit 6cc638c
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 63 deletions.
2 changes: 1 addition & 1 deletion cmd/zfs/zfs_iter.c
Expand Up @@ -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, NULL);
if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks)
(void) zfs_iter_bookmarks(zhp, zfs_callback, data);
Expand Down
44 changes: 38 additions & 6 deletions cmd/zfs/zfs_main.c
Expand Up @@ -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, NULL);
if (cb->cb_firstsnap != NULL) {
uint64_t used = 0;
if (err == 0) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 snapshtos and/or bookmarks to display before
* we stop the iteration
*/
const uint8_t max_younger = 32;

if (cbp->cb_doclones) {
zfs_close(zhp);
Expand Down Expand Up @@ -3649,9 +3655,25 @@ 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("these are the first %d "
"snapshots and/or bookmarks following %s\n"),
max_younger, cbp->cb_target);
return (-1);
}
return (0);
}

Expand All @@ -3665,6 +3687,7 @@ zfs_do_rollback(int argc, char **argv)
zfs_handle_t *zhp, *snap;
char parentname[ZFS_MAX_DATASET_NAME_LEN];
char *delim;
nvlist_t *range_nvl = NULL;

/* check options */
while ((c = getopt(argc, argv, "rRf")) != -1) {
Expand Down Expand Up @@ -3720,7 +3743,15 @@ 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) {
range_nvl = fnvlist_alloc();
fnvlist_add_uint64(range_nvl, SNAP_ITER_SKIP_TO_TXG,
cb.cb_create);
}

if ((ret = zfs_iter_snapshots(zhp, B_FALSE, rollback_check, &cb,
range_nvl)) != 0)
goto out;
if ((ret = zfs_iter_bookmarks(zhp, rollback_check, &cb)) != 0)
goto out;
Expand All @@ -3734,6 +3765,7 @@ zfs_do_rollback(int argc, char **argv)
ret = zfs_rollback(zhp, snap, force);

out:
nvlist_free(range_nvl);
zfs_close(snap);
zfs_close(zhp);

Expand Down
6 changes: 4 additions & 2 deletions include/libzfs.h
Expand Up @@ -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_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 *,
nvlist_t *);
extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *,
nvlist_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 *);
Expand Down
10 changes: 9 additions & 1 deletion include/sys/fs/zfs.h
Expand Up @@ -27,6 +27,7 @@
* Copyright (c) 2014 Integros [integros.com]
* Copyright (c) 2017 Datto Inc.
* Copyright (c) 2017, Intel Corporation.
* Copyright (c) 2018 Datto Inc.
*/

/* Portions Copyright 2010 Robert Milkowski */
Expand Down Expand Up @@ -1076,7 +1077,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;
Expand Down Expand Up @@ -1123,6 +1124,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_SKIP_AFTER_TXG "snap_iter_skip_after_txg"
#define SNAP_ITER_SKIP_TO_TXG "snap_iter_skip_to_txg"

/*
* /dev/zfs ioctl numbers.
*
Expand Down
11 changes: 10 additions & 1 deletion lib/libzfs/libzfs_dataset.c
Expand Up @@ -4371,6 +4371,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 };
nvlist_t *range = NULL;

assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
zhp->zfs_type == ZFS_TYPE_VOLUME);
Expand All @@ -4381,7 +4382,15 @@ 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) {
range = fnvlist_alloc();
fnvlist_add_uint64(range, SNAP_ITER_SKIP_TO_TXG, cb.cb_create);
}

(void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb, range);
nvlist_free(range);

(void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);

if (cb.cb_error)
Expand Down
20 changes: 14 additions & 6 deletions lib/libzfs/libzfs_iter.c
Expand Up @@ -141,7 +141,7 @@ 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, nvlist_t *range_nvl)
{
zfs_cmd_t zc = {"\0"};
zfs_handle_t *nzhp;
Expand All @@ -155,6 +155,13 @@ 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 (range_nvl != NULL &&
zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, range_nvl) != 0) {
zcmd_free_nvlists(&zc);
return (-1);
}

while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
&zc)) == 0) {

Expand Down Expand Up @@ -282,7 +289,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,
nvlist_t *range_nvl)
{
int ret = 0;
zfs_node_t *node;
Expand All @@ -292,7 +300,7 @@ 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, range_nvl);

for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
ret |= callback(node->zn_handle, data);
Expand Down Expand Up @@ -395,7 +403,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, NULL);
if (ret == 0)
ret = err;
if (ret == 0 && (!ssa.ssa_seenfirst ||
Expand Down Expand Up @@ -435,7 +443,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, NULL)) != 0)
return (ret);

return (zfs_iter_filesystems(zhp, func, data));
Expand Down Expand Up @@ -501,7 +509,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, NULL);
ida->stack = isf.next;
}

Expand Down

0 comments on commit 6cc638c

Please sign in to comment.