Whamcloud - gitweb
LU-10070 lod: SEL: Implement basic spillover space 83/33783/24
authorPatrick Farrell <paf@cray.com>
Mon, 3 Jun 2019 16:24:29 +0000 (19:24 +0300)
committerOleg Drokin <green@whamcloud.com>
Fri, 12 Jul 2019 05:21:02 +0000 (05:21 +0000)
This is a barebones implementation of spillover space.
This allows the creation of extendable layout components,
which are normal layout components followed by "extension
components".  These extension components are never
initialized, instead, when i/o reaches them, the server
checks if there is sufficient space on the preceding normal
layout component, and if so, it modifies the extent of the
component to give space to the preceding component.

If there is not sufficient space on those OSTs, the special
extension space component can be removed, and the next
component of the layout is moved down to meet the existing
component.  This allows i/o to "spill over" to this new
layout component, which is expected to be on different
OSTs.

For multi-tiered systems, this makes it possible to avoid
the situation where an inner tier is low on space, but a
an outer tier has plenty, and PFL files cannot use the
space in the outer tier because the inner is full.

This patch requires the next patch in the series for FLR
support, but does not depend on the other subsequent
patches in this series.

Cray-bug-id: LUS-2528
Signed-off-by: Patrick Farrell <paf@cray.com>
Change-Id: I8f6c6df8ee155033d5278535dc456e604552e409
Reviewed-on: https://review.whamcloud.com/33783
Reviewed-by: Patrick Farrell <pfarrell@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Alexey Lyashkov <c17817@cray.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
26 files changed:
lustre/doc/lfs-setstripe.1
lustre/doc/llapi_layout_extension_size_get.3
lustre/include/dt_object.h
lustre/include/uapi/linux/lustre/lustre_user.h
lustre/lod/lod_dev.c
lustre/lod/lod_internal.h
lustre/lod/lod_lov.c
lustre/lod/lod_object.c
lustre/lod/lod_qos.c
lustre/lod/lproc_lod.c
lustre/mdd/mdd_device.c
lustre/mdt/mdt_handler.c
lustre/obdclass/dt_object.c
lustre/obdclass/llog_cat.c
lustre/obdclass/obd_mount_server.c
lustre/ofd/ofd_obd.c
lustre/osd-ldiskfs/osd_handler.c
lustre/osd-ldiskfs/osd_internal.h
lustre/osd-zfs/osd_handler.c
lustre/osd-zfs/osd_internal.h
lustre/osp/osp_dev.c
lustre/osp/osp_precreate.c
lustre/target/tgt_grant.c
lustre/tests/sanity-pfl.sh
lustre/tests/test-framework.sh
lustre/utils/liblustreapi_layout.c

index 0ff3660..a4cc7ef 100644 (file)
@@ -488,7 +488,7 @@ writing beyond 192MiB, the first component is left as [0, 192MiB), and a new
 component is allocated between them, its layout repeats the first component
 layout but initialized on different OSTs so that the full OSTs are avoided.
 It is allocated and immediately extended to [192MiB, 256MiB), the following
 component is allocated between them, its layout repeats the first component
 layout but initialized on different OSTs so that the full OSTs are avoided.
 It is allocated and immediately extended to [192MiB, 256MiB), the following
-extension component is shortended again.
+extension component is shortened again.
 .RE
 .TP
 .B lfs setstripe -E 1G -z 64M -E 100G -z 256M -E -1 -z 1G /mnt/lustre/file1
 .RE
 .TP
 .B lfs setstripe -E 1G -z 64M -E 100G -z 256M -E -1 -z 1G /mnt/lustre/file1
index 57a0d31..5a78f92 100644 (file)
@@ -14,10 +14,10 @@ the extension size of an extension component of a Lustre file
 .fi
 .SH DESCRIPTION
 .PP
 .fi
 .SH DESCRIPTION
 .PP
-The extension size is the unit of increasing the previous component size when
+The extension size is the unit of increase the previous component size when
 writing within the region of the current extension component. At the time of the
 change the OSTs of the previous component layout are checked if they have
 writing within the region of the current extension component. At the time of the
 change the OSTs of the previous component layout are checked if they have
-at least \fIext_size\fR free space. In case there is no enough free space,
+at least \fIext_size\fR free space. In case there is not enough free space,
 the space covered by the extension component spills over to the next component
 (see examples in \fBlfs-setstripe (1)\fR).
 .PP
 the space covered by the extension component spills over to the next component
 (see examples in \fBlfs-setstripe (1)\fR).
 .PP
index 7c4f4e3..5ff7815 100644 (file)
@@ -133,7 +133,8 @@ struct dt_device_operations {
          */
         int   (*dt_statfs)(const struct lu_env *env,
                           struct dt_device *dev,
          */
         int   (*dt_statfs)(const struct lu_env *env,
                           struct dt_device *dev,
-                          struct obd_statfs *osfs);
+                          struct obd_statfs *osfs,
+                          struct obd_statfs_info *info);
 
         /**
         * Create transaction.
 
         /**
         * Create transaction.
@@ -2514,12 +2515,13 @@ static inline int dt_fiemap_get(const struct lu_env *env, struct dt_object *d,
 }
 
 static inline int dt_statfs(const struct lu_env *env, struct dt_device *dev,
 }
 
 static inline int dt_statfs(const struct lu_env *env, struct dt_device *dev,
-                            struct obd_statfs *osfs)
+                           struct obd_statfs *osfs,
+                           struct obd_statfs_info *info)
 {
 {
-        LASSERT(dev);
-        LASSERT(dev->dd_ops);
-        LASSERT(dev->dd_ops->dt_statfs);
-        return dev->dd_ops->dt_statfs(env, dev, osfs);
+       LASSERT(dev);
+       LASSERT(dev->dd_ops);
+       LASSERT(dev->dd_ops->dt_statfs);
+       return dev->dd_ops->dt_statfs(env, dev, osfs, info);
 }
 
 static inline int dt_root_get(const struct lu_env *env, struct dt_device *dev,
 }
 
 static inline int dt_root_get(const struct lu_env *env, struct dt_device *dev,
index 86bfb05..bb93afb 100644 (file)
@@ -161,6 +161,13 @@ struct obd_statfs {
        __u32           os_spare9;
 };
 
        __u32           os_spare9;
 };
 
+/** additional filesystem attributes for target device */
+struct obd_statfs_info {
+       __u32           os_reserved_mb_low;     /* reserved mb low */
+       __u32           os_reserved_mb_high;    /* reserved mb high */
+       bool            os_enable_pre;          /* enable pre create logic */
+};
+
 /**
  * File IDentifier.
  *
 /**
  * File IDentifier.
  *
index a1d07ad..ceed008 100644 (file)
@@ -1320,8 +1320,8 @@ static void lod_statfs_sum(struct obd_statfs *sfs,
  *
  * see include/dt_object.h for the details.
  */
  *
  * see include/dt_object.h for the details.
  */
-static int lod_statfs(const struct lu_env *env,
-                     struct dt_device *dev, struct obd_statfs *sfs)
+static int lod_statfs(const struct lu_env *env, struct dt_device *dev,
+                     struct obd_statfs *sfs, struct obd_statfs_info *info)
 {
        struct lod_device *lod = dt2lod_dev(dev);
        struct lod_ost_desc *ost;
 {
        struct lod_device *lod = dt2lod_dev(dev);
        struct lod_ost_desc *ost;
@@ -1331,7 +1331,7 @@ static int lod_statfs(const struct lu_env *env,
        u64 ost_ffree = 0;
        int i, rc, bs;
 
        u64 ost_ffree = 0;
        int i, rc, bs;
 
-       rc = dt_statfs(env, dt2lod_dev(dev)->lod_child, sfs);
+       rc = dt_statfs(env, dt2lod_dev(dev)->lod_child, sfs, NULL);
        if (rc)
                GOTO(out, rc);
 
        if (rc)
                GOTO(out, rc);
 
@@ -1346,7 +1346,7 @@ static int lod_statfs(const struct lu_env *env,
        lod_foreach_mdt(lod, i) {
                mdt = MDT_TGT(lod, i);
                LASSERT(mdt && mdt->ltd_mdt);
        lod_foreach_mdt(lod, i) {
                mdt = MDT_TGT(lod, i);
                LASSERT(mdt && mdt->ltd_mdt);
-               rc = dt_statfs(env, mdt->ltd_mdt, &ost_sfs);
+               rc = dt_statfs(env, mdt->ltd_mdt, &ost_sfs, NULL);
                /* ignore errors */
                if (rc)
                        continue;
                /* ignore errors */
                if (rc)
                        continue;
@@ -1365,7 +1365,7 @@ static int lod_statfs(const struct lu_env *env,
        lod_foreach_ost(lod, i) {
                ost = OST_TGT(lod, i);
                LASSERT(ost && ost->ltd_ost);
        lod_foreach_ost(lod, i) {
                ost = OST_TGT(lod, i);
                LASSERT(ost && ost->ltd_ost);
-               rc = dt_statfs(env, ost->ltd_ost, &ost_sfs);
+               rc = dt_statfs(env, ost->ltd_ost, &ost_sfs, NULL);
                /* ignore errors */
                if (rc || ost_sfs.os_bsize == 0)
                        continue;
                /* ignore errors */
                if (rc || ost_sfs.os_bsize == 0)
                        continue;
index 83ceeb8..e30be97 100644 (file)
@@ -706,6 +706,9 @@ __u16 lod_comp_entry_stripe_count(struct lod_object *lo,
 __u16 lod_get_stripe_count(struct lod_device *lod, struct lod_object *lo,
                           __u16 stripe_count, bool overstriping);
 void lod_qos_statfs_update(const struct lu_env *env, struct lod_device *lod);
 __u16 lod_get_stripe_count(struct lod_device *lod, struct lod_object *lo,
                           __u16 stripe_count, bool overstriping);
 void lod_qos_statfs_update(const struct lu_env *env, struct lod_device *lod);
+int lod_statfs_and_check(const struct lu_env *env, struct lod_device *d,
+                        int index, struct obd_statfs *sfs,
+                        struct obd_statfs_info *info);
 
 /* lproc_lod.c */
 int lod_procfs_init(struct lod_device *lod);
 
 /* lproc_lod.c */
 int lod_procfs_init(struct lod_device *lod);
index b60700c..aafb4a6 100644 (file)
@@ -1946,7 +1946,7 @@ recheck:
        for_each_comp_entry_v1(comp_v1, ent) {
                ext = &ent->lcme_extent;
 
        for_each_comp_entry_v1(comp_v1, ent) {
                ext = &ent->lcme_extent;
 
-               if (le64_to_cpu(ext->e_start) >= le64_to_cpu(ext->e_end)) {
+               if (le64_to_cpu(ext->e_start) > le64_to_cpu(ext->e_end)) {
                        CDEBUG(D_LAYOUT, "invalid extent "DEXT"\n",
                               le64_to_cpu(ext->e_start),
                               le64_to_cpu(ext->e_end));
                        CDEBUG(D_LAYOUT, "invalid extent "DEXT"\n",
                               le64_to_cpu(ext->e_start),
                               le64_to_cpu(ext->e_end));
@@ -2046,7 +2046,7 @@ recheck:
                stripe_size = le32_to_cpu(lum->lmm_stripe_size);
                if (stripe_size == 0)
                        stripe_size = desc->ld_default_stripe_size;
                stripe_size = le32_to_cpu(lum->lmm_stripe_size);
                if (stripe_size == 0)
                        stripe_size = desc->ld_default_stripe_size;
-               if (stripe_size == 0 || (prev_end & (stripe_size - 1))) {
+               if (prev_end % stripe_size) {
                        CDEBUG(D_LAYOUT, "stripe size isn't aligned, "
                               "stripe_sz: %u, [%llu, %llu)\n",
                               stripe_size, ext->e_start, prev_end);
                        CDEBUG(D_LAYOUT, "stripe size isn't aligned, "
                               "stripe_sz: %u, [%llu, %llu)\n",
                               stripe_size, ext->e_start, prev_end);
index 8c20f0d..e69ecf8 100644 (file)
@@ -2032,7 +2032,7 @@ static int lod_prep_md_striped_create(const struct lu_env *env,
                                continue;
 
                        tgt_dt = tgt->ltd_tgt;
                                continue;
 
                        tgt_dt = tgt->ltd_tgt;
-                       rc = dt_statfs(env, tgt_dt, &info->lti_osfs);
+                       rc = dt_statfs(env, tgt_dt, &info->lti_osfs, NULL);
                        if (rc) {
                                /* this OSP doesn't feel well */
                                rc = 0;
                        if (rc) {
                                /* this OSP doesn't feel well */
                                rc = 0;
@@ -6136,6 +6136,511 @@ static int lod_declare_instantiate_components(const struct lu_env *env,
        RETURN(rc);
 }
 
        RETURN(rc);
 }
 
+/**
+ * Check OSTs for an existing component for further extension
+ *
+ * Checks if OSTs are still healthy and not out of space.  Gets free space
+ * on OSTs (relative to allocation watermark rmb_low) and compares to
+ * the proposed new_end for this component.
+ *
+ * Decides whether or not to extend a component on its current OSTs.
+ *
+ * \param[in] env              execution environment for this thread
+ * \param[in] lo               object we're checking
+ * \param[in] index            index of this component
+ * \param[in] extension_size   extension size for this component
+ * \param[in] extent           layout extent for requested operation
+ * \param[in] comp_extent      extension component extent
+ * \param[in] write            if this is write operation
+ *
+ * \retval     true - OK to extend on current OSTs
+ * \retval     false - do not extend on current OSTs
+ */
+static bool lod_sel_osts_allowed(const struct lu_env *env,
+                                struct lod_object *lo,
+                                int index, __u64 extension_size,
+                                struct lu_extent *extent,
+                                struct lu_extent *comp_extent, int write)
+{
+       struct lod_layout_component *lod_comp = &lo->ldo_comp_entries[index];
+       struct lod_device *lod = lu2lod_dev(lo->ldo_obj.do_lu.lo_dev);
+       struct obd_statfs *sfs = &lod_env_info(env)->lti_osfs;
+       __u64 available = 0;
+       __u64 size;
+       bool ret = true;
+       int i, rc;
+
+       ENTRY;
+
+       LASSERT(lod_comp->llc_stripe_count != 0);
+
+       if (write == 0 ||
+           (extent->e_start == 0 && extent->e_end == OBD_OBJECT_EOF)) {
+               /* truncate or append */
+               size = extension_size;
+       } else {
+               /* In case of write op, check the real write extent,
+                * it may be larger than the extension_size */
+               size = roundup(min(extent->e_end, comp_extent->e_end) -
+                              max(extent->e_start, comp_extent->e_start),
+                              extension_size);
+       }
+       /* extension_size is file level, so we must divide by stripe count to
+        * compare it to available space on a single OST */
+       size /= lod_comp->llc_stripe_count;
+
+       lod_getref(&lod->lod_ost_descs);
+       for (i = 0; i < lod_comp->llc_stripe_count; i++) {
+               int index = lod_comp->llc_ost_indices[i];
+               struct lod_tgt_desc *ost = OST_TGT(lod, index);
+               struct obd_statfs_info info = { 0 };
+               int j, repeated = 0;
+
+               LASSERT(ost);
+
+               /* Get the number of times this OST repeats in this component.
+                * Note: inter-component repeats are not counted as this is
+                * considered as a rare case: we try to not repeat OST in other
+                * components if possible. */
+               for (j = 0; j < lod_comp->llc_stripe_count; j++) {
+                       if (index != lod_comp->llc_ost_indices[j])
+                               continue;
+
+                       /* already handled */
+                       if (j < i)
+                               break;
+
+                       repeated++;
+               }
+               if (j < lod_comp->llc_stripe_count)
+                       continue;
+
+               if (!cfs_bitmap_check(lod->lod_ost_bitmap, index)) {
+                       CDEBUG(D_LAYOUT, "ost %d no longer present\n", index);
+                       ret = false;
+                       break;
+               }
+
+               rc = dt_statfs(env, ost->ltd_ost, sfs, &info);
+               if (rc) {
+                       CDEBUG(D_LAYOUT, "statfs failed for ost %d, error %d\n",
+                              index, rc);
+                       ret = false;
+                       break;
+               }
+
+               if (sfs->os_state & OS_STATE_ENOSPC ||
+                   sfs->os_state & OS_STATE_READONLY ||
+                   sfs->os_state & OS_STATE_DEGRADED) {
+                       CDEBUG(D_LAYOUT, "ost %d is not availble for SEL "
+                              "extension, state %u\n", index, sfs->os_state);
+                       ret = false;
+                       break;
+               }
+
+               /* In bytes */
+               available = sfs->os_bavail * sfs->os_bsize;
+               /* 'available' is relative to the allocation threshold */
+               available -= (__u64) info.os_reserved_mb_low << 20;
+
+               CDEBUG(D_LAYOUT, "ost %d lowwm: %d highwm: %d, "
+                      "%llu %% blocks available, %llu %% blocks free\n",
+                      index, info.os_reserved_mb_low, info.os_reserved_mb_high,
+                      (100ull * sfs->os_bavail) / sfs->os_blocks,
+                      (100ull * sfs->os_bfree) / sfs->os_blocks);
+
+               if (size * repeated > available) {
+                       ret = false;
+                       CDEBUG(D_LAYOUT, "low space on ost %d, available %llu "
+                              "< extension size %llu\n", index, available,
+                              extension_size);
+                       break;
+               }
+       }
+       lod_putref(lod, &lod->lod_ost_descs);
+
+       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;
+}
+
+/**
+ * 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 extend the current component
+ *       regardless.
+ *
+ * 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, int *force)
+{
+       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;
+       __u64 new_end = 0;
+       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);
+       }
+
+       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);
+               /* 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)
+                       rc = 1;
+               if (rc < 0)
+                       RETURN(rc);
+       }
+
+       if (*force == 0 && rc == 0)
+               rc = !lod_sel_osts_allowed(env, lo, index - 1,
+                                          extension_size, extent,
+                                          &lod_comp->llc_extent, write);
+       *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 {
+                       *force = 1;
+               }
+       }
+
+       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;
+       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 */
+       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, &force);
+                       if (rc < 0)
+                               GOTO(out, rc);
+
+                       /* Nothing has changed behind the prev one */
+                       i -= 2;
+                       continue;
+               }
+       }
+
+       /* 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.
+        */
+       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)
 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)
@@ -6144,6 +6649,7 @@ static int lod_declare_update_plain(const struct lu_env *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;
        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;
        bool replay = false;
        int i, rc;
        ENTRY;
@@ -6179,6 +6685,11 @@ static int lod_declare_update_plain(const struct lu_env *env,
                /* old on-disk EA is stored in info->lti_buf */
                comp_v1 = (struct lov_comp_md_v1 *)info->lti_buf.lb_buf;
                replay = true;
                /* 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);
        } else {
                /* non replay path */
                rc = lod_striping_load(env, lo);
@@ -6191,18 +6702,27 @@ static int lod_declare_update_plain(const struct lu_env *env,
        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) {
        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(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));
+               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);
        }
 
                GOTO(out, rc = -EINVAL);
        }
 
-       CDEBUG(D_LAYOUT, "%s: "DFID": instantiate components "DEXT"\n",
+       CDEBUG(D_LAYOUT, "%s: "DFID": update components "DEXT"\n",
               lod2obd(d)->obd_name, PFID(lod_object_fid(lo)),
               PEXT(&layout->li_extent));
 
               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.
        /*
         * Iterate ld->ldo_comp_entries, find the component whose extent under
         * the write range and not instantianted.
@@ -6214,7 +6734,8 @@ static int lod_declare_update_plain(const struct lu_env *env,
                        break;
 
                if (!replay) {
                        break;
 
                if (!replay) {
-                       if (lod_comp_inited(lod_comp))
+                       /* If striping is instantiated or INIT'ed DOM skip */
+                       if (!lod_is_instantiation_needed(lod_comp))
                                continue;
                } else {
                        /**
                                continue;
                } else {
                        /**
@@ -6238,17 +6759,19 @@ static int lod_declare_update_plain(const struct lu_env *env,
 
                LASSERT(info->lti_comp_idx != NULL);
                info->lti_comp_idx[info->lti_count++] = i;
 
                LASSERT(info->lti_comp_idx != NULL);
                info->lti_comp_idx[info->lti_count++] = i;
+               layout_changed = true;
        }
 
        }
 
-       if (info->lti_count == 0)
+       if (!layout_changed)
                RETURN(-EALREADY);
 
        lod_obj_inc_layout_gen(lo);
        rc = lod_declare_instantiate_components(env, lo, th);
                RETURN(-EALREADY);
 
        lod_obj_inc_layout_gen(lo);
        rc = lod_declare_instantiate_components(env, lo, th);
+       EXIT;
 out:
        if (rc)
                lod_striping_free(env, lo);
 out:
        if (rc)
                lod_striping_free(env, lo);
-       RETURN(rc);
+       return rc;
 }
 
 static inline int lod_comp_index(struct lod_object *lo,
 }
 
 static inline int lod_comp_index(struct lod_object *lo,
@@ -6573,7 +7096,7 @@ static int lod_declare_update_rdonly(const struct lu_env *env,
                                                     &lod_comp->llc_extent))
                                break;
 
                                                     &lod_comp->llc_extent))
                                break;
 
-                       if (lod_comp_inited(lod_comp))
+                       if (!lod_is_instantiation_needed(lod_comp))
                                continue;
 
                        info->lti_comp_idx[info->lti_count++] =
                                continue;
 
                        info->lti_comp_idx[info->lti_count++] =
@@ -6730,7 +7253,7 @@ static int lod_declare_update_write_pending(const struct lu_env *env,
                                                     &lod_comp->llc_extent))
                                break;
 
                                                     &lod_comp->llc_extent))
                                break;
 
-                       if (lod_comp_inited(lod_comp))
+                       if (!lod_is_instantiation_needed(lod_comp))
                                continue;
 
                        CDEBUG(D_LAYOUT, "write instantiate %d / %d\n",
                                continue;
 
                        CDEBUG(D_LAYOUT, "write instantiate %d / %d\n",
index 3b87fa9..5015310 100644 (file)
@@ -78,8 +78,9 @@
  * \retval negative    negated errno on error
 
  */
  * \retval negative    negated errno on error
 
  */
-static int lod_statfs_and_check(const struct lu_env *env, struct lod_device *d,
-                               int index, struct obd_statfs *sfs)
+int lod_statfs_and_check(const struct lu_env *env, struct lod_device *d,
+                        int index, struct obd_statfs *sfs,
+                        struct obd_statfs_info *info)
 {
        struct lod_tgt_desc *ost;
        int                  rc;
 {
        struct lod_tgt_desc *ost;
        int                  rc;
@@ -89,7 +90,7 @@ static int lod_statfs_and_check(const struct lu_env *env, struct lod_device *d,
        ost = OST_TGT(d,index);
        LASSERT(ost);
 
        ost = OST_TGT(d,index);
        LASSERT(ost);
 
-       rc = dt_statfs(env, ost->ltd_ost, sfs);
+       rc = dt_statfs(env, ost->ltd_ost, sfs, info);
 
        if (rc == 0 && ((sfs->os_state & OS_STATE_ENOSPC) ||
            (sfs->os_state & OS_STATE_ENOINO && sfs->os_fprecreated == 0)))
 
        if (rc == 0 && ((sfs->os_state & OS_STATE_ENOSPC) ||
            (sfs->os_state & OS_STATE_ENOINO && sfs->os_fprecreated == 0)))
@@ -179,7 +180,7 @@ void lod_qos_statfs_update(const struct lu_env *env, struct lod_device *lod)
                idx = osts->op_array[i];
                avail = OST_TGT(lod,idx)->ltd_statfs.os_bavail;
                if (lod_statfs_and_check(env, lod, idx,
                idx = osts->op_array[i];
                avail = OST_TGT(lod,idx)->ltd_statfs.os_bavail;
                if (lod_statfs_and_check(env, lod, idx,
-                                        &OST_TGT(lod, idx)->ltd_statfs))
+                                        &OST_TGT(lod, idx)->ltd_statfs, NULL))
                        continue;
                if (OST_TGT(lod,idx)->ltd_statfs.os_bavail != avail)
                        /* recalculate weigths */
                        continue;
                if (OST_TGT(lod,idx)->ltd_statfs.os_bavail != avail)
                        /* recalculate weigths */
@@ -837,7 +838,7 @@ static int lod_check_and_reserve_ost(const struct lu_env *env,
        int rc;
        ENTRY;
 
        int rc;
        ENTRY;
 
-       rc = lod_statfs_and_check(env, lod, ost_idx, sfs);
+       rc = lod_statfs_and_check(env, lod, ost_idx, sfs, NULL);
        if (rc)
                RETURN(rc);
 
        if (rc)
                RETURN(rc);
 
@@ -1162,7 +1163,7 @@ static int lod_alloc_ost_list(const struct lu_env *env, struct lod_object *lo,
                        break;
                }
 
                        break;
                }
 
-               rc = lod_statfs_and_check(env, m, ost_idx, sfs);
+               rc = lod_statfs_and_check(env, m, ost_idx, sfs, NULL);
                if (rc < 0) /* this OSP doesn't feel well */
                        break;
 
                if (rc < 0) /* this OSP doesn't feel well */
                        break;
 
@@ -1306,7 +1307,7 @@ repeat_find:
                 * start OST, then it can be skipped, otherwise skip it only
                 * if it is inactive/recovering/out-of-space." */
 
                 * start OST, then it can be skipped, otherwise skip it only
                 * if it is inactive/recovering/out-of-space." */
 
-               rc = lod_statfs_and_check(env, m, ost_idx, sfs);
+               rc = lod_statfs_and_check(env, m, ost_idx, sfs, NULL);
                if (rc) {
                        /* this OSP doesn't feel well */
                        continue;
                if (rc) {
                        /* this OSP doesn't feel well */
                        continue;
@@ -1507,7 +1508,8 @@ static int lod_alloc_qos(const struct lu_env *env, struct lod_object *lo,
                ost = OST_TGT(lod, osts->op_array[i]);
                ost->ltd_qos.ltq_usable = 0;
 
                ost = OST_TGT(lod, osts->op_array[i]);
                ost->ltd_qos.ltq_usable = 0;
 
-               rc = lod_statfs_and_check(env, lod, osts->op_array[i], sfs);
+               rc = lod_statfs_and_check(env, lod, osts->op_array[i],
+                                         sfs, NULL);
                if (rc) {
                        /* this OSP doesn't feel well */
                        continue;
                if (rc) {
                        /* this OSP doesn't feel well */
                        continue;
@@ -2288,6 +2290,7 @@ int lod_qos_prep_create(const struct lu_env *env, struct lod_object *lo,
        LASSERT(lo);
        LASSERT(lo->ldo_comp_cnt > comp_idx && lo->ldo_comp_entries != NULL);
        lod_comp = &lo->ldo_comp_entries[comp_idx];
        LASSERT(lo);
        LASSERT(lo->ldo_comp_cnt > comp_idx && lo->ldo_comp_entries != NULL);
        lod_comp = &lo->ldo_comp_entries[comp_idx];
+       LASSERT(!(lod_comp->llc_flags & LCME_FL_EXTENSION));
 
        /* A released component is being created */
        if (lod_comp->llc_pattern & LOV_PATTERN_F_RELEASED)
 
        /* A released component is being created */
        if (lod_comp->llc_pattern & LOV_PATTERN_F_RELEASED)
index cb2c780..680ce92 100644 (file)
@@ -680,7 +680,7 @@ static int lod_osts_seq_show(struct seq_file *p, void *v)
 
        /* XXX: should be non-NULL env, but it's very expensive */
        active = 1;
 
        /* XXX: should be non-NULL env, but it's very expensive */
        active = 1;
-       rc = dt_statfs(NULL, next, &sfs);
+       rc = dt_statfs(NULL, next, &sfs, NULL);
        if (rc == -ENOTCONN) {
                active = 0;
                rc = 0;
        if (rc == -ENOTCONN) {
                active = 0;
                rc = 0;
index c6caae2..7c88545 100644 (file)
@@ -1331,7 +1331,7 @@ static int mdd_statfs(const struct lu_env *env, struct md_device *m,
 
        ENTRY;
 
 
        ENTRY;
 
-       rc = mdd_child_ops(mdd)->dt_statfs(env, mdd->mdd_child, sfs);
+       rc = mdd_child_ops(mdd)->dt_statfs(env, mdd->mdd_child, sfs, NULL);
 
        sfs->os_namelen = min_t(__u32, sfs->os_namelen, NAME_MAX);
 
 
        sfs->os_namelen = min_t(__u32, sfs->os_namelen, NAME_MAX);
 
index 3717336..fdc360e 100644 (file)
@@ -456,7 +456,7 @@ static int mdt_statfs(struct tgt_session_info *tsi)
                                                              next, osfs);
                        else
                                rc = dt_statfs(info->mti_env, mdt->mdt_bottom,
                                                              next, osfs);
                        else
                                rc = dt_statfs(info->mti_env, mdt->mdt_bottom,
-                                              osfs);
+                                              osfs, NULL);
                        if (rc)
                                GOTO(out, rc);
                        spin_lock(&mdt->mdt_lock);
                        if (rc)
                                GOTO(out, rc);
                        spin_lock(&mdt->mdt_lock);
index 3bec5f7..49cb28b 100644 (file)
@@ -995,7 +995,7 @@ int lprocfs_dt_blksize_seq_show(struct seq_file *m, void *v)
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
-       int rc = dt_statfs(NULL, dt, &osfs);
+       int rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc == 0)
                seq_printf(m, "%u\n", (unsigned) osfs.os_bsize);
        return rc;
        if (rc == 0)
                seq_printf(m, "%u\n", (unsigned) osfs.os_bsize);
        return rc;
@@ -1007,7 +1007,7 @@ int lprocfs_dt_kbytestotal_seq_show(struct seq_file *m, void *v)
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
-       int rc = dt_statfs(NULL, dt, &osfs);
+       int rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc == 0) {
                __u32 blk_size = osfs.os_bsize >> 10;
                __u64 result = osfs.os_blocks;
        if (rc == 0) {
                __u32 blk_size = osfs.os_bsize >> 10;
                __u64 result = osfs.os_blocks;
@@ -1026,7 +1026,7 @@ int lprocfs_dt_kbytesfree_seq_show(struct seq_file *m, void *v)
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
-       int rc = dt_statfs(NULL, dt, &osfs);
+       int rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc == 0) {
                __u32 blk_size = osfs.os_bsize >> 10;
                __u64 result = osfs.os_bfree;
        if (rc == 0) {
                __u32 blk_size = osfs.os_bsize >> 10;
                __u64 result = osfs.os_bfree;
@@ -1045,7 +1045,7 @@ int lprocfs_dt_kbytesavail_seq_show(struct seq_file *m, void *v)
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
-       int rc = dt_statfs(NULL, dt, &osfs);
+       int rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc == 0) {
                __u32 blk_size = osfs.os_bsize >> 10;
                __u64 result = osfs.os_bavail;
        if (rc == 0) {
                __u32 blk_size = osfs.os_bsize >> 10;
                __u64 result = osfs.os_bavail;
@@ -1064,7 +1064,7 @@ int lprocfs_dt_filestotal_seq_show(struct seq_file *m, void *v)
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
-       int rc = dt_statfs(NULL, dt, &osfs);
+       int rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc == 0)
                seq_printf(m, "%llu\n", osfs.os_files);
        return rc;
        if (rc == 0)
                seq_printf(m, "%llu\n", osfs.os_files);
        return rc;
@@ -1076,7 +1076,7 @@ int lprocfs_dt_filesfree_seq_show(struct seq_file *m, void *v)
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
        struct dt_device *dt = m->private;
        struct obd_statfs osfs;
 
-       int rc = dt_statfs(NULL, dt, &osfs);
+       int rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc == 0)
                seq_printf(m, "%llu\n", osfs.os_ffree);
        return rc;
        if (rc == 0)
                seq_printf(m, "%llu\n", osfs.os_ffree);
        return rc;
@@ -1107,7 +1107,7 @@ static ssize_t blocksize_show(struct kobject *kobj, struct attribute *attr,
        struct obd_statfs osfs;
        int rc;
 
        struct obd_statfs osfs;
        int rc;
 
-       rc = dt_statfs(NULL, dt, &osfs);
+       rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc)
                return rc;
 
        if (rc)
                return rc;
 
@@ -1125,7 +1125,7 @@ static ssize_t kbytestotal_show(struct kobject *kobj, struct attribute *attr,
        u64 result;
        int rc;
 
        u64 result;
        int rc;
 
-       rc = dt_statfs(NULL, dt, &osfs);
+       rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc)
                return rc;
 
        if (rc)
                return rc;
 
@@ -1149,7 +1149,7 @@ static ssize_t kbytesfree_show(struct kobject *kobj, struct attribute *attr,
        u64 result;
        int rc;
 
        u64 result;
        int rc;
 
-       rc = dt_statfs(NULL, dt, &osfs);
+       rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc)
                return rc;
 
        if (rc)
                return rc;
 
@@ -1173,7 +1173,7 @@ static ssize_t kbytesavail_show(struct kobject *kobj, struct attribute *attr,
        u64 result;
        int rc;
 
        u64 result;
        int rc;
 
-       rc = dt_statfs(NULL, dt, &osfs);
+       rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc)
                return rc;
 
        if (rc)
                return rc;
 
@@ -1195,7 +1195,7 @@ static ssize_t filestotal_show(struct kobject *kobj, struct attribute *attr,
        struct obd_statfs osfs;
        int rc;
 
        struct obd_statfs osfs;
        int rc;
 
-       rc = dt_statfs(NULL, dt, &osfs);
+       rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc)
                return rc;
 
        if (rc)
                return rc;
 
@@ -1211,7 +1211,7 @@ static ssize_t filesfree_show(struct kobject *kobj, struct attribute *attr,
        struct obd_statfs osfs;
        int rc;
 
        struct obd_statfs osfs;
        int rc;
 
-       rc = dt_statfs(NULL, dt, &osfs);
+       rc = dt_statfs(NULL, dt, &osfs, NULL);
        if (rc)
                return rc;
 
        if (rc)
                return rc;
 
index c5b15f1..a56947a 100644 (file)
@@ -195,7 +195,7 @@ static int llog_cat_new_log(const struct lu_env *env,
        /* 2MB for the cases when free space hasn't been learned yet */
        loghandle->lgh_max_size = 2 << 20;
        dt = lu2dt_dev(cathandle->lgh_obj->do_lu.lo_dev);
        /* 2MB for the cases when free space hasn't been learned yet */
        loghandle->lgh_max_size = 2 << 20;
        dt = lu2dt_dev(cathandle->lgh_obj->do_lu.lo_dev);
-       rc = dt_statfs(env, dt, &lgi->lgi_statfs);
+       rc = dt_statfs(env, dt, &lgi->lgi_statfs, NULL);
        if (rc == 0 && lgi->lgi_statfs.os_bfree > 0) {
                __u64 freespace = (lgi->lgi_statfs.os_bfree *
                                  lgi->lgi_statfs.os_bsize) >> 6;
        if (rc == 0 && lgi->lgi_statfs.os_bfree > 0) {
                __u64 freespace = (lgi->lgi_statfs.os_bfree *
                                  lgi->lgi_statfs.os_bsize) >> 6;
index 42af490..6d62e82 100644 (file)
@@ -1657,7 +1657,7 @@ static int server_statfs(struct dentry *dentry, struct kstatfs *buf)
        ENTRY;
 
        if (lsi->lsi_dt_dev) {
        ENTRY;
 
        if (lsi->lsi_dt_dev) {
-               rc = dt_statfs(NULL, lsi->lsi_dt_dev, &statfs);
+               rc = dt_statfs(NULL, lsi->lsi_dt_dev, &statfs, NULL);
                if (rc == 0) {
                        statfs_unpack(buf, &statfs);
                        buf->f_type = sb->s_magic;
                if (rc == 0) {
                        statfs_unpack(buf, &statfs);
                        buf->f_type = sb->s_magic;
index 478854c..c5d9f2e 100644 (file)
@@ -1434,7 +1434,7 @@ static int ofd_health_check(const struct lu_env *nul, struct obd_device *obd)
                RETURN(rc);
 
        info = ofd_info_init(&env, NULL);
                RETURN(rc);
 
        info = ofd_info_init(&env, NULL);
-       rc = dt_statfs(&env, ofd->ofd_osd, &info->fti_u.osfs);
+       rc = dt_statfs(&env, ofd->ofd_osd, &info->fti_u.osfs, NULL);
        if (unlikely(rc))
                GOTO(out, rc);
 
        if (unlikely(rc))
                GOTO(out, rc);
 
index 5a87b26..0b6a85c 100644 (file)
@@ -2190,7 +2190,7 @@ static int osd_object_print(const struct lu_env *env, void *cookie,
  * Concurrency: shouldn't matter.
  */
 int osd_statfs(const struct lu_env *env, struct dt_device *d,
  * Concurrency: shouldn't matter.
  */
 int osd_statfs(const struct lu_env *env, struct dt_device *d,
-               struct obd_statfs *sfs)
+               struct obd_statfs *sfs, struct obd_statfs_info *info)
 {
        struct osd_device *osd = osd_dt_dev(d);
        struct super_block *sb = osd_sb(osd);
 {
        struct osd_device *osd = osd_dt_dev(d);
        struct super_block *sb = osd_sb(osd);
index db2c3c7..a28ba4c 100644 (file)
@@ -742,7 +742,7 @@ int osd_register_proc_index_in_idif(struct osd_device *osd);
 
 #endif
 int osd_statfs(const struct lu_env *env, struct dt_device *dev,
 
 #endif
 int osd_statfs(const struct lu_env *env, struct dt_device *dev,
-               struct obd_statfs *sfs);
+              struct obd_statfs *sfs, struct obd_statfs_info *info);
 struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
                       struct osd_inode_id *id);
 struct inode *
 struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
                       struct osd_inode_id *id);
 struct inode *
index edf0a16..078eb34 100644 (file)
@@ -552,7 +552,7 @@ static int osd_objset_statfs(struct osd_device *osd, struct obd_statfs *osfs)
  * Concurrency: shouldn't matter.
  */
 int osd_statfs(const struct lu_env *env, struct dt_device *d,
  * Concurrency: shouldn't matter.
  */
 int osd_statfs(const struct lu_env *env, struct dt_device *d,
-              struct obd_statfs *osfs)
+              struct obd_statfs *osfs, struct obd_statfs_info *info)
 {
        struct osd_device *osd = osd_dt_dev(d);
        int               rc;
 {
        struct osd_device *osd = osd_dt_dev(d);
        int               rc;
index d88ef63..ef80fa1 100644 (file)
@@ -465,7 +465,8 @@ struct osd_object {
        struct lu_object_header *oo_header;
 };
 
        struct lu_object_header *oo_header;
 };
 
-int osd_statfs(const struct lu_env *, struct dt_device *, struct obd_statfs *);
+int osd_statfs(const struct lu_env *, struct dt_device *, struct obd_statfs *,
+              struct obd_statfs_info *);
 extern const struct dt_index_operations osd_acct_index_ops;
 extern struct lu_device_operations  osd_lu_ops;
 extern struct dt_index_operations osd_dir_ops;
 extern const struct dt_index_operations osd_acct_index_ops;
 extern struct lu_device_operations  osd_lu_ops;
 extern struct dt_index_operations osd_dir_ops;
index 1625c83..f45cd74 100644 (file)
@@ -730,7 +730,7 @@ const struct lu_device_operations osp_lu_ops = {
  * \retval negative    negative errno if get statfs failed.
  */
 static int osp_statfs(const struct lu_env *env, struct dt_device *dev,
  * \retval negative    negative errno if get statfs failed.
  */
 static int osp_statfs(const struct lu_env *env, struct dt_device *dev,
-                     struct obd_statfs *sfs)
+                     struct obd_statfs *sfs, struct obd_statfs_info *info)
 {
        struct osp_device *d = dt2osp_dev(dev);
        struct obd_import *imp = d->opd_obd->u.cli.cl_import;
 {
        struct osp_device *d = dt2osp_dev(dev);
        struct obd_import *imp = d->opd_obd->u.cli.cl_import;
@@ -745,10 +745,25 @@ static int osp_statfs(const struct lu_env *env, struct dt_device *dev,
 
        /* return recently updated data */
        *sfs = d->opd_statfs;
 
        /* return recently updated data */
        *sfs = d->opd_statfs;
+       if (info) {
+               info->os_reserved_mb_low = d->opd_reserved_mb_low;
+               info->os_reserved_mb_high = d->opd_reserved_mb_high;
+       }
 
        if (d->opd_pre == NULL)
                RETURN(0);
 
 
        if (d->opd_pre == NULL)
                RETURN(0);
 
+       CDEBUG(D_OTHER, "%s: %llu blocks, %llu free, %llu avail, "
+              "%u reserved mb low, %u reserved mb high,"
+              "%llu files, %llu free files\n", d->opd_obd->obd_name,
+              sfs->os_blocks, sfs->os_bfree, sfs->os_bavail,
+              d->opd_reserved_mb_low, d->opd_reserved_mb_high,
+              sfs->os_files, sfs->os_ffree);
+
+
+       if (info && !info->os_enable_pre)
+               RETURN(0);
+
        /*
         * layer above osp (usually lod) can use ffree to estimate
         * how many objects are available for immediate creation
        /*
         * layer above osp (usually lod) can use ffree to estimate
         * how many objects are available for immediate creation
@@ -762,11 +777,6 @@ static int osp_statfs(const struct lu_env *env, struct dt_device *dev,
                 PFID(&d->opd_pre_last_created_fid), PFID(&d->opd_pre_used_fid),
                 d->opd_pre_reserved);
        spin_unlock(&d->opd_pre_lock);
                 PFID(&d->opd_pre_last_created_fid), PFID(&d->opd_pre_used_fid),
                 d->opd_pre_reserved);
        spin_unlock(&d->opd_pre_lock);
-
-       CDEBUG(D_OTHER, "%s: %llu blocks, %llu free, %llu avail, "
-              "%llu files, %llu free files\n", d->opd_obd->obd_name,
-              sfs->os_blocks, sfs->os_bfree, sfs->os_bavail,
-              sfs->os_files, sfs->os_ffree);
        RETURN(0);
 }
 
        RETURN(0);
 }
 
index 9030aa8..66ae03b 100644 (file)
@@ -1008,6 +1008,13 @@ void osp_pre_update_status(struct osp_device *d, int rc)
                else if (msfs->os_ffree > 64)
                        msfs->os_state &= ~OS_STATE_ENOINO;
 
                else if (msfs->os_ffree > 64)
                        msfs->os_state &= ~OS_STATE_ENOINO;
 
+               CDEBUG(D_INFO, "%s: status: %llu blocks, %llu "
+                      "free, %llu avail, %llu MB avail, %u "
+                      "hwm -> %d: rc = %d\n",
+                      d->opd_obd->obd_name, msfs->os_blocks,
+                      msfs->os_bfree, msfs->os_bavail,
+                      available, d->opd_reserved_mb_high,
+                      d->opd_pre_status, rc);
                if (available < d->opd_reserved_mb_low)
                        msfs->os_state |= OS_STATE_ENOSPC;
                else if (available > d->opd_reserved_mb_high)
                if (available < d->opd_reserved_mb_low)
                        msfs->os_state |= OS_STATE_ENOSPC;
                else if (available > d->opd_reserved_mb_high)
index e832bc9..34f1760 100644 (file)
@@ -309,7 +309,7 @@ int tgt_statfs_internal(const struct lu_env *env, struct lu_target *lut,
 
                /* statfs can sleep ... hopefully not for too long since we can
                 * call it fairly often as space fills up */
 
                /* statfs can sleep ... hopefully not for too long since we can
                 * call it fairly often as space fills up */
-               rc = dt_statfs(env, lut->lut_bottom, osfs);
+               rc = dt_statfs(env, lut->lut_bottom, osfs, NULL);
                if (unlikely(rc))
                        GOTO(out, rc);
 
                if (unlikely(rc))
                        GOTO(out, rc);
 
index b21434c..7da57de 100644 (file)
@@ -174,11 +174,6 @@ test_1c() {
 }
 run_test 1c "Test overstriping w/max stripe count"
 
 }
 run_test 1c "Test overstriping w/max stripe count"
 
-check_component_count() {
-       local comp_cnt=$($LFS getstripe --component-count $1)
-       [ $comp_cnt -ne $2 ] && error "$1, component count $comp_cnt != $2"
-}
-
 test_2() {
        local comp_file=$DIR/$tdir/$tfile
        local rw_len=$((5 * 1024 * 1024))       # 5M
 test_2() {
        local comp_file=$DIR/$tdir/$tfile
        local rw_len=$((5 * 1024 * 1024))       # 5M
@@ -950,6 +945,734 @@ test_18() {
 }
 run_test 18 "check component distribution"
 
 }
 run_test 18 "check component distribution"
 
+test19_io_base() {
+       local comp_file=$1
+       local already_created=${2:-0}
+       local rw_len=$((3 * 1024 * 1024))       # 3M
+       local flg_opts=""
+       local found=""
+
+       if [ $already_created != 1 ]; then
+               test_mkdir -p $DIR/$tdir
+               $LFS setstripe --extension-size 64M -c 1 -E -1 $comp_file ||
+                       error "Create $comp_file failed"
+       fi
+
+       # write past end of first component, so it is extended
+       dd if=/dev/zero of=$comp_file bs=1M count=1 seek=127 conv=notrunc ||
+               error "dd to extend failed"
+
+       local ost_idx1=$($LFS getstripe -I1 -i $comp_file)
+       local ost_idx2=$($LFS getstripe -I2 -i $comp_file)
+
+       [ $ost_idx1 -eq $ost_idx2 ] && error "$ost_idx1 == $ost_idx2"
+       [ $ost_idx2 -ne "-1" ] && error "second component init $ost_idx2"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 0 -E 128M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: Extended first 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 "Write: Second component not found"
+
+       small_write $comp_file $rw_len || error "Verify RW failed"
+
+       sel_layout_sanity $comp_file 2
+}
+
+# Self-extending PFL tests
+test_19a() {
+       [ $OSTCOUNT -lt 2 ] && skip "needs >= 2 OSTs" && return
+       [ $(lustre_version_code $SINGLEMDS) -lt $(version_code $SEL_VER) ] &&
+               skip "skipped for lustre < $SEL_VER"
+
+       test19_io_base $DIR/$tdir/$tfile
+}
+run_test 19a "Simple test of extension behavior"
+
+# Same as 19a, but with default layout set on directory rather than on file
+test_19b() {
+       [ $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 --ext-size 64M -c 1 -E -1 $DIR/$tdir ||
+               error "Setstripe on $DIR/$tdir failed"
+
+       touch $comp_file
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 0 -E 64M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Inheritance: wrong first component size"
+
+       flg_opts="--comp-flags extension"
+       found=$($LFS find --comp-start 64M -E EOF $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Inheritance: Second component not found"
+
+       test19_io_base $comp_file 1
+}
+run_test 19b "Simple test of SEL as default layout"
+
+# Test behavior when seeking deep in a file
+test_19c() {
+       [ $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 -z 128M -E 1G -E -1 $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 conv=notrunc ||
+               error "dd to extend failed"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 0M -E 256M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: first extension component not found"
+
+       flg_opts="--comp-flags extension,^init"
+       found=$($LFS find --comp-start 256M -E 1024M $flg_opts $comp_file |\
+               wc -l)
+       [ $found -eq 1 ] || error "Write: second extension component not found"
+
+       local end_1=$($LFS getstripe -I1 -E $comp_file)
+
+       # 256 MiB
+       [ $end_1 -eq 268435456 ] ||
+               error "end of first component $end_1 != 268435456"
+
+       # Write past end of extension space component, in to normal component
+       # should exhaust & remove extension component
+       dd if=/dev/zero bs=1M count=1 seek=1100 of=$comp_file conv=notrunc ||
+               error "dd distant seek failed"
+
+       local ost_idx1=$($LFS getstripe -I1 -i $comp_file)
+       # the last component index is 3
+       local ost_idx2=$($LFS getstripe -I3 -i $comp_file)
+
+       [ $ost_idx1 -eq $ost_idx2 ] && error "$ost_idx1 == $ost_idx2"
+
+       local start1=$($LFS getstripe -I1 --comp-start $comp_file)
+       local end1=$($LFS getstripe -I1 -E $comp_file)
+       local start2=$($LFS getstripe -I3 --comp-start $comp_file)
+       local end2=$($LFS getstripe -I3 -E $comp_file)
+
+       [ $start1 -eq 0 ] || error "start of first component incorrect"
+       [ $end1 -eq 1073741824 ] || error "end of first component incorrect"
+       [ $start2 -eq 1073741824  ] ||
+               error "start of second component incorrect"
+       [ "$end2" = "EOF" ] || error "end of second component incorrect"
+
+       flg_opts="--comp-flags extension"
+       found=$($LFS find $flg_opts $comp_file | wc -l)
+       [ $found -eq 0 ] || error "Seek Write: extension component exists"
+
+       sel_layout_sanity $comp_file 2
+}
+run_test 19c "Test self-extending layout seeking behavior"
+
+test_19d() {
+       [ $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 128M -c 1 -z 64M -E -1 $comp_file ||
+               error "Create $comp_file failed"
+
+       # This will cause component 1 to be extended to 128M, then the
+       # extension space component will be removed
+       dd if=/dev/zero of=$comp_file bs=130M count=1 ||
+               error "dd to extend failed"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 0M -E 128M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: first component not found"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 128M -E EOF $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: second component not found"
+
+       sel_layout_sanity $comp_file 2
+
+       # always remove large files in case of DO_CLEANUP=false
+       rm -f $comp_file || error "Delete $comp_file failed"
+}
+run_test 19d "Test write which completely spans extension space component"
+
+test_19e_check() {
+       comp_file=$1
+
+       local comp2_flags=$($LFS getstripe -I2 --comp-flags $comp_file)
+       local comp3_flags=$($LFS getstripe -I3 --comp-flags $comp_file)
+
+       [ "$comp2_flags" != "init" ] && error "$comp2_flags != init"
+       [ "$comp3_flags" != "extension" ] && error "$comp3_flags != extension"
+
+       local flg_opts=" --comp-start 2M -E 66M --comp-flags init"
+       local found=$($LFS find $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: extended second component not found"
+
+       flg_opts="--comp-start 66M -E EOF --comp-flags extension"
+       found=$($LFS find $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: third component not found"
+
+       sel_layout_sanity $comp_file 3
+}
+
+test_19e() {
+       [ $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 rw_len=$((3 * 1024 * 1024))       # 3M
+       local flg_opts=""
+       local found=""
+
+       test_mkdir -p $DIR/$tdir
+
+       $LFS setstripe -E 2m -E -1 -z 64M $comp_file ||
+               error "Create $comp_file failed"
+
+       replay_barrier $SINGLEMDS
+
+       #instantiate & extend second component
+       dd if=/dev/zero of=$comp_file bs=4M count=1 ||
+               error "dd to extend failed"
+
+       local ost_idx2=$($LFS getstripe -I2 -i $comp_file)
+       local ost_idx3=$($LFS getstripe -I3 -i $comp_file)
+
+       [ $ost_idx2 -eq $ost_idx3 ] && error "$ost_idx2 == $ost_idx3"
+       [ $ost_idx3 -ne "-1" ] && error "third component init $ost_idx3"
+
+       test_19e_check $comp_file
+
+       local f1=$($LFS getstripe -I2 $comp_file | awk '/l_fid:/ {print $7}')
+       echo "before MDS recovery, the ost fid of 2nd component is $f1"
+
+       fail $SINGLEMDS
+
+       local f2=$($LFS getstripe -I2 $comp_file | awk '/l_fid:/ {print $7}')
+       echo "after MDS recovery, the ost fid of 2nd component is $f2"
+       [ "x$f1" == "x$f2" ] || error "$f1 != $f2"
+
+       # simply repeat all previous checks, but also verify components are on
+       # the same OST as before
+
+       local ost_idx2_2=$($LFS getstripe -I2 -i $comp_file)
+       local ost_idx3_2=$($LFS getstripe -I3 -i $comp_file)
+
+       [ $ost_idx2_2 -eq $ost_idx3_2 ] && error "$ost_idx2_2 == $ost_idx3_2"
+       [ $ost_idx3_2 -ne "-1" ] && error "second component init $ost_idx3_2"
+
+       # verify OST id is the same after failover
+       [ $ost_idx2 -ne $ost_idx2_2 ] &&
+               error "$ost_idx2 != $ost_idx2_2, changed after failover"
+
+       test_19e_check $comp_file
+}
+run_test 19e "Replay of layout instantiation & extension"
+
+# Test out of space behavior
+test_20a() {
+       [ $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
+
+       # First component is on OST0
+       $LFS setstripe -E 256M -i 0 -z 64M -E -1 -z 1G $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=66 ||
+               error "dd to extend failed"
+
+       flg_opts="--comp-flags extension"
+       found=$($LFS find --comp-start 128M -E 256M $flg_opts $comp_file |wc -l)
+       [ $found -eq 1 ] || error "Write: Second component not found"
+
+       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
+
+       flg_opts="--comp-flags extension"
+       # Write past current init comp, but we won't extend (because no space)
+       dd if=/dev/zero of=$comp_file bs=1M count=10 seek=200 ||
+               error "dd write past current comp failed"
+
+       $LFS getstripe $comp_file
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 128M -E 1152M $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 1152M -E EOF $flg_opts $comp_file |wc -l)
+       [ $found -eq 1 ] || error "Write: fourth extension component not found"
+
+       sel_layout_sanity $comp_file 3
+}
+run_test 20a "Test out of space, spillover to defined component"
+
+test_20b() {
+       [ $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 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"
+
+       # normal component to 10M, extendable component to 1G
+       # further extendable to EOF
+       $LFS setstripe -E 10M -E 1G -p $TESTNAME -z 64M -E -1 -p "" -z 512M \
+               $comp_file || error "Create $comp_file failed"
+
+       replay_barrier $SINGLEMDS
+
+       found=$($LFS find --comp-start 10M -E 10M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Zero length component not found"
+
+       local ost_idx1=0
+       local wms=$(ost_watermarks_set_enospc $tfile $ost_idx1 |
+                   grep "watermarks")
+       stack_trap "ost_watermarks_clear_enospc $tfile $ost_idx1 $wms" EXIT
+
+       # write past end of first component
+       # This should remove the next component, since OST0 is out of space
+       # and it is striped there (pool contains only OST0)
+       dd if=/dev/zero of=$comp_file bs=1M count=1 seek=14 ||
+               error "dd to extend/remove failed"
+
+       $LFS getstripe $comp_file
+
+       found=$($LFS find --comp-start 10M -E 10M $flg_opts $comp_file | wc -l)
+       [ $found -eq 0 ] || error "Write: zero length component still present"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 10M -E 522M $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 522M -E EOF $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: third component not found"
+
+       fail $SINGLEMDS
+
+       found=$($LFS find --comp-start 10M -E 10M $flg_opts $comp_file | wc -l)
+       [ $found -eq 0 ] || error "Failover: 0-length component still present"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 10M -E 522M $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 522M -E EOF $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Failover: third component not found"
+
+       sel_layout_sanity $comp_file 3
+}
+run_test 20b "Remove component without instantiation when there is no space"
+
+test_20c() {
+       [ $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 100M -E -1 -p $TESTNAME -z 64M $comp_file ||
+               error "Create $comp_file failed"
+
+       local ost_idx1=0
+       local ost_idx2=1
+       local wms=$(ost_watermarks_set_enospc $tfile $ost_idx1 |
+                   grep "watermarks")
+       local wms2=$(ost_watermarks_set_enospc $tfile $ost_idx2 |
+                    grep "watermarks")
+       stack_trap "ost_watermarks_clear_enospc $tfile $ost_idx1 $wms" EXIT
+       stack_trap "ost_watermarks_clear_enospc $tfile $ost_idx2 $wms2" EXIT
+
+       dd if=/dev/zero of=$comp_file bs=1M count=1 seek=120 &&
+               error "dd should fail with ENOSPC"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 0M -E 100M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: First component not found"
+
+       flg_opts="--comp-flags ^init"
+       found=$($LFS find --comp-start 100M -E 100M $flg_opts $comp_file |wc -l)
+       [ $found -eq 1 ] || error "Write: 0-length component not found"
+
+       flg_opts="--comp-flags extension"
+       found=$($LFS find --comp-start 100M -E EOF $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: third extension component not found"
+
+       sel_layout_sanity $comp_file 3
+}
+run_test 20c "Test inability to stripe new extension component"
+
+test_20d() {
+       [ $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
+
+       wait_delete_completed
+       wait_mds_ost_sync
+
+       pool_add $TESTNAME || error "Pool creation failed"
+       pool_add_targets $TESTNAME 0 || error "Pool add targets failed"
+       $LFS setstripe -E 64m -E -1 -p $TESTNAME -z 64M $comp_file ||
+               error "Create $comp_file failed"
+
+       replay_barrier $SINGLEMDS
+
+       local wms=$(ost_watermarks_set_low_space 0 | grep "watermarks")
+       dd if=/dev/zero bs=1M count=1 seek=100 of=$comp_file
+       RC=$?
+
+       ost_watermarks_clear_enospc $tfile 0 $wms
+       [ $RC -eq 0 ] || error "dd failed: $RC"
+
+       $LFS getstripe $comp_file
+       local flg_opts="--comp-start 64M -E 128M --comp-flags init"
+       local found=$($LFS find $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: component (64M-128M) not found"
+
+       local ost_idx=$($LFS getstripe -I3 -i $comp_file)
+       [ "$ost_idx" != "-1" ] && error "Write: EXT component disappeared"
+
+       fail $SINGLEMDS
+
+       found=$($LFS find $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Failover: component (64M-128M) not found"
+
+       ost_idx=$($LFS getstripe -I3 -i $comp_file)
+       [ "$ost_idx" != "-1" ] && error "Failover: EXT component disappeared"
+
+       sel_layout_sanity $comp_file 3
+}
+run_test 20d "Low on space + 0-length comp: force extension"
+
+test_20e() {
+       [ $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
+
+       wait_delete_completed
+       wait_mds_ost_sync
+
+       pool_add $TESTNAME || error "Pool creation failed"
+       pool_add_targets $TESTNAME 0 || error "Pool add targets failed"
+
+       $LFS setstripe -E 64m -E 640M -z 64M -p $TESTNAME -E -1 $comp_file ||
+               error "Create $comp_file failed"
+
+       local wms=$(ost_watermarks_set_low_space 0 | grep "watermarks")
+
+       dd if=/dev/zero bs=1M count=1 seek=100 of=$comp_file
+       RC=$?
+
+       ost_watermarks_clear_enospc $tfile 0 $wms
+       [ $RC -eq 0 ] || error "dd failed $RC"
+
+       $LFS getstripe $comp_file
+       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 "Write: component (64M-EOF) not found"
+
+       local ost_idx=$($LFS getstripe -I2 -i $comp_file)
+       [ "$ost_idx" != "" ] && error "Write: 0-length component still exists"
+       ost_idx=$($LFS getstripe -I3 -i $comp_file)
+       [ "$ost_idx" != "" ] && error "Write: extension component still exists"
+
+       sel_layout_sanity $comp_file 2
+}
+run_test 20e "ENOSPC with next real comp: spillover and backward extension"
+
+# Simple DoM interaction test
+test_21a() {
+       [ $(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
+
+       # simple, correct self-extending layout after DoM component
+       $LFS setstripe -E 1M -L mdt -E -1 -z 64m $comp_file || \
+               error "Create $comp_file failed"
+
+       # Write to DoM component & to self-extending comp after it
+       dd if=/dev/zero bs=1M count=12 of=$comp_file ||
+               error "dd to extend failed"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 1M -E 65M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: extended component not found"
+
+       flg_opts="--comp-flags extension"
+       found=$($LFS find --comp-start 65M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: extension component not found"
+
+       sel_layout_sanity $comp_file 3
+}
+run_test 21a "Simple DoM interaction tests"
+
+# DoM + extension + removal
+test_21b() {
+       [ $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 ost_name=$(ostname_from_index 0)
+       local flg_opts=""
+       local found=""
+
+       test_mkdir -p $DIR/$tdir
+
+       # DoM, extendable component, further extendable component
+       $LFS setstripe -E 1M -L mdt -E 256M -i 0 -z 64M -E -1 -z 1G \
+               $comp_file || error "Create $comp_file failed"
+
+       found=$($LFS find --comp-start 1M -E 1M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: Zero length component not found"
+
+       # This also demonstrates that we will avoid degraded OSTs
+       do_facet ost1 $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 ost1 $LCTL set_param -n \
+               obdfilter.$ost_name.degraded=0; sleep_maxage" EXIT
+
+       # This should remove the first component after DoM and spill over to
+       # the next one
+       dd if=/dev/zero bs=1M count=2 of=$comp_file ||
+               error "dd to remove+spill over failed"
+
+       found=$($LFS find --comp-start 1M -E 1M $flg_opts $comp_file | wc -l)
+       [ $found -eq 0 ] || error "Write: Zero length component still present"
+
+       flg_opts="--comp-flags init"
+       found=$($LFS find --comp-start 1M -E 1025M $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Write: extended component not found"
+
+       flg_opts="--comp-flags extension"
+       found=$($LFS find --comp-start 1025M -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 21b "DoM followed by extendable component with removal"
+
+test_23a() {
+       [ $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"
+
+       dd if=/dev/zero bs=1M oflag=append count=1 of=$comp_file ||
+               error "dd append failed"
+
+       local flg_opts="--comp-start 0 -E EOF --comp-flags init"
+       local found=$($LFS find $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Append: first component (0-EOF) not found"
+
+       local ost_idx=$($LFS getstripe -I2 -i $comp_file)
+       [ "$ost_idx" != "" ] && error "Append: second component still exists"
+
+       sel_layout_sanity $comp_file 1
+}
+run_test 23a "Append: remove EXT comp"
+
+test_23b() {
+       [ $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 -E 64m -E -1 -z 64M $comp_file ||
+               error "Create $comp_file failed"
+
+       dd if=/dev/zero bs=1M oflag=append count=1 of=$comp_file ||
+               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"
+
+       local ost_idx=$($LFS getstripe -I3 -i $comp_file)
+       [ "$ost_idx" != "" ] && error "Append: third component still exists"
+
+       sel_layout_sanity $comp_file 2
+}
+run_test 23b "Append with 0-length comp: remove EXT comp"
+
+test_23c() {
+       [ $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
+
+       wait_delete_completed
+       wait_mds_ost_sync
+
+       pool_add $TESTNAME || error "Pool creation failed"
+       pool_add_targets $TESTNAME 0 || error "Pool add targets failed"
+       $LFS setstripe -E 64m -E -1 -p $TESTNAME -z 64M $comp_file ||
+               error "Create $comp_file failed"
+
+       local wms=$(ost_watermarks_set_low_space 0 | grep "watermarks")
+       dd if=/dev/zero bs=1M oflag=append count=1 of=$comp_file
+       RC=$?
+
+       ost_watermarks_clear_enospc $tfile 0 $wms
+       [ $RC -eq 0 ] || error "dd append failed: $RC"
+
+       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"
+
+       local ost_idx=$($LFS getstripe -I3 -i $comp_file)
+       [ "$ost_idx" != "" ] && error "Append: EXT component still exists"
+
+       sel_layout_sanity $comp_file 2
+}
+run_test 23c "Append with low on space + 0-length comp: force extension"
+
+test_23d() {
+       [ $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 -E 64m -E 640M -z 64M -E -1 $comp_file ||
+               error "Create $comp_file failed"
+
+       dd if=/dev/zero bs=1M oflag=append count=1 of=$comp_file ||
+               error "dd append failed"
+
+       flg_opts="--comp-start 64M -E 640M --comp-flags init"
+       found=$($LFS find $flg_opts $comp_file | wc -l)
+       [ $found -eq 1 ] || error "Append: component (64M-640M) not found"
+
+       ost_idx=$($LFS getstripe -I3 -i $comp_file)
+       [ "$ost_idx" != "" ] && error "Append: third component still exists"
+
+       sel_layout_sanity $comp_file 3
+}
+run_test 23d "Append with 0-length comp + next real comp: remove EXT comp"
+
+test_23e() {
+       [ $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
+
+       wait_delete_completed
+       wait_mds_ost_sync
+
+       pool_add $TESTNAME || error "Pool creation failed"
+       pool_add_targets $TESTNAME 0 || error "Pool add targets failed"
+
+       $LFS setstripe -E 64m -E 640M -z 64M -p $TESTNAME -E -1 $comp_file ||
+               error "Create $comp_file failed"
+
+       local wms=$(ost_watermarks_set_low_space 0 | grep "watermarks")
+
+       dd if=/dev/zero bs=1M oflag=append count=1 of=$comp_file
+       RC=$?
+
+       ost_watermarks_clear_enospc $tfile 0 $wms
+       [ $RC -eq 0 ] || error "dd append failed $RC"
+
+       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"
+
+       local ost_idx=$($LFS getstripe -I2 -i $comp_file)
+       [ "$ost_idx" != "" ] && error "Append: 0-length component still exists"
+       ost_idx=$($LFS getstripe -I3 -i $comp_file)
+       [ "$ost_idx" != "" ] && error "Append: extension component still exists"
+
+       sel_layout_sanity $comp_file 2
+}
+run_test 23e "Append with next real comp: spillover and backward extension"
+
 complete $SECONDS
 check_and_cleanup_lustre
 exit_status
 complete $SECONDS
 check_and_cleanup_lustre
 exit_status
index 03d7655..75f7595 100755 (executable)
@@ -10159,3 +10159,36 @@ sleep_maxage() {
                      awk '{ print $1 * 2; exit; }')
        sleep $delay
 }
                      awk '{ print $1 * 2; exit; }')
        sleep $delay
 }
+
+check_component_count() {
+       local comp_cnt=$($LFS getstripe --component-count $1)
+       [ $comp_cnt -eq $2 ] || error "$1, component count $comp_cnt != $2"
+}
+
+# Verify there are no init components with "extension" flag
+verify_no_init_extension() {
+       local flg_opts="--component-flags init,extension"
+       local found=$($LFS find $flg_opts $1 | wc -l)
+       [ $found -eq 0 ] || error "$1 has component with initialized extension"
+}
+
+# Verify there is at least one component starting at 0
+verify_comp_at_zero() {
+       flg_opts="--component-flags init"
+       found=$($LFS find --component-start 0M $flg_opts $1 | wc -l)
+       [ $found -eq 1 ] ||
+               error "No component starting at zero(!)"
+}
+
+#TODO: This version is a placeholder, to be replaced before final commit
+SEL_VER="2.12.52"
+
+sel_layout_sanity() {
+       local file=$1
+       local comp_cnt=$2
+
+       verify_no_init_extension $file
+       verify_comp_at_zero $file
+       check_component_count $file $comp_cnt
+}
+
index 4976a14..ffee3fc 100644 (file)
@@ -1795,7 +1795,7 @@ int llapi_layout_comp_extent_set(struct llapi_layout *layout,
        if (comp == NULL)
                return -1;
 
        if (comp == NULL)
                return -1;
 
-       if (start >= end) {
+       if (start > end) {
                errno = EINVAL;
                return -1;
        }
                errno = EINVAL;
                return -1;
        }