+ RETURN(ret);
+}
+
+/**
+ * Adjust extents after component removal
+ *
+ * When we remove an extension component, we move the start of the next
+ * component to match the start of the extension component, so no space is left
+ * without layout.
+ *
+ * \param[in] env execution environment for this thread
+ * \param[in] lo object
+ * \param[in] max_comp layout component
+ * \param[in] index index of this component
+ *
+ * \retval 0 on success
+ * \retval negative errno on error
+ */
+static void lod_sel_adjust_extents(const struct lu_env *env,
+ struct lod_object *lo,
+ int max_comp, int index)
+{
+ struct lod_layout_component *lod_comp = NULL;
+ struct lod_layout_component *next = NULL;
+ struct lod_layout_component *prev = NULL;
+ __u64 new_start = 0;
+ __u64 start;
+ int i;
+
+ /* Extension space component */
+ lod_comp = &lo->ldo_comp_entries[index];
+ next = &lo->ldo_comp_entries[index + 1];
+ prev = &lo->ldo_comp_entries[index - 1];
+
+ LASSERT(lod_comp != NULL && prev != NULL && next != NULL);
+ LASSERT(lod_comp->llc_flags & LCME_FL_EXTENSION);
+
+ /* Previous is being removed */
+ if (prev && prev->llc_id == LCME_ID_INVAL)
+ new_start = prev->llc_extent.e_start;
+ else
+ new_start = lod_comp->llc_extent.e_start;
+
+ for (i = index + 1; i < max_comp; i++) {
+ lod_comp = &lo->ldo_comp_entries[i];
+
+ start = lod_comp->llc_extent.e_start;
+ lod_comp->llc_extent.e_start = new_start;
+
+ /* We only move zero length extendable components */
+ if (!(start == lod_comp->llc_extent.e_end))
+ break;
+
+ LASSERT(!(lod_comp->llc_flags & LCME_FL_INIT));
+
+ lod_comp->llc_extent.e_end = new_start;
+ }
+}
+
+/* Calculate the proposed 'new end' for a component we're extending */
+static __u64 lod_extension_new_end(__u64 extension_size, __u64 extent_end,
+ __u32 stripe_size, __u64 component_end,
+ __u64 extension_end)
+{
+ __u64 new_end;
+
+ LASSERT(extension_size != 0 && stripe_size != 0);
+
+ /* Round up to extension size */
+ if (extent_end == OBD_OBJECT_EOF) {
+ new_end = OBD_OBJECT_EOF;
+ } else {
+ /* Add at least extension_size to the previous component_end,
+ * covering the req layout extent */
+ new_end = max(extent_end - component_end, extension_size);
+ new_end = roundup(new_end, extension_size);
+ new_end += component_end;
+
+ /* Component end must be min stripe size aligned */
+ if (new_end % stripe_size) {
+ CDEBUG(D_LAYOUT, "new component end is not aligned "
+ "by the stripe size %u: [%llu, %llu) ext size "
+ "%llu new end %llu, aligning\n",
+ stripe_size, component_end, extent_end,
+ extension_size, new_end);
+ new_end = roundup(new_end, stripe_size);
+ }
+
+ /* Overflow */
+ if (new_end < extent_end)
+ new_end = OBD_OBJECT_EOF;
+ }
+
+ /* Don't extend past the end of the extension component */
+ if (new_end > extension_end)
+ new_end = extension_end;
+
+ return new_end;
+}
+
+/**
+ * Calculate the exact reservation (per-OST extension_size) on the OSTs being
+ * instantiated. It needs to be calculated in advance and taken into account at
+ * the instantiation time, because otherwise lod_statfs_and_check() may consider
+ * an OST as OK, but SEL needs its extension_size to fit the free space and the
+ * OST may turn out to be low-on-space, thus inappropriate OST may be used and
+ * ENOSPC occurs.
+ *
+ * \param[in] lod_comp lod component we are checking
+ *
+ * \retval size to reserved on each OST of lod_comp's stripe.
+ */
+static __u64 lod_sel_stripe_reserved(struct lod_layout_component *lod_comp)
+{
+ /* extension_size is file level, so we must divide by stripe count to
+ * compare it to available space on a single OST */
+ return lod_comp->llc_stripe_size * SEL_UNIT_SIZE /
+ lod_comp->llc_stripe_count;
+}
+
+/* As lod_sel_handler() could be re-entered for the same component several
+ * times, this is the data for the next call. Fields could be changed to
+ * component indexes when needed, (e.g. if there is no need to instantiate
+ * all the previous components up to the current position) to tell the caller
+ * where to start over from. */
+struct sel_data {
+ int sd_force;
+ int sd_repeat;
+};
+
+/**
+ * Process extent updates for a particular layout component
+ *
+ * Handle layout updates for a particular extension space component touched by
+ * a layout update operation. Core function of self-extending PFL feature.
+ *
+ * In general, this function processes exactly *one* stage of an extension
+ * operation, modifying the layout accordingly, then returns to the caller.
+ * The caller is responsible for restarting processing with the new layout,
+ * which may repeatedly return to this function until the extension updates
+ * are complete.
+ *
+ * This function does one of a few things to the layout:
+ * 1. Extends the component before the current extension space component to
+ * allow it to accomodate the requested operation (if space/policy permit that
+ * component to continue on its current OSTs)
+ *
+ * 2. If extension of the existing component fails, we do one of two things:
+ * a. If there is a component after the extension space, we remove the
+ * extension space component, move the start of the next component down
+ * accordingly, then notify the caller to restart processing w/the new
+ * layout.
+ * b. If there is no following component, we try repeating the current
+ * component, creating a new component using the current one as a
+ * template (keeping its stripe properties but not specific striping),
+ * and try assigning striping for this component. If there is sufficient
+ * free space on the OSTs chosen for this component, it is instantiated
+ * and i/o continues there.
+ *
+ * If there is not sufficient space on the new OSTs, we remove this new
+ * component & extend the current component.
+ *
+ * Note further that uninited components followed by extension space can be zero
+ * length meaning that we will try to extend them before initializing them, and
+ * if that fails, they will be removed without initialization.
+ *
+ * 3. If we extend to/beyond the end of an extension space component, that
+ * component is exhausted (all of its range has been given to real components),
+ * so we remove it and restart processing.
+ *
+ * \param[in] env execution environment for this thread
+ * \param[in,out] lo object to update the layout of
+ * \param[in] extent layout extent for requested operation, update
+ * layout to fit this operation
+ * \param[in] th transaction handle for this operation
+ * \param[in,out] max_comp the highest comp for the portion of the layout
+ * we are operating on (For FLR, the chosen
+ * replica). Updated because we may remove
+ * components.
+ * \param[in] index index of the extension space component we're
+ * working on
+ * \param[in] write if this is write op
+ * \param[in,out] force if the extension is to be forced; set here
+ to force it on the 2nd call for the same
+ extension component
+ *
+ * \retval 0 on success
+ * \retval negative errno on error
+ */
+static int lod_sel_handler(const struct lu_env *env,
+ struct lod_object *lo,
+ struct lu_extent *extent,
+ struct thandle *th, int *max_comp,
+ int index, int write,
+ struct sel_data *sd)
+{
+ struct lod_device *d = lu2lod_dev(lo->ldo_obj.do_lu.lo_dev);
+ struct lod_thread_info *info = lod_env_info(env);
+ struct lod_layout_component *lod_comp;
+ struct lod_layout_component *prev;
+ struct lod_layout_component *next = NULL;
+ __u64 extension_size, reserve;
+ __u64 new_end = 0;
+ bool repeated;
+ int change = 0;
+ int rc = 0;
+ ENTRY;
+
+ /* First component cannot be extension space */
+ if (index == 0) {
+ CERROR("%s: "DFID" first component cannot be extension space\n",
+ lod2obd(d)->obd_name, PFID(lod_object_fid(lo)));
+ RETURN(-EINVAL);
+ }
+
+ lod_comp = &lo->ldo_comp_entries[index];
+ prev = &lo->ldo_comp_entries[index - 1];
+ if ((index + 1) < *max_comp)
+ next = &lo->ldo_comp_entries[index + 1];
+
+ /* extension size uses the stripe size field as KiB */
+ extension_size = lod_comp->llc_stripe_size * SEL_UNIT_SIZE;
+
+ CDEBUG(D_LAYOUT, "prev start %llu, extension start %llu, extension end"
+ " %llu, extension size %llu\n", prev->llc_extent.e_start,
+ lod_comp->llc_extent.e_start, lod_comp->llc_extent.e_end,
+ extension_size);
+
+ /* Two extension space components cannot be adjacent & extension space
+ * components cannot be init */
+ if ((prev->llc_flags & LCME_FL_EXTENSION) ||
+ !(ergo(next, !(next->llc_flags & LCME_FL_EXTENSION))) ||
+ lod_comp_inited(lod_comp)) {
+ CERROR("%s: "DFID" invalid extension space components\n",
+ lod2obd(d)->obd_name, PFID(lod_object_fid(lo)));
+ RETURN(-EINVAL);
+ }
+
+ reserve = lod_sel_stripe_reserved(lod_comp);
+
+ if (!prev->llc_stripe) {
+ CDEBUG(D_LAYOUT, "Previous component not inited\n");
+ info->lti_count = 1;
+ info->lti_comp_idx[0] = index - 1;
+ rc = lod_declare_instantiate_components(env, lo, th, reserve);
+ /* ENOSPC tells us we can't use this component. If there is
+ * a next or we are repeating, we either spill over (next) or
+ * extend the original comp (repeat). Otherwise, return the
+ * error to the user. */
+ if (rc == -ENOSPC && (next || sd->sd_repeat))
+ rc = 1;
+ if (rc < 0)
+ RETURN(rc);
+ }
+
+ if (sd->sd_force == 0 && rc == 0)
+ rc = !lod_sel_osts_allowed(env, lo, index - 1, reserve, extent,
+ &lod_comp->llc_extent, write);
+
+ repeated = !!(sd->sd_repeat);
+ sd->sd_repeat = 0;
+ sd->sd_force = 0;
+
+ /* Extend previous component */
+ if (rc == 0) {
+ new_end = lod_extension_new_end(extension_size, extent->e_end,
+ prev->llc_stripe_size,
+ prev->llc_extent.e_end,
+ lod_comp->llc_extent.e_end);
+
+ CDEBUG(D_LAYOUT, "new end %llu\n", new_end);
+ lod_comp->llc_extent.e_start = new_end;
+ prev->llc_extent.e_end = new_end;
+
+ if (prev->llc_extent.e_end == lod_comp->llc_extent.e_end) {
+ CDEBUG(D_LAYOUT, "Extension component exhausted\n");
+ lod_comp->llc_id = LCME_ID_INVAL;
+ change--;
+ }
+ } else {
+ /* rc == 1, failed to extend current component */
+ LASSERT(rc == 1);
+ if (next) {
+ /* Normal 'spillover' case - Remove the extension
+ * space component & bring down the start of the next
+ * component. */
+ lod_comp->llc_id = LCME_ID_INVAL;
+ change--;
+ if (!(prev->llc_flags & LCME_FL_INIT)) {
+ prev->llc_id = LCME_ID_INVAL;
+ change--;
+ }
+ lod_sel_adjust_extents(env, lo, *max_comp, index);
+ } else if (lod_comp_inited(prev)) {
+ /* If there is no next, and the previous component is
+ * INIT'ed, try repeating the previous component. */
+ LASSERT(repeated == 0);
+ rc = lod_layout_repeat_comp(env, lo, index - 1);
+ if (rc < 0)
+ RETURN(rc);
+ change++;
+ /* The previous component is a repeated component.
+ * Record this so we don't keep trying to repeat it. */
+ sd->sd_repeat = 1;
+ } else {
+ /* If the previous component is not INIT'ed, this may
+ * be a component we have just instantiated but failed
+ * to extend. Or even a repeated component we failed
+ * to prepare a striping for. Do not repeat but instead
+ * remove the repeated component & force the extention
+ * of the original one */
+ sd->sd_force = 1;
+ if (repeated) {
+ prev->llc_id = LCME_ID_INVAL;
+ change--;
+ }
+ }
+ }
+
+ if (change < 0) {
+ rc = lod_layout_del_prep_layout(env, lo, NULL);
+ if (rc < 0)
+ RETURN(rc);
+ LASSERTF(-rc == change,
+ "number deleted %d != requested %d\n", -rc,
+ change);
+ }
+ *max_comp = *max_comp + change;
+
+ /* lod_del_prep_layout reallocates ldo_comp_entries, so we must
+ * refresh these pointers before using them */
+ lod_comp = &lo->ldo_comp_entries[index];
+ prev = &lo->ldo_comp_entries[index - 1];
+ CDEBUG(D_LAYOUT, "After extent updates: prev start %llu, current start "
+ "%llu, current end %llu max_comp %d ldo_comp_cnt %d\n",
+ prev->llc_extent.e_start, lod_comp->llc_extent.e_start,
+ lod_comp->llc_extent.e_end, *max_comp, lo->ldo_comp_cnt);
+
+ /* Layout changed successfully */
+ RETURN(0);
+}
+
+/**
+ * Declare layout extent updates
+ *
+ * Handles extensions. Identifies extension components touched by current
+ * operation and passes them to processing function.
+ *
+ * Restarts with updated layouts from the processing function until the current
+ * operation no longer touches an extension space component.
+ *
+ * \param[in] env execution environment for this thread
+ * \param[in,out] lo object to update the layout of
+ * \param[in] extent layout extent for requested operation, update layout to
+ * fit this operation
+ * \param[in] th transaction handle for this operation
+ * \param[in] pick identifies chosen mirror for FLR layouts
+ * \param[in] write if this is write op
+ *
+ * \retval 1 on layout changed, 0 on no change
+ * \retval negative errno on error
+ */
+static int lod_declare_update_extents(const struct lu_env *env,
+ struct lod_object *lo, struct lu_extent *extent,
+ struct thandle *th, int pick, int write)
+{
+ struct lod_thread_info *info = lod_env_info(env);
+ struct lod_layout_component *lod_comp;
+ bool layout_changed = false;
+ struct sel_data sd = { 0 };
+ int start_index;
+ int i = 0;
+ int max_comp = 0;
+ int rc = 0, rc2;
+ int change = 0;
+ ENTRY;
+
+ /* This makes us work on the components of the chosen mirror */
+ start_index = lo->ldo_mirrors[pick].lme_start;
+ max_comp = lo->ldo_mirrors[pick].lme_end + 1;
+ if (lo->ldo_flr_state == LCM_FL_NONE)
+ LASSERT(start_index == 0 && max_comp == lo->ldo_comp_cnt);
+
+ CDEBUG(D_LAYOUT, "extent->e_start %llu, extent->e_end %llu\n",
+ extent->e_start, extent->e_end);
+ for (i = start_index; i < max_comp; i++) {
+ lod_comp = &lo->ldo_comp_entries[i];
+
+ /* We've passed all components of interest */
+ if (lod_comp->llc_extent.e_start >= extent->e_end)
+ break;
+
+ if (lod_comp->llc_flags & LCME_FL_EXTENSION) {
+ layout_changed = true;
+ rc = lod_sel_handler(env, lo, extent, th, &max_comp,
+ i, write, &sd);
+ if (rc < 0)
+ GOTO(out, rc);
+
+ /* Nothing has changed behind the prev one */
+ i -= 2;
+ continue;
+ }
+ }
+
+ /* We may have added or removed components. If so, we must update the
+ * start & ends of all the mirrors after the current one, and the end
+ * of the current mirror. */
+ change = max_comp - 1 - lo->ldo_mirrors[pick].lme_end;
+ if (change) {
+ lo->ldo_mirrors[pick].lme_end += change;
+ for (i = pick + 1; i < lo->ldo_mirror_count; i++) {
+ lo->ldo_mirrors[i].lme_start += change;
+ lo->ldo_mirrors[i].lme_end += change;
+ }
+ }
+
+ EXIT;
+out:
+ /* The amount of components has changed, adjust the lti_comp_idx */
+ rc2 = lod_layout_data_init(info, lo->ldo_comp_cnt);
+
+ return rc < 0 ? rc : rc2 < 0 ? rc2 : layout_changed;
+}
+
+/* If striping is already instantiated or INIT'ed DOM? */
+static bool lod_is_instantiation_needed(struct lod_layout_component *comp)
+{
+ return !(((lov_pattern(comp->llc_pattern) == LOV_PATTERN_MDT) &&
+ lod_comp_inited(comp)) || comp->llc_stripe);
+}
+
+/**
+ * Declare layout update for a non-FLR layout.
+ *
+ * \param[in] env execution environment for this thread
+ * \param[in,out] lo object to update the layout of
+ * \param[in] layout layout intent for requested operation, "update" is
+ * a process of reacting to this
+ * \param[in] buf buffer containing lov ea (see comment on usage inline)
+ * \param[in] th transaction handle for this operation
+ *
+ * \retval 0 on success
+ * \retval negative errno on error
+ */
+static int lod_declare_update_plain(const struct lu_env *env,
+ struct lod_object *lo, struct layout_intent *layout,
+ const struct lu_buf *buf, struct thandle *th)
+{
+ struct lod_thread_info *info = lod_env_info(env);
+ struct lod_device *d = lu2lod_dev(lo->ldo_obj.do_lu.lo_dev);
+ struct lod_layout_component *lod_comp;
+ struct lov_comp_md_v1 *comp_v1 = NULL;
+ bool layout_changed = false;
+ bool replay = false;
+ int i, rc;
+ ENTRY;
+
+ LASSERT(lo->ldo_flr_state == LCM_FL_NONE);
+
+ /*
+ * In case the client is passing lovea, which only happens during
+ * the replay of layout intent write RPC for now, we may need to
+ * parse the lovea and apply new layout configuration.
+ */
+ if (buf && buf->lb_len) {
+ struct lov_user_md_v1 *v1 = buf->lb_buf;
+
+ if (v1->lmm_magic != (LOV_MAGIC_DEFINED | LOV_MAGIC_COMP_V1) &&
+ v1->lmm_magic != __swab32(LOV_MAGIC_DEFINED |
+ LOV_MAGIC_COMP_V1)) {
+ CERROR("%s: the replay buffer of layout extend "
+ "(magic %#x) does not contain expected "
+ "composite layout.\n",
+ lod2obd(d)->obd_name, v1->lmm_magic);
+ GOTO(out, rc = -EINVAL);
+ }
+
+ rc = lod_use_defined_striping(env, lo, buf);
+ if (rc)
+ GOTO(out, rc);
+ lo->ldo_comp_cached = 1;
+
+ rc = lod_get_lov_ea(env, lo);
+ if (rc <= 0)
+ GOTO(out, rc);
+ /* old on-disk EA is stored in info->lti_buf */
+ comp_v1 = (struct lov_comp_md_v1 *)info->lti_buf.lb_buf;
+ replay = true;
+ layout_changed = true;
+
+ rc = lod_layout_data_init(info, lo->ldo_comp_cnt);
+ if (rc)
+ GOTO(out, rc);
+ } else {
+ /* non replay path */
+ rc = lod_striping_load(env, lo);
+ if (rc)
+ GOTO(out, rc);
+ }
+
+ /* Make sure defined layout covers the requested write range. */
+ lod_comp = &lo->ldo_comp_entries[lo->ldo_comp_cnt - 1];
+ if (lo->ldo_comp_cnt > 1 &&
+ lod_comp->llc_extent.e_end != OBD_OBJECT_EOF &&
+ lod_comp->llc_extent.e_end < layout->li_extent.e_end) {
+ CDEBUG_LIMIT(replay ? D_ERROR : D_LAYOUT,
+ "%s: the defined layout [0, %#llx) does not "
+ "covers the write range "DEXT"\n",
+ lod2obd(d)->obd_name, lod_comp->llc_extent.e_end,
+ PEXT(&layout->li_extent));
+ GOTO(out, rc = -EINVAL);
+ }
+
+ CDEBUG(D_LAYOUT, "%s: "DFID": update components "DEXT"\n",
+ lod2obd(d)->obd_name, PFID(lod_object_fid(lo)),
+ PEXT(&layout->li_extent));
+
+ if (!replay) {
+ rc = lod_declare_update_extents(env, lo, &layout->li_extent,
+ th, 0, layout->li_opc == LAYOUT_INTENT_WRITE);
+ if (rc < 0)
+ GOTO(out, rc);
+ else if (rc)
+ layout_changed = true;
+ }
+
+ /*
+ * Iterate ld->ldo_comp_entries, find the component whose extent under
+ * the write range and not instantianted.
+ */
+ for (i = 0; i < lo->ldo_comp_cnt; i++) {
+ lod_comp = &lo->ldo_comp_entries[i];
+
+ if (lod_comp->llc_extent.e_start >= layout->li_extent.e_end)
+ break;
+
+ if (!replay) {
+ /* If striping is instantiated or INIT'ed DOM skip */
+ if (!lod_is_instantiation_needed(lod_comp))
+ continue;
+ } else {
+ /**
+ * In replay path, lod_comp is the EA passed by
+ * client replay buffer, comp_v1 is the pre-recovery
+ * on-disk EA, we'd sift out those components which
+ * were init-ed in the on-disk EA.
+ */
+ if (le32_to_cpu(comp_v1->lcm_entries[i].lcme_flags) &