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 ↓ 4073 lines elided ↑ open up ↑
4074 4074          nvlist_t *nvl;
4075 4075          const char *snapname;
4076 4076          const char *tag;
4077 4077          boolean_t recursive;
4078 4078  };
4079 4079  
4080 4080  static int
4081 4081  zfs_hold_one(zfs_handle_t *zhp, void *arg)
4082 4082  {
4083 4083          struct holdarg *ha = arg;
4084      -        zfs_handle_t *szhp;
4085 4084          char name[ZFS_MAXNAMELEN];
4086 4085          int rv = 0;
4087 4086  
4088 4087          (void) snprintf(name, sizeof (name),
4089 4088              "%s@%s", zhp->zfs_name, ha->snapname);
4090 4089  
4091      -        szhp = make_dataset_handle(zhp->zfs_hdl, name);
4092      -        if (szhp) {
     4090 +        if (lzc_exists(name))
4093 4091                  fnvlist_add_string(ha->nvl, name, ha->tag);
4094      -                zfs_close(szhp);
4095      -        }
4096 4092  
4097 4093          if (ha->recursive)
4098 4094                  rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4099 4095          zfs_close(zhp);
4100 4096          return (rv);
4101 4097  }
4102 4098  
4103 4099  int
4104 4100  zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4105      -    boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
     4101 +    boolean_t recursive, int cleanup_fd)
4106 4102  {
4107 4103          int ret;
4108 4104          struct holdarg ha;
4109      -        nvlist_t *errors;
4110      -        libzfs_handle_t *hdl = zhp->zfs_hdl;
4111      -        char errbuf[1024];
4112      -        nvpair_t *elem;
4113 4105  
4114 4106          ha.nvl = fnvlist_alloc();
4115 4107          ha.snapname = snapname;
4116 4108          ha.tag = tag;
4117 4109          ha.recursive = recursive;
4118 4110          (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4119      -        ret = lzc_hold(ha.nvl, cleanup_fd, &errors);
     4111 +        ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
4120 4112          fnvlist_free(ha.nvl);
4121 4113  
4122      -        if (ret == 0)
     4114 +        return (ret);
     4115 +}
     4116 +
     4117 +int
     4118 +zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
     4119 +{
     4120 +        int ret;
     4121 +        nvlist_t *errors;
     4122 +        libzfs_handle_t *hdl = zhp->zfs_hdl;
     4123 +        char errbuf[1024];
     4124 +        nvpair_t *elem;
     4125 + 
     4126 +        errors = NULL;
     4127 +        ret = lzc_hold(holds, cleanup_fd, &errors);
     4128 + 
     4129 +        if (ret == 0) {
     4130 +                /* There may be errors even in the success case. */
     4131 +                fnvlist_free(errors);
4123 4132                  return (0);
     4133 +        }
4124 4134  
4125 4135          if (nvlist_next_nvpair(errors, NULL) == NULL) {
4126 4136                  /* no hold-specific errors */
4127 4137                  (void) snprintf(errbuf, sizeof (errbuf),
4128 4138                      dgettext(TEXT_DOMAIN, "cannot hold"));
4129 4139                  switch (ret) {
4130 4140                  case ENOTSUP:
4131 4141                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4132 4142                              "pool must be upgraded"));
4133 4143                          (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
↓ open down ↓ 21 lines elided ↑ open up ↑
4155 4165                           * up being slightly too long.
4156 4166                           */
4157 4167                          (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4158 4168                          break;
4159 4169                  case EINVAL:
4160 4170                          (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4161 4171                          break;
4162 4172                  case EEXIST:
4163 4173                          (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4164 4174                          break;
4165      -                case ENOENT:
4166      -                        if (enoent_ok)
4167      -                                return (ENOENT);
4168      -                        /* FALLTHROUGH */
4169 4175                  default:
4170 4176                          (void) zfs_standard_error(hdl,
4171 4177                              fnvpair_value_int32(elem), errbuf);
4172 4178                  }
4173 4179          }
4174 4180  
4175 4181          fnvlist_free(errors);
4176 4182          return (ret);
4177 4183  }
4178 4184  
4179      -struct releasearg {
4180      -        nvlist_t *nvl;
4181      -        const char *snapname;
4182      -        const char *tag;
4183      -        boolean_t recursive;
4184      -};
4185      -
4186 4185  static int
4187 4186  zfs_release_one(zfs_handle_t *zhp, void *arg)
4188 4187  {
4189 4188          struct holdarg *ha = arg;
4190      -        zfs_handle_t *szhp;
4191 4189          char name[ZFS_MAXNAMELEN];
4192 4190          int rv = 0;
4193 4191  
4194 4192          (void) snprintf(name, sizeof (name),
4195 4193              "%s@%s", zhp->zfs_name, ha->snapname);
4196 4194  
4197      -        szhp = make_dataset_handle(zhp->zfs_hdl, name);
4198      -        if (szhp) {
     4195 +        if (lzc_exists(name)) {
4199 4196                  nvlist_t *holds = fnvlist_alloc();
4200 4197                  fnvlist_add_boolean(holds, ha->tag);
4201 4198                  fnvlist_add_nvlist(ha->nvl, name, holds);
4202      -                zfs_close(szhp);
     4199 +                fnvlist_free(holds);
4203 4200          }
4204 4201  
4205 4202          if (ha->recursive)
4206 4203                  rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4207 4204          zfs_close(zhp);
4208 4205          return (rv);
4209 4206  }
4210 4207  
4211 4208  int
4212 4209  zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
↓ open down ↓ 3 lines elided ↑ open up ↑
4216 4213          struct holdarg ha;
4217 4214          nvlist_t *errors;
4218 4215          nvpair_t *elem;
4219 4216          libzfs_handle_t *hdl = zhp->zfs_hdl;
4220 4217  
4221 4218          ha.nvl = fnvlist_alloc();
4222 4219          ha.snapname = snapname;
4223 4220          ha.tag = tag;
4224 4221          ha.recursive = recursive;
4225 4222          (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
     4223 +        errors = NULL;
4226 4224          ret = lzc_release(ha.nvl, &errors);
4227 4225          fnvlist_free(ha.nvl);
4228 4226  
4229      -        if (ret == 0)
     4227 +        if (ret == 0) {
     4228 +                /* There may be errors even in the success case. */
     4229 +                fnvlist_free(errors);
4230 4230                  return (0);
     4231 +        }
4231 4232  
4232 4233          if (nvlist_next_nvpair(errors, NULL) == NULL) {
4233 4234                  /* no hold-specific errors */
4234 4235                  char errbuf[1024];
4235 4236  
4236 4237                  (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4237 4238                      "cannot release"));
4238 4239                  switch (errno) {
4239 4240                  case ENOTSUP:
4240 4241                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
↓ open down ↓ 227 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX