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

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libzfs/common/libzfs_dataset.c
          +++ new/usr/src/lib/libzfs/common/libzfs_dataset.c
↓ open down ↓ 17 lines elided ↑ open up ↑
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright (c) 2012 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
  26   26   * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
  27   27   * Copyright (c) 2013 Martin Matuska. All rights reserved.
       28 + * Copyright (c) 2013 Steven Hartland. All rights reserved.
  28   29   */
  29   30  
  30   31  #include <ctype.h>
  31   32  #include <errno.h>
  32   33  #include <libintl.h>
  33   34  #include <math.h>
  34   35  #include <stdio.h>
  35   36  #include <stdlib.h>
  36   37  #include <strings.h>
  37   38  #include <unistd.h>
↓ open down ↓ 4037 lines elided ↑ open up ↑
4075 4076          nvlist_t *nvl;
4076 4077          const char *snapname;
4077 4078          const char *tag;
4078 4079          boolean_t recursive;
4079 4080  };
4080 4081  
4081 4082  static int
4082 4083  zfs_hold_one(zfs_handle_t *zhp, void *arg)
4083 4084  {
4084 4085          struct holdarg *ha = arg;
4085      -        zfs_handle_t *szhp;
4086 4086          char name[ZFS_MAXNAMELEN];
4087 4087          int rv = 0;
4088 4088  
4089 4089          (void) snprintf(name, sizeof (name),
4090 4090              "%s@%s", zhp->zfs_name, ha->snapname);
4091 4091  
4092      -        szhp = make_dataset_handle(zhp->zfs_hdl, name);
4093      -        if (szhp) {
     4092 +        if (lzc_exists(name))
4094 4093                  fnvlist_add_string(ha->nvl, name, ha->tag);
4095      -                zfs_close(szhp);
4096      -        }
4097 4094  
4098 4095          if (ha->recursive)
4099 4096                  rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4100 4097          zfs_close(zhp);
4101 4098          return (rv);
4102 4099  }
4103 4100  
4104 4101  int
4105 4102  zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4106      -    boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
     4103 +    boolean_t recursive, int cleanup_fd)
4107 4104  {
4108 4105          int ret;
4109 4106          struct holdarg ha;
4110      -        nvlist_t *errors;
4111      -        libzfs_handle_t *hdl = zhp->zfs_hdl;
4112      -        char errbuf[1024];
4113      -        nvpair_t *elem;
4114 4107  
4115 4108          ha.nvl = fnvlist_alloc();
4116 4109          ha.snapname = snapname;
4117 4110          ha.tag = tag;
4118 4111          ha.recursive = recursive;
4119 4112          (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4120 4113  
4121 4114          if (nvlist_next_nvpair(ha.nvl, NULL) == NULL) {
     4115 +                char errbuf[1024];
     4116 +
4122 4117                  fnvlist_free(ha.nvl);
4123 4118                  ret = ENOENT;
4124      -                if (!enoent_ok) {
4125      -                        (void) snprintf(errbuf, sizeof (errbuf),
4126      -                            dgettext(TEXT_DOMAIN,
4127      -                            "cannot hold snapshot '%s@%s'"),
4128      -                            zhp->zfs_name, snapname);
4129      -                        (void) zfs_standard_error(hdl, ret, errbuf);
4130      -                }
     4119 +                (void) snprintf(errbuf, sizeof (errbuf),
     4120 +                    dgettext(TEXT_DOMAIN,
     4121 +                    "cannot hold snapshot '%s@%s'"),
     4122 +                    zhp->zfs_name, snapname);
     4123 +                (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
4131 4124                  return (ret);
4132 4125          }
4133 4126  
4134      -        ret = lzc_hold(ha.nvl, cleanup_fd, &errors);
     4127 +        ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
4135 4128          fnvlist_free(ha.nvl);
4136 4129  
4137      -        if (ret == 0)
     4130 +        return (ret);
     4131 +}
     4132 +
     4133 +int
     4134 +zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
     4135 +{
     4136 +        int ret;
     4137 +        nvlist_t *errors;
     4138 +        libzfs_handle_t *hdl = zhp->zfs_hdl;
     4139 +        char errbuf[1024];
     4140 +        nvpair_t *elem;
     4141 +
     4142 +        errors = NULL;
     4143 +        ret = lzc_hold(holds, cleanup_fd, &errors);
     4144 +
     4145 +        if (ret == 0) {
     4146 +                /* There may be errors even in the success case. */
     4147 +                fnvlist_free(errors);
4138 4148                  return (0);
     4149 +        }
4139 4150  
4140 4151          if (nvlist_next_nvpair(errors, NULL) == NULL) {
4141 4152                  /* no hold-specific errors */
4142 4153                  (void) snprintf(errbuf, sizeof (errbuf),
4143 4154                      dgettext(TEXT_DOMAIN, "cannot hold"));
4144 4155                  switch (ret) {
4145 4156                  case ENOTSUP:
4146 4157                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4147 4158                              "pool must be upgraded"));
4148 4159                          (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
↓ open down ↓ 21 lines elided ↑ open up ↑
4170 4181                           * up being slightly too long.
4171 4182                           */
4172 4183                          (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4173 4184                          break;
4174 4185                  case EINVAL:
4175 4186                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4176 4187                          break;
4177 4188                  case EEXIST:
4178 4189                          (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4179 4190                          break;
4180      -                case ENOENT:
4181      -                        if (enoent_ok)
4182      -                                return (ENOENT);
4183      -                        /* FALLTHROUGH */
4184 4191                  default:
4185 4192                          (void) zfs_standard_error(hdl,
4186 4193                              fnvpair_value_int32(elem), errbuf);
4187 4194                  }
4188 4195          }
4189 4196  
4190 4197          fnvlist_free(errors);
4191 4198          return (ret);
4192 4199  }
4193 4200  
4194      -struct releasearg {
4195      -        nvlist_t *nvl;
4196      -        const char *snapname;
4197      -        const char *tag;
4198      -        boolean_t recursive;
4199      -};
4200      -
4201 4201  static int
4202 4202  zfs_release_one(zfs_handle_t *zhp, void *arg)
4203 4203  {
4204 4204          struct holdarg *ha = arg;
4205      -        zfs_handle_t *szhp;
4206 4205          char name[ZFS_MAXNAMELEN];
4207 4206          int rv = 0;
4208 4207  
4209 4208          (void) snprintf(name, sizeof (name),
4210 4209              "%s@%s", zhp->zfs_name, ha->snapname);
4211 4210  
4212      -        szhp = make_dataset_handle(zhp->zfs_hdl, name);
4213      -        if (szhp) {
     4211 +        if (lzc_exists(name)) {
4214 4212                  nvlist_t *holds = fnvlist_alloc();
4215 4213                  fnvlist_add_boolean(holds, ha->tag);
4216 4214                  fnvlist_add_nvlist(ha->nvl, name, holds);
4217      -                zfs_close(szhp);
     4215 +                fnvlist_free(holds);
4218 4216          }
4219 4217  
4220 4218          if (ha->recursive)
4221 4219                  rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4222 4220          zfs_close(zhp);
4223 4221          return (rv);
4224 4222  }
4225 4223  
4226 4224  int
4227 4225  zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
↓ open down ↓ 16 lines elided ↑ open up ↑
4244 4242                  fnvlist_free(ha.nvl);
4245 4243                  ret = ENOENT;
4246 4244                  (void) snprintf(errbuf, sizeof (errbuf),
4247 4245                      dgettext(TEXT_DOMAIN,
4248 4246                      "cannot release hold from snapshot '%s@%s'"),
4249 4247                      zhp->zfs_name, snapname);
4250 4248                  (void) zfs_standard_error(hdl, ret, errbuf);
4251 4249                  return (ret);
4252 4250          }
4253 4251  
     4252 +        errors = NULL;
4254 4253          ret = lzc_release(ha.nvl, &errors);
4255 4254          fnvlist_free(ha.nvl);
4256 4255  
4257      -        if (ret == 0)
     4256 +        if (ret == 0) {
     4257 +                /* There may be errors even in the success case. */
     4258 +                fnvlist_free(errors);
4258 4259                  return (0);
     4260 +        }
4259 4261  
4260 4262          if (nvlist_next_nvpair(errors, NULL) == NULL) {
4261 4263                  /* no hold-specific errors */
4262 4264                  (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4263 4265                      "cannot release"));
4264 4266                  switch (errno) {
4265 4267                  case ENOTSUP:
4266 4268                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4267 4269                              "pool must be upgraded"));
4268 4270                          (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
↓ open down ↓ 223 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX