Print this page
3740 Poor ZFS send / receive performance due to snapshot hold / release processing
Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk>

*** 23,32 **** --- 23,33 ---- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2013 Martin Matuska. All rights reserved. + * Copyright (c) 2013 Steven Hartland. All rights reserved. */ #include <ctype.h> #include <errno.h> #include <libintl.h>
*** 4080,4143 **** static int zfs_hold_one(zfs_handle_t *zhp, void *arg) { struct holdarg *ha = arg; - zfs_handle_t *szhp; char name[ZFS_MAXNAMELEN]; int rv = 0; (void) snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, ha->snapname); ! szhp = make_dataset_handle(zhp->zfs_hdl, name); ! if (szhp) { fnvlist_add_string(ha->nvl, name, ha->tag); - zfs_close(szhp); - } if (ha->recursive) rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha); zfs_close(zhp); return (rv); } int zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, ! boolean_t recursive, boolean_t enoent_ok, int cleanup_fd) { int ret; struct holdarg ha; - nvlist_t *errors; - libzfs_handle_t *hdl = zhp->zfs_hdl; - char errbuf[1024]; - nvpair_t *elem; ha.nvl = fnvlist_alloc(); ha.snapname = snapname; ha.tag = tag; ha.recursive = recursive; (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); if (nvlist_next_nvpair(ha.nvl, NULL) == NULL) { fnvlist_free(ha.nvl); ret = ENOENT; - if (!enoent_ok) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot hold snapshot '%s@%s'"), zhp->zfs_name, snapname); ! (void) zfs_standard_error(hdl, ret, errbuf); ! } return (ret); } ! ret = lzc_hold(ha.nvl, cleanup_fd, &errors); fnvlist_free(ha.nvl); ! if (ret == 0) return (0); if (nvlist_next_nvpair(errors, NULL) == NULL) { /* no hold-specific errors */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot hold")); --- 4081,4154 ---- static int zfs_hold_one(zfs_handle_t *zhp, void *arg) { struct holdarg *ha = arg; char name[ZFS_MAXNAMELEN]; int rv = 0; (void) snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, ha->snapname); ! if (lzc_exists(name)) fnvlist_add_string(ha->nvl, name, ha->tag); if (ha->recursive) rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha); zfs_close(zhp); return (rv); } int zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, ! boolean_t recursive, int cleanup_fd) { int ret; struct holdarg ha; ha.nvl = fnvlist_alloc(); ha.snapname = snapname; ha.tag = tag; ha.recursive = recursive; (void) zfs_hold_one(zfs_handle_dup(zhp), &ha); if (nvlist_next_nvpair(ha.nvl, NULL) == NULL) { + char errbuf[1024]; + fnvlist_free(ha.nvl); ret = ENOENT; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot hold snapshot '%s@%s'"), zhp->zfs_name, snapname); ! (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf); return (ret); } ! ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl); fnvlist_free(ha.nvl); ! return (ret); ! } ! ! int ! zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds) ! { ! int ret; ! nvlist_t *errors; ! libzfs_handle_t *hdl = zhp->zfs_hdl; ! char errbuf[1024]; ! nvpair_t *elem; ! ! errors = NULL; ! ret = lzc_hold(holds, cleanup_fd, &errors); ! ! if (ret == 0) { ! /* There may be errors even in the success case. */ ! fnvlist_free(errors); return (0); + } if (nvlist_next_nvpair(errors, NULL) == NULL) { /* no hold-specific errors */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot hold"));
*** 4175,4222 **** (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); break; case EEXIST: (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); break; - case ENOENT: - if (enoent_ok) - return (ENOENT); - /* FALLTHROUGH */ default: (void) zfs_standard_error(hdl, fnvpair_value_int32(elem), errbuf); } } fnvlist_free(errors); return (ret); } - struct releasearg { - nvlist_t *nvl; - const char *snapname; - const char *tag; - boolean_t recursive; - }; - static int zfs_release_one(zfs_handle_t *zhp, void *arg) { struct holdarg *ha = arg; - zfs_handle_t *szhp; char name[ZFS_MAXNAMELEN]; int rv = 0; (void) snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, ha->snapname); ! szhp = make_dataset_handle(zhp->zfs_hdl, name); ! if (szhp) { nvlist_t *holds = fnvlist_alloc(); fnvlist_add_boolean(holds, ha->tag); fnvlist_add_nvlist(ha->nvl, name, holds); ! zfs_close(szhp); } if (ha->recursive) rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); zfs_close(zhp); --- 4186,4220 ---- (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); break; case EEXIST: (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf); break; default: (void) zfs_standard_error(hdl, fnvpair_value_int32(elem), errbuf); } } fnvlist_free(errors); return (ret); } static int zfs_release_one(zfs_handle_t *zhp, void *arg) { struct holdarg *ha = arg; char name[ZFS_MAXNAMELEN]; int rv = 0; (void) snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, ha->snapname); ! if (lzc_exists(name)) { nvlist_t *holds = fnvlist_alloc(); fnvlist_add_boolean(holds, ha->tag); fnvlist_add_nvlist(ha->nvl, name, holds); ! fnvlist_free(holds); } if (ha->recursive) rv = zfs_iter_filesystems(zhp, zfs_release_one, ha); zfs_close(zhp);
*** 4249,4263 **** zhp->zfs_name, snapname); (void) zfs_standard_error(hdl, ret, errbuf); return (ret); } ret = lzc_release(ha.nvl, &errors); fnvlist_free(ha.nvl); ! if (ret == 0) return (0); if (nvlist_next_nvpair(errors, NULL) == NULL) { /* no hold-specific errors */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot release")); --- 4247,4265 ---- zhp->zfs_name, snapname); (void) zfs_standard_error(hdl, ret, errbuf); return (ret); } + errors = NULL; ret = lzc_release(ha.nvl, &errors); fnvlist_free(ha.nvl); ! if (ret == 0) { ! /* There may be errors even in the success case. */ ! fnvlist_free(errors); return (0); + } if (nvlist_next_nvpair(errors, NULL) == NULL) { /* no hold-specific errors */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot release"));