From b300ce6507e43aba446ad81fbcac1799e8376179 Mon Sep 17 00:00:00 2001 From: Alek Pinchuk Date: Tue, 19 Feb 2019 18:11:43 -0500 Subject: [PATCH] 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. Signed-off-by: Alek Pinchuk --- cmd/zfs/zfs_iter.c | 2 +- cmd/zfs/zfs_main.c | 44 +++++++++++++-- include/libzfs.h | 6 +- include/sys/fs/zfs.h | 10 +++- lib/libzfs/libzfs_dataset.c | 11 +++- lib/libzfs/libzfs_iter.c | 20 +++++-- lib/libzfs/libzfs_sendrecv.c | 103 +++++++++++++++++++++++------------ module/zfs/zfs_ioctl.c | 77 ++++++++++++++++++++------ 8 files changed, 203 insertions(+), 70 deletions(-) diff --git a/cmd/zfs/zfs_iter.c b/cmd/zfs/zfs_iter.c index af4e4b4d2d7b..9917330263f4 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, NULL); 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 2017c9803e09..62a5b2e1eab4 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -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) { @@ -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 snapshtos 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,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); } @@ -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) { @@ -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; @@ -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); diff --git a/include/libzfs.h b/include/libzfs.h index 65b06f7a806c..a4c419ce2be2 100644 --- a/include/libzfs.h +++ b/include/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 *, + 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 *); diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 395d2e27f20f..c4537faf7020 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -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 */ @@ -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; @@ -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. * diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index be86e5692b0d..d2c9123ec670 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -4366,6 +4366,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); @@ -4376,7 +4377,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) diff --git a/lib/libzfs/libzfs_iter.c b/lib/libzfs/libzfs_iter.c index b1bdc4a6d9e3..24124447e496 100644 --- a/lib/libzfs/libzfs_iter.c +++ b/lib/libzfs/libzfs_iter.c @@ -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; @@ -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) { @@ -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; @@ -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); @@ -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 || @@ -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)); @@ -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; } diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 2aa0fd222514..df5e087fa3a5 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 * Copyright (c) 2018, loli10K . All rights reserved. - * Copyright (c) 2018 Datto Inc. + * Copyright (c) 2019 Datto Inc. */ #include @@ -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 */ @@ -843,7 +844,7 @@ static int send_iterate_fs(zfs_handle_t *zhp, void *arg) { send_data_t *sd = arg; - nvlist_t *nvfs = NULL, *nv = NULL; + nvlist_t *nvfs = NULL, *nv = NULL, *range_nvl = NULL; int rv = 0; uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid; uint64_t fromsnap_txg_save = sd->fromsnap_txg; @@ -888,10 +889,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 +901,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 +922,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 +942,39 @@ 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) { + range_nvl = fnvlist_alloc(); + fnvlist_add_uint64(range_nvl, SNAP_ITER_SKIP_TO_TXG, + fromsnap_txg_save); + } + if (!sd->replicate && tosnap_txg != 0) { + if (range_nvl == NULL) + range_nvl = fnvlist_alloc(); + fnvlist_add_uint64(range_nvl, SNAP_ITER_SKIP_AFTER_TXG, + sd->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, range_nvl); + fnvlist_free(range_nvl); + 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 +984,8 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg) 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 +993,9 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg) 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 +1012,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 +1451,8 @@ dump_filesystem(zfs_handle_t *zhp, void *arg) send_dump_data_t *sdd = arg; boolean_t missingfrom = B_FALSE; zfs_cmd_t zc = {"\0"}; + nvlist_t *range_nvl = NULL; + uint64_t txg; (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s", zhp->zfs_name, sdd->tosnap); @@ -1469,7 +1485,24 @@ 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) { + range_nvl = fnvlist_alloc(); + txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sdd->fromsnap); + if (txg != 0) + fnvlist_add_uint64(range_nvl, SNAP_ITER_SKIP_TO_TXG, + txg); + } + if (!sdd->replicate && sdd->tosnap != NULL) { + if (range_nvl == NULL) + range_nvl = fnvlist_alloc(); + txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sdd->tosnap); + if (txg != 0) + fnvlist_add_uint64(range_nvl, SNAP_ITER_SKIP_AFTER_TXG, + txg); + } + + rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg, range_nvl); + fnvlist_free(range_nvl); if (!sdd->seenfrom) { (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "WARNING: could not send %s@%s:\n" @@ -1948,8 +1981,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 +2886,8 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs, 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, B_FALSE, B_FALSE, B_FALSE, B_FALSE, B_TRUE, + &local_nv, &local_avl)) != 0) return (error); /* @@ -4287,8 +4320,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 f4aea57d445b..49ae716d906d 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -34,9 +34,9 @@ * Copyright 2016 Toomas Soome * Copyright (c) 2016 Actifio, Inc. All rights reserved. * Copyright (c) 2018, loli10K . 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) 2018 Datto Inc. */ /* @@ -2315,7 +2315,8 @@ zfs_ioc_dataset_list_next(zfs_cmd_t *zc) * inputs: * zc_name name of filesystem * zc_cookie zap cursor - * zc_nvlist_dst_size size of buffer for property nvlist + * zc_nvlist_dst property nvlist + * zc_nvlist_dst_size size of property nvlist * * outputs: * zc_name name of next snapshot @@ -2326,8 +2327,23 @@ zfs_ioc_dataset_list_next(zfs_cmd_t *zc) 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 skip_after = 0, skip_to = 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_SKIP_TO_TXG, + &skip_to); + (void) nvlist_lookup_uint64(props, SNAP_ITER_SKIP_AFTER_TXG, + &skip_after); + nvlist_free(props); + } error = dmu_objset_hold(zc->zc_name, FTAG, &os); if (error != 0) { @@ -2344,26 +2360,51 @@ 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; + if ((error = dsl_dataset_hold_obj(dmu_objset_pool(os), + zc->zc_obj, FTAG, &ds)) != 0) + break; - error = dmu_objset_from_ds(ds, &ossnap); - if (error == 0) - error = zfs_ioc_objset_stats_impl(zc, ossnap); + if ((skip_after != 0 && dsl_get_creationtxg(ds) > skip_after) || + (skip_to != 0 && dsl_get_creationtxg(ds) < skip_to)) { + 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; } - } else if (error == ENOENT) { - error = SET_ERROR(ESRCH); + + 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);