Print this page
4986 receiving replication stream fails if any snapshot exceeds refquota
Reviewed by: John Kennedy <john.kennedy@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/zfs_ioctl.c
          +++ new/usr/src/uts/common/fs/zfs/zfs_ioctl.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  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   * Portions Copyright 2011 Martin Matuska
       25 + * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
  25   26   * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  26   27   * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  27   28   * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  28   29   * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  29   30   * Copyright (c) 2013 Steven Hartland. All rights reserved.
  30   31   */
  31   32  
  32   33  /*
  33   34   * ZFS ioctls.
  34   35   *
↓ open down ↓ 4048 lines elided ↑ open up ↑
4083 4084  
4084 4085                  /* don't clear the existing received value */
4085 4086                  (void) nvlist_remove_nvpair(origprops, match);
4086 4087                  /* don't bother receiving the property */
4087 4088                  (void) nvlist_remove_nvpair(props, pair);
4088 4089  next:
4089 4090                  pair = next_pair;
4090 4091          }
4091 4092  }
4092 4093  
     4094 +/*
     4095 + * Extract properties that cannot be set PRIOR to the receipt of a dataset.
     4096 + * For example, refquota cannot be set until after the receipt of a dataset,
     4097 + * because in replication streams, an older/earlier snapshot may exceed the
     4098 + * refquota.  We want to receive the older/earlier snapshot, but setting
     4099 + * refquota pre-receipt will set the dsl's ACTUAL quota, which will prevent
     4100 + * the older/earlier snapshot from being received (with EDQUOT).
     4101 + *
     4102 + * The ZFS test "zfs_receive_011_pos" demonstrates such a scenario.
     4103 + *
     4104 + * libzfs will need to be judicious handling errors encountered by props
     4105 + * extracted by this function.
     4106 + */
     4107 +static nvlist_t *
     4108 +extract_delay_props(nvlist_t *props)
     4109 +{
     4110 +        nvlist_t *delayprops;
     4111 +        nvpair_t *nvp, *tmp;
     4112 +        static const zfs_prop_t delayable[] = { ZFS_PROP_REFQUOTA, 0 };
     4113 +        int i;
     4114 +
     4115 +        VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
     4116 +
     4117 +        for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL;
     4118 +            nvp = nvlist_next_nvpair(props, nvp)) {
     4119 +                /*
     4120 +                 * strcmp() is safe because zfs_prop_to_name() always returns
     4121 +                 * a bounded string.
     4122 +                 */
     4123 +                for (i = 0; delayable[i] != 0; i++) {
     4124 +                        if (strcmp(zfs_prop_to_name(delayable[i]),
     4125 +                            nvpair_name(nvp)) == 0) {
     4126 +                                break;
     4127 +                        }
     4128 +                }
     4129 +                if (delayable[i] != 0) {
     4130 +                        tmp = nvlist_prev_nvpair(props, nvp);
     4131 +                        VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0);
     4132 +                        VERIFY(nvlist_remove_nvpair(props, nvp) == 0);
     4133 +                        nvp = tmp;
     4134 +                }
     4135 +        }
     4136 +
     4137 +        if (nvlist_empty(delayprops)) {
     4138 +                nvlist_free(delayprops);
     4139 +                delayprops = NULL;
     4140 +        }
     4141 +        return (delayprops);
     4142 +}
     4143 +
4093 4144  #ifdef  DEBUG
4094 4145  static boolean_t zfs_ioc_recv_inject_err;
4095 4146  #endif
4096 4147  
4097 4148  /*
4098 4149   * inputs:
4099 4150   * zc_name              name of containing filesystem
4100 4151   * zc_nvlist_src{_size} nvlist of properties to apply
4101 4152   * zc_value             name of snapshot to create
4102 4153   * zc_string            name of clone origin (if DRR_FLAG_CLONE)
↓ open down ↓ 16 lines elided ↑ open up ↑
4119 4170          file_t *fp;
4120 4171          dmu_recv_cookie_t drc;
4121 4172          boolean_t force = (boolean_t)zc->zc_guid;
4122 4173          int fd;
4123 4174          int error = 0;
4124 4175          int props_error = 0;
4125 4176          nvlist_t *errors;
4126 4177          offset_t off;
4127 4178          nvlist_t *props = NULL; /* sent properties */
4128 4179          nvlist_t *origprops = NULL; /* existing properties */
     4180 +        nvlist_t *delayprops = NULL; /* sent properties applied post-receive */
4129 4181          char *origin = NULL;
4130 4182          char *tosnap;
4131 4183          char tofs[ZFS_MAXNAMELEN];
4132 4184          boolean_t first_recvd_props = B_FALSE;
4133 4185  
4134 4186          if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
4135 4187              strchr(zc->zc_value, '@') == NULL ||
4136 4188              strchr(zc->zc_value, '%'))
4137 4189                  return (SET_ERROR(EINVAL));
4138 4190  
↓ open down ↓ 60 lines elided ↑ open up ↑
4199 4251                                  zc->zc_obj |= ZPROP_ERR_NOCLEAR;
4200 4252                  } else {
4201 4253                          zc->zc_obj |= ZPROP_ERR_NOCLEAR;
4202 4254                  }
4203 4255          }
4204 4256  
4205 4257          if (props != NULL) {
4206 4258                  props_error = dsl_prop_set_hasrecvd(tofs);
4207 4259  
4208 4260                  if (props_error == 0) {
     4261 +                        delayprops = extract_delay_props(props);
4209 4262                          (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
4210 4263                              props, errors);
4211 4264                  }
4212 4265          }
4213 4266  
4214      -        if (zc->zc_nvlist_dst_size != 0 &&
4215      -            (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
4216      -            put_nvlist(zc, errors) != 0)) {
4217      -                /*
4218      -                 * Caller made zc->zc_nvlist_dst less than the minimum expected
4219      -                 * size or supplied an invalid address.
4220      -                 */
4221      -                props_error = SET_ERROR(EINVAL);
4222      -        }
4223      -
4224 4267          off = fp->f_offset;
4225 4268          error = dmu_recv_stream(&drc, fp->f_vnode, &off, zc->zc_cleanup_fd,
4226 4269              &zc->zc_action_handle);
4227 4270  
4228 4271          if (error == 0) {
4229 4272                  zfsvfs_t *zfsvfs = NULL;
4230 4273  
4231 4274                  if (getzfsvfs(tofs, &zfsvfs) == 0) {
4232 4275                          /* online recv */
4233 4276                          int end_err;
↓ open down ↓ 4 lines elided ↑ open up ↑
4238 4281                           * likely also fail, and clean up after itself.
4239 4282                           */
4240 4283                          end_err = dmu_recv_end(&drc, zfsvfs);
4241 4284                          if (error == 0)
4242 4285                                  error = zfs_resume_fs(zfsvfs, tofs);
4243 4286                          error = error ? error : end_err;
4244 4287                          VFS_RELE(zfsvfs->z_vfs);
4245 4288                  } else {
4246 4289                          error = dmu_recv_end(&drc, NULL);
4247 4290                  }
     4291 +
     4292 +                /* Set delayed properties now, after we're done receiving. */
     4293 +                if (delayprops != NULL && error == 0) {
     4294 +                        (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
     4295 +                            delayprops, errors);
     4296 +                }
4248 4297          }
4249 4298  
     4299 +        if (delayprops != NULL) {
     4300 +                /*
     4301 +                 * Merge delayed props back in with initial props, in case
     4302 +                 * we're DEBUG and zfs_ioc_recv_inject_err is set (which means
     4303 +                 * we have to make sure clear_received_props() includes
     4304 +                 * the delayed properties).
     4305 +                 *
     4306 +                 * Since zfs_ioc_recv_inject_err is only in DEBUG kernels,
     4307 +                 * using ASSERT() will be just like a VERIFY.
     4308 +                 */
     4309 +                ASSERT(nvlist_merge(props, delayprops, 0) == 0);
     4310 +                nvlist_free(delayprops);
     4311 +        }
     4312 +
     4313 +        /*
     4314 +         * Now that all props, initial and delayed, are set, report the prop
     4315 +         * errors to the caller.
     4316 +         */
     4317 +        if (zc->zc_nvlist_dst_size != 0 &&
     4318 +            (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
     4319 +            put_nvlist(zc, errors) != 0)) {
     4320 +                /*
     4321 +                 * Caller made zc->zc_nvlist_dst less than the minimum expected
     4322 +                 * size or supplied an invalid address.
     4323 +                 */
     4324 +                props_error = SET_ERROR(EINVAL);
     4325 +        }
     4326 +
4250 4327          zc->zc_cookie = off - fp->f_offset;
4251 4328          if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
4252 4329                  fp->f_offset = off;
4253 4330  
4254 4331  #ifdef  DEBUG
4255 4332          if (zfs_ioc_recv_inject_err) {
4256 4333                  zfs_ioc_recv_inject_err = B_FALSE;
4257 4334                  error = 1;
4258 4335          }
4259 4336  #endif
↓ open down ↓ 1948 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX