Print this page
zero-errno cleanup
Cleanup nvlist_merge case.
Matt's code review fixes
Code review fixes
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 in replication streams, an older/earlier snapshot may exceed the
     4097 + * refquota.  We want to receive the older/earlier snapshot, but setting
     4098 + * refquota pre-receipt will set the dsl's ACTUAL quota, which will prevent
     4099 + * the older/earlier snapshot from being received (with EDQUOT).
     4100 + *
     4101 + * The ZFS test "zfs_receive_011_pos" demonstrates such a scenario.
     4102 + *
     4103 + * libzfs will need to be judicious handling errors encountered by props
     4104 + * extracted by this function.
     4105 + */
     4106 +static nvlist_t *
     4107 +extract_delay_props(nvlist_t *props)
     4108 +{
     4109 +        nvlist_t *delayprops;
     4110 +        nvpair_t *nvp, *tmp;
     4111 +        static const zfs_prop_t delayable[] = { ZFS_PROP_REFQUOTA, 0 };
     4112 +        int i;
     4113 +
     4114 +        VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
     4115 +
     4116 +        for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL;
     4117 +            nvp = nvlist_next_nvpair(props, nvp)) {
     4118 +                /*
     4119 +                 * strcmp() is safe because zfs_prop_to_name() always returns
     4120 +                 * a bounded string.
     4121 +                 */
     4122 +                for (i = 0; delayable[i] != 0; i++) {
     4123 +                        if (strcmp(zfs_prop_to_name(delayable[i]),
     4124 +                            nvpair_name(nvp)) == 0) {
     4125 +                                break;
     4126 +                        }
     4127 +                }
     4128 +                if (delayable[i] != 0) {
     4129 +                        tmp = nvlist_prev_nvpair(props, nvp);
     4130 +                        VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0);
     4131 +                        VERIFY(nvlist_remove_nvpair(props, nvp) == 0);
     4132 +                        nvp = tmp;
     4133 +                }
     4134 +        }
     4135 +
     4136 +        if (nvlist_empty(delayprops)) {
     4137 +                nvlist_free(delayprops);
     4138 +                delayprops = NULL;
     4139 +        }
     4140 +        return (delayprops);
     4141 +}
     4142 +
4093 4143  #ifdef  DEBUG
4094 4144  static boolean_t zfs_ioc_recv_inject_err;
4095 4145  #endif
4096 4146  
4097 4147  /*
4098 4148   * inputs:
4099 4149   * zc_name              name of containing filesystem
4100 4150   * zc_nvlist_src{_size} nvlist of properties to apply
4101 4151   * zc_value             name of snapshot to create
4102 4152   * zc_string            name of clone origin (if DRR_FLAG_CLONE)
↓ open down ↓ 16 lines elided ↑ open up ↑
4119 4169          file_t *fp;
4120 4170          dmu_recv_cookie_t drc;
4121 4171          boolean_t force = (boolean_t)zc->zc_guid;
4122 4172          int fd;
4123 4173          int error = 0;
4124 4174          int props_error = 0;
4125 4175          nvlist_t *errors;
4126 4176          offset_t off;
4127 4177          nvlist_t *props = NULL; /* sent properties */
4128 4178          nvlist_t *origprops = NULL; /* existing properties */
     4179 +        nvlist_t *delayprops = NULL; /* sent properties applied post-receive */
4129 4180          char *origin = NULL;
4130 4181          char *tosnap;
4131 4182          char tofs[ZFS_MAXNAMELEN];
4132 4183          boolean_t first_recvd_props = B_FALSE;
4133 4184  
4134 4185          if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
4135 4186              strchr(zc->zc_value, '@') == NULL ||
4136 4187              strchr(zc->zc_value, '%'))
4137 4188                  return (SET_ERROR(EINVAL));
4138 4189  
↓ open down ↓ 60 lines elided ↑ open up ↑
4199 4250                                  zc->zc_obj |= ZPROP_ERR_NOCLEAR;
4200 4251                  } else {
4201 4252                          zc->zc_obj |= ZPROP_ERR_NOCLEAR;
4202 4253                  }
4203 4254          }
4204 4255  
4205 4256          if (props != NULL) {
4206 4257                  props_error = dsl_prop_set_hasrecvd(tofs);
4207 4258  
4208 4259                  if (props_error == 0) {
     4260 +                        delayprops = extract_delay_props(props);
4209 4261                          (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
4210 4262                              props, errors);
4211 4263                  }
4212 4264          }
4213 4265  
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 4266          off = fp->f_offset;
4225 4267          error = dmu_recv_stream(&drc, fp->f_vnode, &off, zc->zc_cleanup_fd,
4226 4268              &zc->zc_action_handle);
4227 4269  
4228 4270          if (error == 0) {
4229 4271                  zfsvfs_t *zfsvfs = NULL;
4230 4272  
4231 4273                  if (getzfsvfs(tofs, &zfsvfs) == 0) {
4232 4274                          /* online recv */
4233 4275                          int end_err;
↓ open down ↓ 4 lines elided ↑ open up ↑
4238 4280                           * likely also fail, and clean up after itself.
4239 4281                           */
4240 4282                          end_err = dmu_recv_end(&drc, zfsvfs);
4241 4283                          if (error == 0)
4242 4284                                  error = zfs_resume_fs(zfsvfs, tofs);
4243 4285                          error = error ? error : end_err;
4244 4286                          VFS_RELE(zfsvfs->z_vfs);
4245 4287                  } else {
4246 4288                          error = dmu_recv_end(&drc, NULL);
4247 4289                  }
     4290 +
     4291 +                /* Set delayed properties now, after we're done receiving. */
     4292 +                if (delayprops != NULL && error == 0) {
     4293 +                        (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
     4294 +                            delayprops, errors);
     4295 +                }
4248 4296          }
4249 4297  
     4298 +        if (delayprops != NULL) {
     4299 +                /*
     4300 +                 * Merge delayed props back in with initial props, in case
     4301 +                 * we're DEBUG and zfs_ioc_recv_inject_err is set (which means
     4302 +                 * we have to make sure clear_received_props() includes
     4303 +                 * the delayed properties).
     4304 +                 *
     4305 +                 * Since zfs_ioc_recv_inject_err is only in DEBUG kernels,
     4306 +                 * using ASSERT() will be just like a VERIFY.
     4307 +                 */
     4308 +                ASSERT(nvlist_merge(props, delayprops, 0) == 0);
     4309 +                nvlist_free(delayprops);
     4310 +        }
     4311 +
     4312 +        /*
     4313 +         * Now that all props, initial and delayed, are set, report the prop
     4314 +         * errors to the caller.
     4315 +         */
     4316 +        if (zc->zc_nvlist_dst_size != 0 &&
     4317 +            (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
     4318 +            put_nvlist(zc, errors) != 0)) {
     4319 +                /*
     4320 +                 * Caller made zc->zc_nvlist_dst less than the minimum expected
     4321 +                 * size or supplied an invalid address.
     4322 +                 */
     4323 +                props_error = SET_ERROR(EINVAL);
     4324 +        }
     4325 +
4250 4326          zc->zc_cookie = off - fp->f_offset;
4251 4327          if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
4252 4328                  fp->f_offset = off;
4253 4329  
4254 4330  #ifdef  DEBUG
4255 4331          if (zfs_ioc_recv_inject_err) {
4256 4332                  zfs_ioc_recv_inject_err = B_FALSE;
4257 4333                  error = 1;
4258 4334          }
4259 4335  #endif
↓ open down ↓ 1948 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX