Print this page
4986 receiving replication stream fails if any snapshot exceeds refquota

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 ↓ 4082 lines elided ↑ open up ↑
4083 4083  
4084 4084                  /* don't clear the existing received value */
4085 4085                  (void) nvlist_remove_nvpair(origprops, match);
4086 4086                  /* don't bother receiving the property */
4087 4087                  (void) nvlist_remove_nvpair(props, pair);
4088 4088  next:
4089 4089                  pair = next_pair;
4090 4090          }
4091 4091  }
4092 4092  
     4093 +/*
     4094 + * Extract properties that cannot be set PRIOR to the receipt of a dataset.
     4095 + * For example, refquota cannot be set until after the receipt of a dataset,
     4096 + * because a prior snapshot may exceed the refquota, and refquotas only apply
     4097 + * to the current dataset.  The caller (libzfs) will manage these properties
     4098 + * somewhat as well to make sure they only come down with the last dataset in
     4099 + * a replication stream, but we still need to be safe about it here in
     4100 + * kernel-land.
     4101 + */
     4102 +static nvlist_t *
     4103 +extract_delay_props(nvlist_t *props)
     4104 +{
     4105 +        nvlist_t *delayprops;
     4106 +        nvpair_t *nvp, *tmp;
     4107 +        static const zfs_prop_t delayable[] =
     4108 +            { ZFS_PROP_REFQUOTA, ZFS_PROP_REFRESERVATION, 0 };
     4109 +        boolean_t dontbother = B_TRUE;
     4110 +        int i;
     4111 +
     4112 +        VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
     4113 +
     4114 +        for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL;
     4115 +            nvp = nvlist_next_nvpair(props, nvp)) {
     4116 +                /*
     4117 +                 * strcmp() is safe because zfs_prop_to_name() always returns
     4118 +                 * a bounded string.
     4119 +                 */
     4120 +                for (i = 0; delayable[i] != 0; i++) {
     4121 +                        if (strcmp(zfs_prop_to_name(delayable[i]),
     4122 +                            nvpair_name(nvp)) == 0) {
     4123 +                                break;
     4124 +                        }
     4125 +                }
     4126 +                if (delayable[i] != 0) {
     4127 +                        tmp = nvlist_prev_nvpair(props, nvp);
     4128 +                        VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0);
     4129 +                        VERIFY(nvlist_remove_nvpair(props, nvp) == 0);
     4130 +                        nvp = tmp;
     4131 +                        dontbother = B_FALSE;  /* Actually, do bother! */
     4132 +                }
     4133 +        }
     4134 +
     4135 +        if (dontbother) {
     4136 +                nvlist_free(delayprops);
     4137 +                delayprops = NULL;
     4138 +        }
     4139 +        return (delayprops);
     4140 +}
     4141 +
4093 4142  #ifdef  DEBUG
4094 4143  static boolean_t zfs_ioc_recv_inject_err;
4095 4144  #endif
4096 4145  
4097 4146  /*
4098 4147   * inputs:
4099 4148   * zc_name              name of containing filesystem
4100 4149   * zc_nvlist_src{_size} nvlist of properties to apply
4101 4150   * zc_value             name of snapshot to create
4102 4151   * zc_string            name of clone origin (if DRR_FLAG_CLONE)
↓ open down ↓ 16 lines elided ↑ open up ↑
4119 4168          file_t *fp;
4120 4169          dmu_recv_cookie_t drc;
4121 4170          boolean_t force = (boolean_t)zc->zc_guid;
4122 4171          int fd;
4123 4172          int error = 0;
4124 4173          int props_error = 0;
4125 4174          nvlist_t *errors;
4126 4175          offset_t off;
4127 4176          nvlist_t *props = NULL; /* sent properties */
4128 4177          nvlist_t *origprops = NULL; /* existing properties */
     4178 +        nvlist_t *delayprops = NULL; /* sent properties applied post-receive */
4129 4179          char *origin = NULL;
4130 4180          char *tosnap;
4131 4181          char tofs[ZFS_MAXNAMELEN];
4132 4182          boolean_t first_recvd_props = B_FALSE;
4133 4183  
4134 4184          if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
4135 4185              strchr(zc->zc_value, '@') == NULL ||
4136 4186              strchr(zc->zc_value, '%'))
4137 4187                  return (SET_ERROR(EINVAL));
4138 4188  
↓ open down ↓ 60 lines elided ↑ open up ↑
4199 4249                                  zc->zc_obj |= ZPROP_ERR_NOCLEAR;
4200 4250                  } else {
4201 4251                          zc->zc_obj |= ZPROP_ERR_NOCLEAR;
4202 4252                  }
4203 4253          }
4204 4254  
4205 4255          if (props != NULL) {
4206 4256                  props_error = dsl_prop_set_hasrecvd(tofs);
4207 4257  
4208 4258                  if (props_error == 0) {
     4259 +                        delayprops = extract_delay_props(props);
4209 4260                          (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
4210 4261                              props, errors);
4211 4262                  }
4212 4263          }
4213 4264  
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 4265          off = fp->f_offset;
4225 4266          error = dmu_recv_stream(&drc, fp->f_vnode, &off, zc->zc_cleanup_fd,
4226 4267              &zc->zc_action_handle);
4227 4268  
4228 4269          if (error == 0) {
4229 4270                  zfsvfs_t *zfsvfs = NULL;
4230 4271  
4231 4272                  if (getzfsvfs(tofs, &zfsvfs) == 0) {
4232 4273                          /* online recv */
4233 4274                          int end_err;
↓ open down ↓ 4 lines elided ↑ open up ↑
4238 4279                           * likely also fail, and clean up after itself.
4239 4280                           */
4240 4281                          end_err = dmu_recv_end(&drc, zfsvfs);
4241 4282                          if (error == 0)
4242 4283                                  error = zfs_resume_fs(zfsvfs, tofs);
4243 4284                          error = error ? error : end_err;
4244 4285                          VFS_RELE(zfsvfs->z_vfs);
4245 4286                  } else {
4246 4287                          error = dmu_recv_end(&drc, NULL);
4247 4288                  }
     4289 +
     4290 +                /* Set delayed properties now, after we're done receiving. */
     4291 +                if (delayprops != NULL) {
     4292 +                        (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
     4293 +                            delayprops, errors);
     4294 +                }
4248 4295          }
4249 4296  
     4297 +        /* Merge delayprops back in with regular props, in case of errors. */
     4298 +        if (delayprops != NULL) {
     4299 +                VERIFY(nvlist_merge(props, delayprops, 0) == 0);
     4300 +                nvlist_free(delayprops);
     4301 +        }
     4302 +
     4303 +        /* Put the props error list into zc AFTER the delayprops. */
     4304 +        if (zc->zc_nvlist_dst_size != 0 &&
     4305 +            (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
     4306 +            put_nvlist(zc, errors) != 0)) {
     4307 +                /*
     4308 +                 * Caller made zc->zc_nvlist_dst less than the minimum expected
     4309 +                 * size or supplied an invalid address.
     4310 +                 */
     4311 +                props_error = SET_ERROR(EINVAL);
     4312 +        }
     4313 +
4250 4314          zc->zc_cookie = off - fp->f_offset;
4251 4315          if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
4252 4316                  fp->f_offset = off;
4253 4317  
4254 4318  #ifdef  DEBUG
4255 4319          if (zfs_ioc_recv_inject_err) {
4256 4320                  zfs_ioc_recv_inject_err = B_FALSE;
4257 4321                  error = 1;
4258 4322          }
4259 4323  #endif
↓ open down ↓ 1948 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX