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>
Approved by: Gordon Ross <gordon.ross@nexenta.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 ↓ 15 lines elided ↑ open up ↑
  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   25   * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
       26 + * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
  26   27   * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  27   28   * Copyright (c) 2011, 2014 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   * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
  31   32   */
  32   33  
  33   34  /*
  34   35   * ZFS ioctls.
  35   36   *
↓ open down ↓ 4013 lines elided ↑ open up ↑
4049 4050  
4050 4051                  /* don't clear the existing received value */
4051 4052                  (void) nvlist_remove_nvpair(origprops, match);
4052 4053                  /* don't bother receiving the property */
4053 4054                  (void) nvlist_remove_nvpair(props, pair);
4054 4055  next:
4055 4056                  pair = next_pair;
4056 4057          }
4057 4058  }
4058 4059  
     4060 +/*
     4061 + * Extract properties that cannot be set PRIOR to the receipt of a dataset.
     4062 + * For example, refquota cannot be set until after the receipt of a dataset,
     4063 + * because in replication streams, an older/earlier snapshot may exceed the
     4064 + * refquota.  We want to receive the older/earlier snapshot, but setting
     4065 + * refquota pre-receipt will set the dsl's ACTUAL quota, which will prevent
     4066 + * the older/earlier snapshot from being received (with EDQUOT).
     4067 + *
     4068 + * The ZFS test "zfs_receive_011_pos" demonstrates such a scenario.
     4069 + *
     4070 + * libzfs will need to be judicious handling errors encountered by props
     4071 + * extracted by this function.
     4072 + */
     4073 +static nvlist_t *
     4074 +extract_delay_props(nvlist_t *props)
     4075 +{
     4076 +        nvlist_t *delayprops;
     4077 +        nvpair_t *nvp, *tmp;
     4078 +        static const zfs_prop_t delayable[] = { ZFS_PROP_REFQUOTA, 0 };
     4079 +        int i;
     4080 +
     4081 +        VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
     4082 +
     4083 +        for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL;
     4084 +            nvp = nvlist_next_nvpair(props, nvp)) {
     4085 +                /*
     4086 +                 * strcmp() is safe because zfs_prop_to_name() always returns
     4087 +                 * a bounded string.
     4088 +                 */
     4089 +                for (i = 0; delayable[i] != 0; i++) {
     4090 +                        if (strcmp(zfs_prop_to_name(delayable[i]),
     4091 +                            nvpair_name(nvp)) == 0) {
     4092 +                                break;
     4093 +                        }
     4094 +                }
     4095 +                if (delayable[i] != 0) {
     4096 +                        tmp = nvlist_prev_nvpair(props, nvp);
     4097 +                        VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0);
     4098 +                        VERIFY(nvlist_remove_nvpair(props, nvp) == 0);
     4099 +                        nvp = tmp;
     4100 +                }
     4101 +        }
     4102 +
     4103 +        if (nvlist_empty(delayprops)) {
     4104 +                nvlist_free(delayprops);
     4105 +                delayprops = NULL;
     4106 +        }
     4107 +        return (delayprops);
     4108 +}
     4109 +
4059 4110  #ifdef  DEBUG
4060 4111  static boolean_t zfs_ioc_recv_inject_err;
4061 4112  #endif
4062 4113  
4063 4114  /*
4064 4115   * inputs:
4065 4116   * zc_name              name of containing filesystem
4066 4117   * zc_nvlist_src{_size} nvlist of properties to apply
4067 4118   * zc_value             name of snapshot to create
4068 4119   * zc_string            name of clone origin (if DRR_FLAG_CLONE)
↓ open down ↓ 15 lines elided ↑ open up ↑
4084 4135          file_t *fp;
4085 4136          dmu_recv_cookie_t drc;
4086 4137          boolean_t force = (boolean_t)zc->zc_guid;
4087 4138          int fd;
4088 4139          int error = 0;
4089 4140          int props_error = 0;
4090 4141          nvlist_t *errors;
4091 4142          offset_t off;
4092 4143          nvlist_t *props = NULL; /* sent properties */
4093 4144          nvlist_t *origprops = NULL; /* existing properties */
     4145 +        nvlist_t *delayprops = NULL; /* sent properties applied post-receive */
4094 4146          char *origin = NULL;
4095 4147          char *tosnap;
4096 4148          char tofs[ZFS_MAXNAMELEN];
4097 4149          boolean_t first_recvd_props = B_FALSE;
4098 4150  
4099 4151          if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
4100 4152              strchr(zc->zc_value, '@') == NULL ||
4101 4153              strchr(zc->zc_value, '%'))
4102 4154                  return (SET_ERROR(EINVAL));
4103 4155  
↓ open down ↓ 60 lines elided ↑ open up ↑
4164 4216                                  zc->zc_obj |= ZPROP_ERR_NOCLEAR;
4165 4217                  } else {
4166 4218                          zc->zc_obj |= ZPROP_ERR_NOCLEAR;
4167 4219                  }
4168 4220          }
4169 4221  
4170 4222          if (props != NULL) {
4171 4223                  props_error = dsl_prop_set_hasrecvd(tofs);
4172 4224  
4173 4225                  if (props_error == 0) {
     4226 +                        delayprops = extract_delay_props(props);
4174 4227                          (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
4175 4228                              props, errors);
4176 4229                  }
4177 4230          }
4178 4231  
4179      -        if (zc->zc_nvlist_dst_size != 0 &&
4180      -            (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
4181      -            put_nvlist(zc, errors) != 0)) {
4182      -                /*
4183      -                 * Caller made zc->zc_nvlist_dst less than the minimum expected
4184      -                 * size or supplied an invalid address.
4185      -                 */
4186      -                props_error = SET_ERROR(EINVAL);
4187      -        }
4188      -
4189 4232          off = fp->f_offset;
4190 4233          error = dmu_recv_stream(&drc, fp->f_vnode, &off, zc->zc_cleanup_fd,
4191 4234              &zc->zc_action_handle);
4192 4235  
4193 4236          if (error == 0) {
4194 4237                  zfsvfs_t *zfsvfs = NULL;
4195 4238  
4196 4239                  if (getzfsvfs(tofs, &zfsvfs) == 0) {
4197 4240                          /* online recv */
4198 4241                          int end_err;
↓ open down ↓ 4 lines elided ↑ open up ↑
4203 4246                           * likely also fail, and clean up after itself.
4204 4247                           */
4205 4248                          end_err = dmu_recv_end(&drc, zfsvfs);
4206 4249                          if (error == 0)
4207 4250                                  error = zfs_resume_fs(zfsvfs, tofs);
4208 4251                          error = error ? error : end_err;
4209 4252                          VFS_RELE(zfsvfs->z_vfs);
4210 4253                  } else {
4211 4254                          error = dmu_recv_end(&drc, NULL);
4212 4255                  }
     4256 +
     4257 +                /* Set delayed properties now, after we're done receiving. */
     4258 +                if (delayprops != NULL && error == 0) {
     4259 +                        (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
     4260 +                            delayprops, errors);
     4261 +                }
4213 4262          }
4214 4263  
     4264 +        if (delayprops != NULL) {
     4265 +                /*
     4266 +                 * Merge delayed props back in with initial props, in case
     4267 +                 * we're DEBUG and zfs_ioc_recv_inject_err is set (which means
     4268 +                 * we have to make sure clear_received_props() includes
     4269 +                 * the delayed properties).
     4270 +                 *
     4271 +                 * Since zfs_ioc_recv_inject_err is only in DEBUG kernels,
     4272 +                 * using ASSERT() will be just like a VERIFY.
     4273 +                 */
     4274 +                ASSERT(nvlist_merge(props, delayprops, 0) == 0);
     4275 +                nvlist_free(delayprops);
     4276 +        }
     4277 +
     4278 +        /*
     4279 +         * Now that all props, initial and delayed, are set, report the prop
     4280 +         * errors to the caller.
     4281 +         */
     4282 +        if (zc->zc_nvlist_dst_size != 0 &&
     4283 +            (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
     4284 +            put_nvlist(zc, errors) != 0)) {
     4285 +                /*
     4286 +                 * Caller made zc->zc_nvlist_dst less than the minimum expected
     4287 +                 * size or supplied an invalid address.
     4288 +                 */
     4289 +                props_error = SET_ERROR(EINVAL);
     4290 +        }
     4291 +
4215 4292          zc->zc_cookie = off - fp->f_offset;
4216 4293          if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
4217 4294                  fp->f_offset = off;
4218 4295  
4219 4296  #ifdef  DEBUG
4220 4297          if (zfs_ioc_recv_inject_err) {
4221 4298                  zfs_ioc_recv_inject_err = B_FALSE;
4222 4299                  error = 1;
4223 4300          }
4224 4301  #endif
↓ open down ↓ 1919 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX