RETURN(rc);
}
+static __u32 lod_gen_component_id(struct lod_object *lo,
+ int mirror_id, int comp_idx);
+
+/**
+ * Repeat an existing component
+ *
+ * Creates a new layout by replicating an existing component. Uses striping
+ * policy from previous component as a template for the striping for the new
+ * new component.
+ *
+ * New component starts with zero length, will be extended (or removed) before
+ * returning layout to client.
+ *
+ * NB: Reallocates layout components array (lo->ldo_comp_entries), invalidating
+ * any pre-existing pointers to components. Handle with care.
+ *
+ * \param[in] env execution environment for this thread
+ * \param[in,out] lo object to update the layout of
+ * \param[in] index index of component to copy
+ *
+ * \retval 0 on success
+ * \retval negative errno on error
+ */
+static int lod_layout_repeat_comp(const struct lu_env *env,
+ struct lod_object *lo, int index)
+{
+ struct lod_layout_component *lod_comp;
+ struct lod_layout_component *new_comp = NULL;
+ struct lod_layout_component *comp_array;
+ int rc = 0, i, new_cnt = lo->ldo_comp_cnt + 1;
+ __u16 mirror_id;
+ int offset = 0;
+ ENTRY;
+
+ lod_comp = &lo->ldo_comp_entries[index];
+ LASSERT(lod_comp_inited(lod_comp) && lod_comp->llc_id != LCME_ID_INVAL);
+
+ CDEBUG(D_LAYOUT, "repeating component %d\n", index);
+
+ OBD_ALLOC(comp_array, sizeof(*comp_array) * new_cnt);
+ if (comp_array == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ for (i = 0; i < lo->ldo_comp_cnt; i++) {
+ memcpy(&comp_array[i + offset], &lo->ldo_comp_entries[i],
+ sizeof(*comp_array));
+
+ /* Duplicate this component in to the next slot */
+ if (i == index) {
+ new_comp = &comp_array[i + 1];
+ memcpy(&comp_array[i + 1], &lo->ldo_comp_entries[i],
+ sizeof(*comp_array));
+ /* We must now skip this new component when copying */
+ offset = 1;
+ }
+ }
+
+ /* Set up copied component */
+ new_comp->llc_flags &= ~LCME_FL_INIT;
+ new_comp->llc_stripe = NULL;
+ new_comp->llc_stripes_allocated = 0;
+ new_comp->llc_stripe_offset = LOV_OFFSET_DEFAULT;
+ /* for uninstantiated components, layout gen stores default stripe
+ * offset */
+ new_comp->llc_layout_gen = lod_comp->llc_stripe_offset;
+ /* This makes the repeated component zero-length, placed at the end of
+ * the preceding component */
+ new_comp->llc_extent.e_start = new_comp->llc_extent.e_end;
+ new_comp->llc_timestamp = lod_comp->llc_timestamp;
+ new_comp->llc_pool = NULL;
+
+ rc = lod_set_pool(&new_comp->llc_pool, lod_comp->llc_pool);
+ if (rc)
+ GOTO(out, rc);
+
+ if (new_comp->llc_ostlist.op_array) {
+ __u32 *op_array = NULL;
+
+ OBD_ALLOC(op_array, new_comp->llc_ostlist.op_size);
+ if (!op_array)
+ GOTO(out, rc = -ENOMEM);
+ memcpy(op_array, &new_comp->llc_ostlist.op_array,
+ new_comp->llc_ostlist.op_size);
+ new_comp->llc_ostlist.op_array = op_array;
+ }
+
+ OBD_FREE(lo->ldo_comp_entries,
+ sizeof(*comp_array) * lo->ldo_comp_cnt);
+ lo->ldo_comp_entries = comp_array;
+ lo->ldo_comp_cnt = new_cnt;
+
+ /* Generate an id for the new component */
+ mirror_id = mirror_id_of(new_comp->llc_id);
+ new_comp->llc_id = LCME_ID_INVAL;
+ new_comp->llc_id = lod_gen_component_id(lo, mirror_id, index + 1);
+ if (new_comp->llc_id == LCME_ID_INVAL)
+ GOTO(out, rc = -ERANGE);
+
+ EXIT;
+out:
+ if (rc)
+ OBD_FREE(comp_array, sizeof(*comp_array) * new_cnt);
+
+ return rc;
+}
+
static int lod_layout_data_init(struct lod_thread_info *info, __u32 comp_cnt)
{
ENTRY;
return new_end;
}
+/* 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
*
* 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 extend the current component
- * regardless.
+ * 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
struct lod_object *lo,
struct lu_extent *extent,
struct thandle *th, int *max_comp,
- int index, int write, int *force)
+ 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 *next = NULL;
__u64 extension_size;
__u64 new_end = 0;
+ bool repeated;
int change = 0;
int rc = 0;
ENTRY;
info->lti_count = 1;
info->lti_comp_idx[0] = index - 1;
rc = lod_declare_instantiate_components(env, lo, th);
- /* ENOSPC tells us we can't use this component, so it's the
- * same as if check_extension failed. But if there is no next,
- * we have no fall back if we failed to stripe this, and we
- * should return the error. */
- if (rc == -ENOSPC && next)
+ /* 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 (*force == 0 && rc == 0)
+ if (sd->sd_force == 0 && rc == 0)
rc = !lod_sel_osts_allowed(env, lo, index - 1,
extension_size, extent,
&lod_comp->llc_extent, write);
- *force = 0;
+
+ repeated = !!(sd->sd_repeat);
+ sd->sd_repeat = 0;
+ sd->sd_force = 0;
/* Extend previous component */
if (rc == 0) {
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 {
- *force = 1;
+ /* 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--;
+ }
}
}
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;
- int force = 0;
ENTRY;
/* This makes us work on the components of the chosen mirror */
if (lod_comp->llc_flags & LCME_FL_EXTENSION) {
layout_changed = true;
rc = lod_sel_handler(env, lo, extent, th, &max_comp,
- i, write, &force);
+ i, write, &sd);
if (rc < 0)
GOTO(out, rc);
}
}
- /* We may have 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.
- */
+ /* 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;
}
run_test 204c "FLR write/stale/resync test with component removal"
+# Successful repeated component in primary mirror
+test_204d() {
+ [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+ [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+ skip "skipped for lustre < $SEL_VERSION"
+
+ local comp_file=$DIR/$tdir/$tfile
+ local found=""
+
+ wait_delete_completed
+ wait_mds_ost_sync
+ test_mkdir $DIR/$tdir
+
+ # first mirror is 64M followed by extension space to -1, second mirror
+ # is 0-10M, then 10M-(-1)
+ $LFS setstripe -N -E-1 -z64M -N -E 10M -E-1 $comp_file ||
+ error "Create $comp_file failed"
+
+ local ost_idx1=$($LFS getstripe -I65537 -i $comp_file)
+ local ost_name=$(ostname_from_index $ost_idx1)
+ # degrade OST for first comp so we won't extend there
+ do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+ obdfilter.$ost_name.degraded=1
+ sleep_maxage
+
+ # Write beyond first component, causing repeat & stale second mirror
+ dd if=/dev/zero bs=1M count=1 seek=66 of=$comp_file conv=notrunc
+ RC=$?
+
+ do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+ obdfilter.$ost_name.degraded=0
+ sleep_maxage
+
+ [ $RC -eq 0 ] || error "dd to repeat & stale failed"
+
+ $LFS getstripe $comp_file
+
+ found=$($LFS find --component-start 64m --component-end 128m \
+ --component-flags init $comp_file | wc -l)
+ [ $found -eq 1 ] || error "write: Repeat comp incorrect"
+
+ local ost_idx2=$($LFS getstripe --component-start=64m \
+ --component-end=128m --component-flags=init \
+ -i $comp_file)
+ [[ $ost_idx1 -eq $ost_idx2 ]] && error "$ost_idx1 == $ost_idx2"
+ local mirror_id=$($LFS getstripe --component-start=64m \
+ --component-end=128m --component-flags=init \
+ $comp_file | grep lcme_mirror_id | awk '{ print $2 }')
+ [[ $mirror_id -eq 1 ]] ||
+ error "component not in correct mirror: $mirror_id, not 1"
+
+ $LFS mirror resync $comp_file
+
+ $LFS getstripe $comp_file
+
+ # component dimensions should not change from resync
+ found=$($LFS find --component-start 0m --component-end 64m \
+ --component-flags init $comp_file | wc -l)
+ [ $found -eq 1 ] || error "resync: first comp incorrect"
+ found=$($LFS find --component-start 64m --component-end 128m \
+ --component-flags init $comp_file | wc -l)
+ [ $found -eq 1 ] || error "resync: repeat comp incorrect"
+
+ sel_layout_sanity $comp_file 5
+
+ rm -f $comp_file
+}
+run_test 204d "FLR write/stale/resync sel test with repeated comp"
+
+# Successful repeated component, SEL in non-primary mirror
+test_204e() {
+ [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+ [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+ skip "skipped for lustre < $SEL_VERSION"
+
+ local comp_file=$DIR/$tdir/$tfile
+ local found=""
+
+ wait_delete_completed
+ wait_mds_ost_sync
+
+ test_mkdir $DIR/$tdir
+
+ # first mirror is is 0-100M, then 100M-(-1), second mirror is extension
+ # space to -1 (-z 64M, so first comp is 0-64M)
+ # Note: we have to place both 1st components on OST0, otherwise 2 OSTs
+ # will be not enough - one will be degraded, the other is used on
+ # an overlapping mirror.
+ $LFS setstripe -N -E 100M -i 0 -E-1 -N -E-1 -i 0 -z 64M $comp_file ||
+ error "Create $comp_file failed"
+
+ local ost_idx1=$($LFS getstripe --component-start=0 \
+ --component-end=64m -i $comp_file)
+ local ost_name=$(ostname_from_index $ost_idx1)
+ # degrade OST for first comp of 2nd mirror so we won't extend there
+ do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+ obdfilter.$ost_name.degraded=1
+ sleep_maxage
+
+ $LFS getstripe $comp_file
+
+ # Write to first component, stale & instantiate second mirror components
+ # overlapping with the written component (0-100M);
+ dd if=/dev/zero bs=2M count=1 of=$comp_file conv=notrunc
+ RC=$?
+
+ do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+ obdfilter.$ost_name.degraded=0
+ sleep_maxage
+ $LFS getstripe $comp_file
+
+ [ $RC -eq 0 ] || error "dd to repeat & stale failed"
+
+ found=$($LFS find --component-start 0m --component-end 64m \
+ --component-flags init,stale $comp_file | wc -l)
+ [ $found -eq 1 ] || error "write: first comp incorrect"
+
+ # was repeated due to degraded ost
+ found=$($LFS find --component-start 64m --component-end 128m \
+ --component-flags init,stale $comp_file | wc -l)
+ [ $found -eq 1 ] || error "write: repeated comp incorrect"
+
+ local ost_idx2=$($LFS getstripe --component-start=64m \
+ --component-end=128m --component-flags=init \
+ -i $comp_file)
+ [[ $ost_idx1 -eq $ost_idx2 ]] && error "$ost_idx1 == $ost_idx2"
+ local mirror_id=$($LFS getstripe --component-start=0m \
+ --component-end=64m --component-flags=init \
+ $comp_file | grep lcme_mirror_id | awk '{ print $2 }')
+ [[ $mirror_id -eq 2 ]] ||
+ error "component not in correct mirror? $mirror_id"
+
+ $LFS mirror resync $comp_file
+
+ $LFS getstripe $comp_file
+
+ # component dimensions should not change from resync
+ found=$($LFS find --component-start 0m --component-end 64m \
+ --component-flags init,^stale $comp_file | wc -l)
+ [ $found -eq 1 ] || error "resync: first comp incorrect"
+ found=$($LFS find --component-start 64m --component-end 128m \
+ --component-flags init,^stale $comp_file | wc -l)
+ [ $found -eq 1 ] || error "resync: repeated comp incorrect"
+
+ sel_layout_sanity $comp_file 5
+
+ rm -f $comp_file
+}
+run_test 204e "FLR write/stale/resync sel test with repeated comp"
+
+# FLR + SEL: failed repeated component, SEL in non-primary mirror
+test_204f() {
+ [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+ [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+ skip "skipped for lustre < $SEL_VERSION"
+
+ local comp_file=$DIR/$tdir/$tfile
+ local found=""
+
+ wait_delete_completed
+ wait_mds_ost_sync
+ test_mkdir $DIR/$tdir
+
+ pool_add $TESTNAME || error "Pool creation failed"
+ pool_add_targets $TESTNAME 0 1 || error "Pool add targets failed"
+
+ # first mirror is is 0-100M, then 100M-(-1), second mirror is extension
+ # space to -1 (-z 64M, so first comp is 0-64M)
+ $LFS setstripe -N -E 100M -E-1 -N --pool="$TESTNAME" \
+ -E-1 -c 1 -z 64M $comp_file || error "Create $comp_file failed"
+
+ local ost_name0=$(ostname_from_index 0)
+ local ost_name1=$(ostname_from_index 1)
+
+ # degrade both OSTs in pool, so we'll try to repeat, then fail and
+ # extend original comp
+ do_facet ost1 $LCTL set_param -n obdfilter.$ost_name0.degraded=1
+ do_facet ost2 $LCTL set_param -n obdfilter.$ost_name1.degraded=1
+ sleep_maxage
+
+ # a write to the 1st component, 100M length, which will try to stale
+ # the first 100M of mirror 2, attempting to extend its 0-64M component
+ dd if=/dev/zero bs=2M count=1 of=$comp_file conv=notrunc
+ RC=$?
+
+ do_facet ost1 $LCTL set_param -n obdfilter.$ost_name0.degraded=0
+ do_facet ost2 $LCTL set_param -n obdfilter.$ost_name1.degraded=0
+ sleep_maxage
+
+ [ $RC -eq 0 ] || error "dd to extend mirror comp failed"
+
+ $LFS getstripe $comp_file
+
+ found=$($LFS find --component-start 0m --component-end 128m \
+ --component-flags init,stale $comp_file | wc -l)
+ [ $found -eq 1 ] || error "write: First mirror comp incorrect"
+
+ local mirror_id=$($LFS getstripe --component-start=0m \
+ --component-end=128m --component-flags=init \
+ $comp_file | grep lcme_mirror_id | awk '{ print $2 }')
+
+ [[ $mirror_id -eq 2 ]] ||
+ error "component not in correct mirror? $mirror_id, not 2"
+
+ $LFS mirror resync $comp_file
+
+ $LFS getstripe $comp_file
+
+ # component dimensions should not change from resync
+ found=$($LFS find --component-start 0m --component-end 128m \
+ --component-flags init,^stale $comp_file | wc -l)
+ [ $found -eq 1 ] || error "resync: First mirror comp incorrect"
+
+ sel_layout_sanity $comp_file 4
+
+ rm -f $comp_file
+}
+run_test 204f "FLR write/stale/resync sel w/forced extension"
+
complete $SECONDS
check_and_cleanup_lustre
exit_status
}
run_test 21b "DoM followed by extendable component with removal"
+# Test of repeat component behavior with OOS/degraded OST
+test_22a() {
+ [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+ [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+ skip "skipped for lustre < $SEL_VER"
+
+ local comp_file=$DIR/$tdir/$tfile
+ local flg_opts=""
+ local found=""
+
+ test_mkdir -p $DIR/$tdir
+
+ $LFS setstripe -E -1 -c 1 -z 128M $comp_file ||
+ error "Create $comp_file failed"
+
+ local ost_idx1=$($LFS getstripe -I1 -i $comp_file)
+ local ost_name=$(ostname_from_index $ost_idx1)
+
+ # write past end of first component, so it is extended
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=130 ||
+ error "dd to extend failed"
+
+ flg_opts="--comp-flags extension"
+ found=$($LFS find --comp-start 256M -E EOF $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: second component not found"
+
+ # degrade OST for component 1
+ do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+ obdfilter.$ost_name.degraded=1
+ # sleep to guarantee we see the degradation
+ sleep_maxage
+
+ # un-degrade on exit
+ stack_trap "do_facet ost$((ost_idx1+1)) $LCTL set_param -n \
+ obdfilter.$ost_name.degraded=0; sleep_maxage" EXIT
+
+ replay_barrier $SINGLEMDS
+
+ # seek past the end of current comp & write, should cause a new comp
+ # to be created (ie repeat previous comp)
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=300 ||
+ error "dd to repeat failed"
+
+ local ost_idx2=$($LFS getstripe -I2 -i $comp_file)
+
+ [ $ost_idx1 -eq $ost_idx2 ] && error "$ost_idx1 == $ost_idx2"
+
+ flg_opts="--comp-flags init"
+ found=$($LFS find --comp-start 256M $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: second component not found"
+
+ flg_opts="--comp-flags extension"
+ found=$($LFS find --comp-start 384M -E EOF $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: extension component not found"
+
+ fail $SINGLEMDS
+
+ local ost_idx2_2=$($LFS getstripe -I2 -i $comp_file)
+ [ $ost_idx2_2 -ne $ost_idx2 ] && error "$ost_idx2_2 != $ost_idx2"
+
+ flg_opts="--comp-flags init"
+ found=$($LFS find --comp-start 256M $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Failover: second component not found"
+
+ flg_opts="--comp-flags extension"
+ found=$($LFS find --comp-start 384M -E EOF $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Failover: extension component not found"
+
+ sel_layout_sanity $comp_file 3
+}
+run_test 22a "Test repeat component behavior with degraded OST"
+
+# Test repeat behavior with low space
+test_22b() {
+ [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+ [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+ skip "skipped for lustre < $SEL_VER"
+
+ local comp_file=$DIR/$tdir/$tfile
+ local flg_opts=""
+ local found=""
+
+ test_mkdir -p $DIR/$tdir
+
+ # without this, a previous delete can finish after we check free space
+ wait_delete_completed
+ wait_mds_ost_sync
+
+ $LFS setstripe -E -1 -c 1 -z 128M \
+ $comp_file || error "Create $comp_file failed"
+
+ # write past end of first component, so it is extended
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=130 ||
+ error "dd to extend failed"
+
+ flg_opts="--comp-flags extension"
+ found=$($LFS find --comp-start 256M -E EOF $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: Second component not found"
+
+ # set our OST low on space
+ local ost_idx1=$($LFS getstripe -I1 -i $comp_file)
+ local wms=$(ost_watermarks_set_low_space $ost_idx1 | grep "watermarks")
+
+ stack_trap "ost_watermarks_clear_enospc $tfile $ost_idx1 $wms" EXIT
+
+ # Write past end of current space, fail to extend, causing repeat
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=300 ||
+ error "dd to repeat failed"
+
+ $LFS getstripe $comp_file
+
+ local ost_idx2=$($LFS getstripe -I2 -i $comp_file)
+
+ [ $ost_idx1 -eq $ost_idx2 ] && error "$ost_idx1 == $ost_idx2"
+
+ flg_opts="--comp-flags init"
+ found=$($LFS find --comp-start 256M $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: Second component not found"
+
+ flg_opts="--comp-flags extension"
+ found=$($LFS find --comp-start 384M -E EOF $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: Extension component not found"
+
+ sel_layout_sanity $comp_file 3
+}
+run_test 22b "Test simple 'out of space' condition with repeat"
+
+# This tests both "repeat" and "extend in place when repeat fails" aspects
+# of repeating components
+test_22c() {
+ [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+ [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+ skip "skipped for lustre < $SEL_VER"
+
+ local comp_file=$DIR/$tdir/$tfile
+ local flg_opts=""
+ local found=""
+
+ test_mkdir -p $DIR/$tdir
+
+ # pool is used to limit available OSTs to 0 and 1, so we can set all
+ # available OSTs out of space
+ pool_add $TESTNAME || error "Pool creation failed"
+ pool_add_targets $TESTNAME 0 1 || error "Pool add targets failed"
+
+ # without this, a previous delete can finish after we check free space
+ wait_delete_completed
+ wait_mds_ost_sync
+
+ $LFS setstripe -E -1 -z 64M -c 1 -p "$TESTNAME" $comp_file || \
+ error "Create $comp_file failed"
+
+ # write past end of first component, so it is extended
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=80 conv=notrunc ||
+ error "dd to extend failed"
+
+ $LFS getstripe $comp_file
+
+ flg_opts="--comp-flags extension"
+ found=$($LFS find --comp-start 128M -E EOF $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: second component not found"
+
+ # set our OST out of space
+ local ost_idx1=$($LFS getstripe -I1 -i $comp_file)
+ local wms=$(ost_watermarks_set_enospc $tfile $ost_idx1 |
+ grep "watermarks")
+ stack_trap "ost_watermarks_clear_enospc $tfile $ost_idx1 $wms" EXIT
+
+ # This should create a repeat component on a new OST
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=180 conv=notrunc ||
+ error "dd to repeat failed"
+
+ $LFS getstripe $comp_file
+
+ local comp_cnt=$($LFS getstripe --component-count $comp_file)
+ [ $comp_cnt -ne 3 ] && error "component count: $comp_cnt, should be 3"
+
+ # New second component should be on a different OST
+ local ost_idx2=$($LFS getstripe --comp-start=128m \
+ --comp-end=192m --comp-flags=init -i $comp_file)
+
+ [ $ost_idx1 -eq $ost_idx2 ] && error "2nd comp: same OST $ost_idx1"
+
+ local wms2=$(ost_watermarks_set_enospc $tfile $ost_idx2 |
+ grep "watermarks")
+ stack_trap "ost_watermarks_clear_enospc $tfile $ost_idx2 $wms2" EXIT
+
+ # now that the second OST is out of space (as is the first OST), we
+ # attempt to extend. This should result in an extension of the
+ # existing component, rather than a new component.
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=240 conv=notrunc ||
+ error "dd for forced extension failed"
+
+ $LFS getstripe $comp_file
+
+ # clear out of space on first OST
+ ost_watermarks_clear_enospc $tfile $ost_idx1 $wms
+
+ # finally, now that the first OST has space again, we attempt to
+ # extend one last time. This should create a new component on the
+ # first OST
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=300 conv=notrunc ||
+ error "dd for repeat on first OST failed"
+
+ $LFS getstripe $comp_file
+
+ flg_opts="--comp-flags init"
+ found=$($LFS find --comp-start 128M $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: second component not found"
+
+ flg_opts="--comp-flags init"
+ found=$($LFS find --comp-start 256M $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: third component not found"
+
+ flg_opts="--comp-flags extension"
+ found=$($LFS find --comp-start 320M -E EOF $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Write: extension component not found"
+
+ sel_layout_sanity $comp_file 4
+}
+run_test 22c "Test repeat with out of space on > 1 OST"
+
+test_22d_post_check() {
+ local comp_file=$1
+ local name=$2
+ local flg_opts="--comp-flags init"
+ local found=$($LFS find --comp-start 0M -E 128M $flg_opts $comp_file |
+ wc -l)
+ [ $found -eq 1 ] || {
+ $LFS getstripe $comp_file
+ error "$name: second component not found"
+ }
+
+ flg_opts="--comp-flags extension"
+ found=$($LFS find --comp-start 128M -E EOF $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "$name: third extension component not found"
+
+ sel_layout_sanity $comp_file 2
+}
+
+test_22d_pre() {
+ local comp_file=$1
+ local wms="$2"
+ local RC
+
+ # write past end of first component
+ dd if=/dev/zero of=$comp_file bs=1M count=1 seek=70
+ RC=$?
+
+ ost_watermarks_clear_enospc $tfile 0 $wms
+ [ $RC -eq 0 ] || error "dd to force extend failed"
+
+ test_22d_post_check $comp_file "Write"
+}
+
+test_22d() {
+ [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+ [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+ skip "skipped for lustre < $SEL_VER"
+
+ local comp_file=$DIR/$tdir/$tfile
+ local flg_opts=""
+ local found=""
+
+ test_mkdir -p $DIR/$tdir
+
+ # without this, a previous delete can finish after we check free space
+ wait_delete_completed
+ wait_mds_ost_sync
+
+ # Pool allows us to force use of only certain OSTs
+ pool_add $TESTNAME || error "Pool creation failed"
+ pool_add_targets $TESTNAME 0 || error "Pool add targets failed"
+
+ # 1. Fail to extend due to OOS, try to repeat within the same pool,
+ # fail to stripe (again OOS) the 0-length component, remove the
+ # repeated one, force the extension on the original one.
+ $LFS setstripe -E -1 -p $TESTNAME -z 64M $comp_file ||
+ error "Create $comp_file failed"
+
+ replay_barrier $SINGLEMDS
+
+ # set our OST out of space
+ local wms=$(ost_watermarks_set_enospc $tfile 0 | grep "watermarks")
+
+ test_22d_pre $comp_file "$wms"
+ fail $SINGLEMDS
+ test_22d_post_check $comp_file "Failover"
+
+ # 2. repeat with low on space: 0-length repeated component will be
+ # striped, but still fails to be extended; otherwise the same as (1).
+ rm -f $comp_file
+ $LFS setstripe -E -1 -p $TESTNAME -z 64M $comp_file ||
+ error "Create $comp_file failed"
+
+ replay_barrier $SINGLEMDS
+
+ # set our OST low on space
+ local wms=$(ost_watermarks_set_low_space 0 | grep "watermarks")
+
+ test_22d_pre $comp_file "$wms"
+ fail $SINGLEMDS
+ test_22d_post_check $comp_file "Failover"
+}
+run_test 22d "out of/low on space + failed to repeat + forced extension"
+
test_23a() {
[ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
[ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
}
run_test 23e "Append with next real comp: spillover and backward extension"
+test_23f() {
+ [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+ [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+ skip "skipped for lustre < $SEL_VER"
+
+ local comp_file=$DIR/$tdir/$tfile
+ test_mkdir -p $DIR/$tdir
+
+ $LFS setstripe -z 64M -c 1 -E -1 $comp_file ||
+ error "Create $comp_file failed"
+
+ local ost_idx=$($LFS getstripe -I1 -i $comp_file)
+ local wms=$(ost_watermarks_set_low_space $ost_idx | grep "watermarks")
+
+ dd if=/dev/zero bs=1M oflag=append count=1 of=$comp_file
+ RC=$?
+
+ ost_watermarks_clear_enospc $tfile $ost_idx $wms
+ [ $RC -eq 0 ] || error "dd append failed"
+
+ local flg_opts="--comp-start 64M -E EOF --comp-flags init"
+ local found=$($LFS find $flg_opts $comp_file | wc -l)
+ [ $found -eq 1 ] || error "Append: component (64M-EOF) not found"
+
+ ost_idx=$($LFS getstripe -I2 -i $comp_file)
+ [ "$ost_idx" != "" ] && error "Append: extension component still exists"
+
+ sel_layout_sanity $comp_file 2
+}
+run_test 23f "Append with low on space: repeat and remove EXT comp"
+
complete $SECONDS
check_and_cleanup_lustre
exit_status