From 1af3a1121865a9caca8bac769b1845af9864edf3 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 26 Oct 2019 17:11:02 +0000 Subject: 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 Reviewed-by: Brian Behlendorf Reviewed by: Matt Ahrens Signed-off-by: Alek Pinchuk Closes #8077 zfsonlinux/zfs@4c0883fb4af0d5565459099b98fcf90ecbfa1ca1 MFC after: 2 weeks --- .../contrib/opensolaris/lib/libzfs/common/libzfs.h | 8 ++-- .../opensolaris/lib/libzfs/common/libzfs_dataset.c | 11 +++++- .../opensolaris/lib/libzfs/common/libzfs_iter.c | 36 ++++++++++++++--- .../lib/libzfs/common/libzfs_sendrecv.c | 45 +++++++++++++++------- 4 files changed, 76 insertions(+), 24 deletions(-) (limited to 'cddl/contrib/opensolaris/lib') diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h index 15b1d54e6341..c0e235476fed 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h @@ -28,7 +28,7 @@ * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2014 Integros [integros.com] * Copyright 2016 Nexenta Systems, Inc. - * Copyright (c) 2017 Datto Inc. + * Copyright (c) 2019 Datto Inc. */ #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_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 *); diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c index 76a71f39d987..b6a17c2c85c1 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c @@ -31,6 +31,7 @@ * Copyright 2017 Nexenta Systems, Inc. * Copyright 2016 Igor Kozhukhov * Copyright 2017-2018 RackTop Systems. + * Copyright (c) 2019 Datto Inc. */ #include @@ -4163,7 +4164,7 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) rollback_data_t cb = { 0 }; int err; 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; 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_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/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c index 6bca98816f7c..36138676e7db 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c @@ -24,6 +24,7 @@ * Copyright (c) 2013, 2015 by Delphix. All rights reserved. * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2019 Datto Inc. */ #include @@ -139,11 +140,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) @@ -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) 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) { @@ -165,10 +185,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); } @@ -276,7 +298,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; @@ -286,7 +309,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); @@ -389,7 +413,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 || @@ -429,7 +453,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)); @@ -495,7 +519,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/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c index 4360f96a0b9f..a4539f6d6e4b 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c @@ -28,6 +28,7 @@ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright (c) 2014 Integros [integros.com] * Copyright 2016 Igor Kozhukhov + * Copyright (c) 2019 Datto Inc. */ #include @@ -612,6 +613,7 @@ typedef struct send_data { const char *tosnap; boolean_t recursive; boolean_t verbose; + boolean_t replicate; /* * 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; nvlist_t *nvfs, *nv; 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; @@ -832,10 +835,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, @@ -855,14 +858,19 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg) nvlist_free(nv); /* 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; VERIFY(0 == nvlist_alloc(&sd->parent_snaps, 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, "snapprops", sd->snapprops)); - nvlist_free(sd->parent_snaps); - nvlist_free(sd->snapprops); + fnvlist_free(sd->parent_snaps); + fnvlist_free(sd->snapprops); /* add this fs to nvlist */ (void) snprintf(guidstring, sizeof (guidstring), @@ -886,11 +894,12 @@ out: static int gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, 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; - send_data_t sd = { 0 }; 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); if (zhp == NULL) @@ -902,6 +911,7 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, sd.tosnap = tosnap; sd.recursive = recursive; sd.verbose = verbose; + sd.replicate = replicate; if ((error = send_iterate_fs(zhp, &sd)) != 0) { nvlist_free(sd.fss); @@ -1338,6 +1348,7 @@ static int dump_filesystem(zfs_handle_t *zhp, void *arg) { int rv = 0; + uint64_t min_txg = 0, max_txg = 0; send_dump_data_t *sdd = arg; boolean_t missingfrom = B_FALSE; zfs_cmd_t zc = { 0 }; @@ -1373,7 +1384,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" @@ -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, fromsnap, tosnap, flags->replicate, flags->verbose, - &fss, &fsavl); + flags->replicate, &fss, &fsavl); if (err) goto err_out; VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); @@ -2477,7 +2496,7 @@ again: VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0)); 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); /* @@ -3554,7 +3573,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, */ *cp = '\0'; 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 = '@'; fs = fsavl_find(local_avl, drrb->drr_toguid, NULL); fsavl_destroy(local_avl); -- cgit v1.2.3