Whamcloud - gitweb
LU-10070 test: llapi_layout_test enhancements
[fs/lustre-release.git] / lustre / tests / llapi_layout_test.c
index 60d3ab8..f875f91 100644 (file)
@@ -20,6 +20,9 @@
  * GPL HEADER END
  */
 /*
+ * Copyright (c) 2016, 2017, Intel Corporation.
+ */
+/*
  * These tests exercise the llapi_layout API which abstracts the layout
  * of a Lustre file behind an opaque data type.  They assume a Lustre
  * file system with at least 2 OSTs and a pool containing at least the
@@ -46,6 +49,7 @@
 #include <sys/stat.h>
 #include <getopt.h>
 #include <inttypes.h>
+#include <sys/ioctl.h>
 
 #define ERROR(fmt, ...)                                                        \
        fprintf(stderr, "%s: %s:%d: %s: " fmt "\n",                     \
@@ -66,11 +70,13 @@ do {                                                                        \
 
 static char *lustre_dir;
 static char *poolname;
+static bool run_list_provided;
 static int num_osts = -1;
 
 void usage(char *prog)
 {
-       printf("Usage: %s [-d lustre_dir] [-p pool_name] [-o num_osts]\n",
+       printf("Usage: %s [-d lustre_dir] [-p pool_name] [-o num_osts] "
+              "[-s $n,$m,... (skip tests)] [-t $n,$m,... (run tests)]\n",
               prog);
        exit(0);
 }
@@ -200,7 +206,7 @@ void test3(void)
 {
        int rc;
        struct llapi_layout *layout;
-       lustre_fid fid;
+       struct lu_fid fid;
        char fidstr[4096];
        char path[PATH_MAX];
 
@@ -231,7 +237,7 @@ void test4(void)
        uint64_t size;
        const char *lfs = getenv("LFS");
        char mypool[LOV_MAXPOOLNAME + 1] = { '\0' };
-       char cmd[4096];
+       char cmd[PATH_MAX + 128];
        char path[PATH_MAX];
 
        snprintf(path, sizeof(path), "%s/%s", lustre_dir, T4FILE);
@@ -242,7 +248,7 @@ void test4(void)
        rc = unlink(path);
        ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno);
 
-       snprintf(cmd, sizeof(cmd), "%s setstripe %s %s -c %d -s %d %s", lfs,
+       snprintf(cmd, sizeof(cmd), "%s setstripe %s %s -c %d -S %d %s", lfs,
                 strlen(poolname) > 0 ? "-p" : "", poolname, T4_STRIPE_COUNT,
                 T4_STRIPE_SIZE, path);
        rc = system(cmd);
@@ -556,12 +562,6 @@ void test13(void)
        layout = llapi_layout_alloc();
        ASSERTF(layout != NULL, "errno = %d", errno);
 
-       /* Only setting OST index for stripe 0 is supported for now. */
-       errno = 0;
-       rc = llapi_layout_ost_index_set(layout, 1, 1);
-       ASSERTF(rc == -1 && errno == EOPNOTSUPP, "rc = %d, errno = %d",
-               rc, errno);
-
        /* invalid OST index */
        errno = 0;
        rc = llapi_layout_ost_index_set(layout, 0, LLAPI_LAYOUT_INVALID);
@@ -715,7 +715,9 @@ void test16(void)
 
        rc = llapi_layout_stripe_count_get(filelayout, &fcount);
        ASSERTF(rc == 0, "errno = %d", errno);
-       ASSERTF(fcount == dcount, "%"PRIu64" != %"PRIu64, fcount, dcount);
+       ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT ||
+               dcount == LLAPI_LAYOUT_WIDE,
+               "%"PRIu64" != %"PRIu64, fcount, dcount);
 
        rc = llapi_layout_stripe_size_get(filelayout, &fsize);
        ASSERTF(rc == 0, "errno = %d", errno);
@@ -736,7 +738,9 @@ void test16(void)
        ASSERTF(rc == 0, "errno = %d", errno);
        rc = llapi_layout_stripe_size_get(filelayout, &fsize);
        ASSERTF(rc == 0, "errno = %d", errno);
-       ASSERTF(fcount == dcount, "%"PRIu64" != %"PRIu64, fcount, dcount);
+       ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT ||
+               dcount == LLAPI_LAYOUT_WIDE,
+               "%"PRIu64" != %"PRIu64, fcount, dcount);
        ASSERTF(fsize == dsize, "%"PRIu64" != %"PRIu64, fsize, dsize);
 
        llapi_layout_free(filelayout);
@@ -894,7 +898,9 @@ void test20(void)
        ASSERTF(rc == 0, "errno = %d", errno);
        rc = llapi_layout_stripe_count_get(deflayout, &dcount);
        ASSERTF(rc == 0, "errno = %d", errno);
-       ASSERTF(fcount == dcount, "%"PRIu64" != %"PRIu64, fcount, dcount);
+       ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT ||
+               dcount == LLAPI_LAYOUT_WIDE,
+               "%"PRIu64" != %"PRIu64, fcount, dcount);
 
        rc = llapi_layout_stripe_size_get(filelayout, &fsize);
        ASSERTF(rc == 0, "errno = %d", errno);
@@ -1080,7 +1086,7 @@ void test26(void)
        uint64_t size;
        uint64_t pattern;
        char dir[PATH_MAX];
-       char cmd[4096];
+       char cmd[PATH_MAX + 64];
 
        snprintf(dir, sizeof(dir), "%s/%s", lustre_dir, T26DIR);
        rc = rmdir(dir);
@@ -1091,7 +1097,7 @@ void test26(void)
        if (lfs == NULL)
                lfs = "/usr/bin/lfs";
 
-       snprintf(cmd, sizeof(cmd), "%s setstripe -s %d %s", lfs,
+       snprintf(cmd, sizeof(cmd), "%s setstripe -S %d %s", lfs,
                 T26_STRIPE_SIZE, dir);
        rc = system(cmd);
        ASSERTF(rc == 0, "system(%s): exit status %d", cmd, WEXITSTATUS(rc));
@@ -1127,11 +1133,11 @@ void test27(void)
        uint64_t count;
        uint64_t size;
        uint64_t pattern;
-       char dirpath[PATH_MAX];
-       char filepath[PATH_MAX];
-       char cmd[4096];
+       char dirpath[PATH_MAX + 128];
+       char filepath[PATH_MAX * 2];
+       char cmd[PATH_MAX * 2];
 
-       snprintf(dirpath, sizeof(dirpath), "%s/%s", lustre_dir, T27DIR);
+       snprintf(dirpath, sizeof(dirpath) - 1, "%s/%s", lustre_dir, T27DIR);
        snprintf(filepath, sizeof(filepath), "%s/nonesuch", dirpath);
 
        rc = rmdir(dirpath);
@@ -1142,7 +1148,7 @@ void test27(void)
        if (lfs == NULL)
                lfs = "/usr/bin/lfs";
 
-       snprintf(cmd, sizeof(cmd), "%s setstripe -s %d %s", lfs,
+       snprintf(cmd, sizeof(cmd), "%s setstripe -S %d %s", lfs,
                 T27_STRIPE_SIZE, dirpath);
        rc = system(cmd);
        ASSERTF(rc == 0, "system(%s): exit status %d", cmd, WEXITSTATUS(rc));
@@ -1176,7 +1182,7 @@ void test28(void)
        const char *lfs = getenv("LFS");
        uint64_t count;
        char dirpath[PATH_MAX];
-       char cmd[4096];
+       char cmd[PATH_MAX + 64];
 
        snprintf(dirpath, sizeof(dirpath), "%s/%s", lustre_dir, T28DIR);
 
@@ -1202,7 +1208,537 @@ void test28(void)
        llapi_layout_free(layout);
 }
 
-#define TEST_DESC_LEN  50
+#define T29FILE                "f29"
+#define T29_DESC       "set ost index to non-zero stripe number"
+void test29(void)
+{
+       int rc, fd, i;
+       uint64_t ost0, ost1, nost;
+       struct llapi_layout *layout;
+       char path[PATH_MAX];
+
+       if (num_osts < 2)
+               return;
+
+       layout = llapi_layout_alloc();
+       ASSERTF(layout != NULL, "errno %d", errno);
+
+       snprintf(path, sizeof(path), "%s/%s", lustre_dir, T29FILE);
+
+       rc = unlink(path);
+       ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno);
+
+       /* set ost index to LLAPI_LAYOUT_IDX_MAX should fail */
+       rc = llapi_layout_ost_index_set(layout, 1, LLAPI_LAYOUT_IDX_MAX);
+       ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d\n",
+               rc, errno);
+
+       /* specify ost index partially */
+       rc = llapi_layout_ost_index_set(layout, 1, 0);
+       ASSERTF(rc == 0, "errno = %d", errno);
+
+       /* create a partially specified layout will fail */
+       fd = llapi_layout_file_create(path, 0, 0660, layout);
+       ASSERTF(fd == -1 && errno == EINVAL, "path = %s, fd = %d, errno = %d",
+               path, fd, errno);
+
+       rc = unlink(path);
+       ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno);
+
+       /* specify all stripes */
+       rc = llapi_layout_ost_index_set(layout, 0, 1);
+       ASSERTF(rc == 0, "errno = %d", errno);
+
+       /* create */
+       fd = llapi_layout_file_create(path, 0, 0660, layout);
+       ASSERTF(fd >= 0, "path = %s, fd = %d, errno = %d", path, fd, errno);
+
+       rc = close(fd);
+       ASSERTF(rc == 0, "errno = %d", errno);
+       llapi_layout_free(layout);
+
+       /* get layout from file */
+       layout = llapi_layout_get_by_path(path, 0);
+       ASSERTF(layout != NULL, "errno = %d", errno);
+
+       rc = llapi_layout_ost_index_get(layout, 0, &ost0);
+       ASSERTF(rc == 0, "errno = %d", errno);
+       rc = llapi_layout_ost_index_get(layout, 1, &ost1);
+       ASSERTF(rc == 0, "errno = %d", errno);
+       ASSERTF(ost0 == 1, "%"PRIu64" != %d", ost0, 1);
+       ASSERTF(ost1 == 0, "%"PRIu64" != %d", ost1, 0);
+       llapi_layout_free(layout);
+
+       /* specify more ost indexes to test realloc */
+       nost = 0;
+       layout = llapi_layout_alloc();
+       ASSERTF(layout != NULL, "errno %d", errno);
+       for (i = 0; i < LOV_MAX_STRIPE_COUNT; i++) {
+               rc = llapi_layout_ost_index_set(layout, i, nost);
+               ASSERTF(rc == 0, "errno = %d", errno);
+               rc = llapi_layout_ost_index_get(layout, i, &ost0);
+               ASSERTF(rc == 0, "errno = %d", errno);
+               nost++;
+               if (nost == num_osts)
+                       nost = 0;
+       }
+
+       nost = 0;
+       for (i = 0; i < LOV_MAX_STRIPE_COUNT; i++) {
+               rc = llapi_layout_ost_index_get(layout, i, &ost0);
+               ASSERTF(rc == 0, "errno = %d", errno);
+               ASSERTF(ost0 == nost, "ost=%"PRIu64" nost=%"PRIu64"",
+                       ost0, nost);
+               nost++;
+               if (nost == num_osts)
+                       nost = 0;
+       }
+       llapi_layout_free(layout);
+
+       nost = 0;
+       layout = llapi_layout_alloc();
+       ASSERTF(layout != NULL, "errno %d", errno);
+       for (i = LOV_MAX_STRIPE_COUNT-1; i >= 0; i--) {
+               rc = llapi_layout_ost_index_set(layout, i, nost);
+               ASSERTF(rc == 0, "errno = %d", errno);
+               rc = llapi_layout_ost_index_get(layout, i, &ost0);
+               ASSERTF(rc == 0, "errno = %d", errno);
+               nost++;
+               if (nost == num_osts)
+                       nost = 0;
+       }
+
+       nost = 0;
+       for (i = LOV_MAX_STRIPE_COUNT-1; i <= 0; i--) {
+               rc = llapi_layout_ost_index_get(layout, i, &ost0);
+               ASSERTF(rc == 0, "errno = %d", errno);
+               ASSERTF(ost0 == nost, "ost=%"PRIu64", nost=%"PRIu64"",
+                       ost0, nost);
+               nost++;
+               if (nost == num_osts)
+                       nost = 0;
+       }
+       llapi_layout_free(layout);
+}
+
+#define T30FILE                "f30"
+#define T30_DESC       "create composite file, traverse components"
+void test30(void)
+{
+       int rc, fd;
+       uint64_t start[3], end[3];
+       uint64_t s, e;
+       struct llapi_layout *layout;
+       char path[PATH_MAX];
+
+       start[0] = 0;
+       end[0] = 64 * 1024 * 1024; /* 64m */
+       start[1] = end[0];
+       end[1] = 1 * 1024 * 1024 * 1024; /* 1G */
+       start[2] = end[1];
+       end[2] = LUSTRE_EOF;
+
+       if (num_osts < 2)
+               return;
+
+       snprintf(path, sizeof(path), "%s/%s", lustre_dir, T30FILE);
+
+       rc = unlink(path);
+       ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno);
+
+       layout = llapi_layout_alloc();
+       ASSERTF(layout != NULL, "errno %d", errno);
+
+       rc = llapi_layout_stripe_count_set(layout, 1);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* add component without adjusting previous component's extent
+        * end will fail. */
+       rc = llapi_layout_comp_add(layout);
+       ASSERTF(rc == -1 && errno == EINVAL, "rc %d, errno %d", rc, errno);
+
+       rc = llapi_layout_comp_extent_set(layout, start[0], end[0]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_add(layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* set non-contiguous extent will fail */
+       rc = llapi_layout_comp_extent_set(layout, start[1] * 2, end[1]);
+       ASSERTF(rc == 0, "errno %d", errno);
+       rc = llapi_layout_sanity(layout, false, false);
+       ASSERTF(rc == 12 /*LSE_NOT_ADJACENT_PREV*/, "rc %d", rc);
+
+       rc = llapi_layout_comp_extent_set(layout, start[1], end[1]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_add(layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_extent_set(layout, start[2], end[2]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* create composite file */
+       fd = llapi_layout_file_create(path, 0, 0660, layout);
+       ASSERTF(fd >= 0, "path = %s, fd = %d, errno = %d", path, fd, errno);
+
+       llapi_layout_free(layout);
+
+       /* traverse & verify all components */
+       layout = llapi_layout_get_by_path(path, 0);
+       ASSERTF(layout != NULL, "errno = %d", errno);
+
+       /* current component should be the tail component */
+       rc = llapi_layout_comp_extent_get(layout, &s, &e);
+       ASSERTF(rc == 0, "errno %d", errno);
+       ASSERTF(s == start[2] && e == end[2],
+               "s: %"PRIu64", e: %"PRIu64"", s, e);
+
+       rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
+       ASSERTF(rc == 0, "rc %d, errno %d", rc, errno);
+
+       /* delete non-tail component will fail */
+       rc = llapi_layout_comp_del(layout);
+       ASSERTF(rc == -1 && errno == EINVAL, "rc %d, errno %d", rc, errno);
+
+       rc = llapi_layout_comp_extent_get(layout, &s, &e);
+       ASSERTF(rc == 0, "errno %d", errno);
+       ASSERTF(s == start[0] && e == end[0],
+               "s: %"PRIu64", e: %"PRIu64"", s, e);
+
+       rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
+       ASSERTF(rc == 0, "rc %d, errno %d", rc,  errno);
+
+       rc = llapi_layout_comp_extent_get(layout, &s, &e);
+       ASSERTF(rc == 0, "errno %d", errno);
+       ASSERTF(s == start[1] && e == end[1],
+               "s: %"PRIu64", e: %"PRIu64"", s, e);
+
+       rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
+       ASSERTF(rc == 0, "rc %d, errno %d", rc,  errno);
+
+       rc = llapi_layout_comp_del(layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       llapi_layout_free(layout);
+}
+
+#define T31FILE                "f31"
+#define T31_DESC       "add/delete component to/from existing file"
+void test31(void)
+{
+       int rc, fd, i;
+       uint64_t start[2], end[2];
+       uint64_t s, e;
+       uint32_t id[2];
+       struct llapi_layout *layout;
+       char path[PATH_MAX];
+
+       start[0] = 0;
+       end[0] = 64 * 1024 * 1024; /* 64m */
+       start[1] = end[0];
+       end[1] = LUSTRE_EOF;
+
+       if (num_osts < 2)
+               return;
+
+       snprintf(path, sizeof(path), "%s/%s", lustre_dir, T31FILE);
+
+       rc = unlink(path);
+       ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno);
+
+       layout = llapi_layout_alloc();
+       ASSERTF(layout != NULL, "errno %d", errno);
+
+       rc = llapi_layout_stripe_count_set(layout, 1);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_extent_set(layout, start[0], end[0]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* create composite file */
+       fd = llapi_layout_file_create(path, 0, 0660, layout);
+       ASSERTF(fd >= 0, "path = %s, fd = %d, errno = %d", path, fd, errno);
+       llapi_layout_free(layout);
+
+       layout = llapi_layout_alloc();
+       ASSERTF(layout != NULL, "errno %d", errno);
+
+       rc = llapi_layout_stripe_count_set(layout, 2);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_extent_set(layout, start[1], end[1]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* add comopnent to existing file */
+       rc = llapi_layout_file_comp_add(path, layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+       llapi_layout_free(layout);
+
+       /* verify the composite layout after adding */
+       layout = llapi_layout_get_by_path(path, 0);
+       ASSERTF(layout != NULL, "errno = %d", errno);
+
+       rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
+       ASSERTF(rc == 0, "rc %d, errno %d", rc, errno);
+       i = 0;
+       do {
+               rc = llapi_layout_comp_extent_get(layout, &s, &e);
+               ASSERTF(rc == 0 && i < 2, "i %d, errno %d", i, errno);
+               ASSERTF(s == start[i] && e == end[i],
+                       "i: %d s: %"PRIu64", e: %"PRIu64"", i, s, e);
+
+               rc = llapi_layout_comp_id_get(layout, &id[i]);
+               ASSERTF(rc == 0 && id[i] != 0, "i %d, errno %d, id %d",
+                       i, errno, id[i]);
+
+               rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
+               ASSERTF(rc == 0 || i == 1, "i=%d rc=%d errno=%d", i, rc, errno);
+               i++;
+       } while (rc == 0);
+
+       /* Verify reverse iteration gives the same IDs as forward iteration */
+       rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_LAST);
+       ASSERTF(rc == 0, "rc %d, errno %d", rc, errno);
+       do {
+               __u32 comp_id;
+
+               --i;
+               rc = llapi_layout_comp_id_get(layout, &comp_id);
+               ASSERTF(rc == 0 && comp_id == id[i],
+                       "i %d, errno %d, id[] %u/%u", i, errno, id[i], comp_id);
+
+               rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV);
+               ASSERTF(rc == 0 || i == 0, "i=%d rc=%d errno=%d", i, rc, errno);
+       } while (rc == 0);
+
+       llapi_layout_free(layout);
+
+       /* delete non-tail component will fail */
+       rc = llapi_layout_file_comp_del(path, id[0], 0);
+       ASSERTF(rc < 0 && errno == EINVAL, "rc %d, errno %d", rc, errno);
+
+       rc = llapi_layout_file_comp_del(path, id[1], 0);
+       ASSERTF(rc == 0, "rc %d, errno %d", rc, errno);
+
+       /* verify the composite layout after deleting */
+       layout = llapi_layout_get_by_path(path, 0);
+       ASSERTF(layout != NULL, "errno = %d", errno);
+
+       rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
+       ASSERTF(rc == 0, "rc %d, errno %d", rc, errno);
+
+       rc = llapi_layout_comp_extent_get(layout, &s, &e);
+       ASSERTF(rc == 0, "errno %d", errno);
+       ASSERTF(s == start[0] && e == end[0],
+               "s: %"PRIu64", e: %"PRIu64"", s, e);
+}
+
+#define T32FILE                        "t32"
+#define T32_STRIPE_COUNT       (num_osts*2)
+#define T32_DESC               "Test overstriping with layout_file_create"
+void test32(void)
+{
+       int rc;
+       int fd;
+       uint64_t count;
+       struct llapi_layout *layout = llapi_layout_alloc();
+       void *lmdbuf = NULL;
+       struct lov_user_md *lmd;
+       char path[PATH_MAX];
+
+       ASSERTF(layout != NULL, "errno %d", errno);
+
+       /* Maximum possible, to be on the safe side - num_osts could be large */
+       lmdbuf = malloc(XATTR_SIZE_MAX);
+       ASSERTF(lmdbuf != NULL, "errno %d", errno);
+       lmd = lmdbuf;
+
+       snprintf(path, sizeof(path), "%s/%s", lustre_dir, T32FILE);
+
+       rc = unlink(path);
+       ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno);
+
+       /* stripe count */
+       rc = llapi_layout_stripe_count_set(layout, T32_STRIPE_COUNT);
+       ASSERTF(rc == 0, "errno = %d", errno);
+       rc = llapi_layout_stripe_count_get(layout, &count);
+       ASSERTF(rc == 0 && count == T32_STRIPE_COUNT, "%"PRIu64" != %d", count,
+               T32_STRIPE_COUNT);
+
+       rc = llapi_layout_pattern_set(layout, LLAPI_LAYOUT_OVERSTRIPING);
+       ASSERTF(rc == 0, "errno = %d", errno);
+
+       /* create */
+       fd = llapi_layout_file_create(path, 0, 0660, layout);
+       ASSERTF(fd >= 0, "path = %s, errno = %d", path, errno);
+
+       rc = ioctl(fd, LL_IOC_LOV_GETSTRIPE_NEW, lmdbuf);
+       ASSERTF(rc == 0, "errno = %d", errno);
+
+       count = lmd->lmm_stripe_count;
+       ASSERTF(count == T32_STRIPE_COUNT,
+               "stripe count (%"PRIu64") not equal to expected (%d)",
+               count, T32_STRIPE_COUNT);
+
+       rc = close(fd);
+       ASSERTF(rc == 0, "errno = %d", errno);
+       llapi_layout_free(layout);
+       free(lmdbuf);
+}
+
+#define T33FILE                        "t33"
+#define T33_STRIPE_COUNT       (num_osts*2)
+#define T33_DESC               "Test overstriping with llapi_file_open"
+void test33(void)
+{
+       int rc;
+       int fd;
+       uint64_t count;
+       void *lmdbuf = NULL;
+       struct lov_user_md *lmd;
+       char path[PATH_MAX];
+
+       /* Maximum possible, to be on the safe side - num_osts could be large */
+       lmdbuf = malloc(XATTR_SIZE_MAX);
+       ASSERTF(lmdbuf != NULL, "errno %d", errno);
+       lmd = lmdbuf;
+
+       snprintf(path, sizeof(path), "%s/%s", lustre_dir, T33FILE);
+
+       rc = unlink(path);
+       ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno);
+
+       fd = llapi_file_open(path, O_CREAT | O_RDWR, 0660, 0, -1, num_osts*2,
+                            LOV_PATTERN_RAID0 | LOV_PATTERN_OVERSTRIPING);
+       ASSERTF(fd >= 0, "path = %s, errno = %d", path, errno);
+
+       rc = ioctl(fd, LL_IOC_LOV_GETSTRIPE_NEW, lmdbuf);
+       ASSERTF(rc == 0, "errno = %d", errno);
+
+       count = lmd->lmm_stripe_count;
+       ASSERTF(count == T33_STRIPE_COUNT,
+               "stripe count (%"PRIu64") not equal to expected (%d)",
+               count, T33_STRIPE_COUNT);
+
+       rc = close(fd);
+       ASSERTF(rc == 0, "errno = %d", errno);
+       free(lmdbuf);
+}
+
+#define T34FILE                "f34"
+#define T34_DESC       "create simple valid & invalid self extending layouts"
+void test34(void)
+{
+       int rc, fd;
+       uint64_t start[4], end[4];
+       struct llapi_layout *layout;
+       char path[PATH_MAX];
+
+       start[0] = 0;
+       end[0] = 10 * 1024 * 1024; /* 10m */
+       start[1] = end[0];
+       end[1] = 1024 * 1024 * 1024; /* 1G */
+       start[2] = end[1];
+       end[2] = 10ull * 1024 * 1024 * 1024; /* 10G */
+       start[3] = end[2];
+       end[3] = LUSTRE_EOF;
+
+       if (num_osts < 2)
+               return;
+
+       snprintf(path, sizeof(path), "%s/%s", lustre_dir, T34FILE);
+
+       rc = unlink(path);
+       ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno);
+
+       layout = llapi_layout_alloc();
+       ASSERTF(layout != NULL, "errno %d", errno);
+
+       rc = llapi_layout_stripe_count_set(layout, 1);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* add component without adjusting previous component's extent
+        * end will fail.
+        */
+       rc = llapi_layout_comp_add(layout);
+       ASSERTF(rc == -1 && errno == EINVAL, "rc %d, errno %d", rc, errno);
+
+       rc = llapi_layout_comp_extent_set(layout, start[0], end[0]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_add(layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_extent_set(layout, start[1], end[1]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_flags_set(layout, LCME_FL_EXTENSION);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* Invalid size, too small - < 64 MiB */
+       rc = llapi_layout_extension_size_set(layout, 32 << 20);
+       ASSERTF(rc == -1, "errno %d", errno);
+
+       /* too large - > 4 TiB */
+       rc = llapi_layout_extension_size_set(layout, 5ull << 40);
+       ASSERTF(rc == -1, "errno %d", errno);
+
+       /* Valid size, 64 MiB */
+       rc = llapi_layout_extension_size_set(layout, 64 << 20);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_add(layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_extent_set(layout, start[2], end[2]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* Set extension space flag on adjacent components:
+        * This is invalid, but can't be checked until we try to create the
+        * file. */
+       rc = llapi_layout_comp_flags_set(layout, LCME_FL_EXTENSION);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       fd = llapi_layout_file_create(path, 0, 0660, layout);
+       ASSERTF(fd = -1, "path = %s, fd = %d, errno = %d", path, fd, errno);
+
+       /* Delete incorrect component */
+       rc = llapi_layout_comp_del(layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_add(layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* Convert this comp to zero-length so it can be followed by extension
+        * space */
+       rc = llapi_layout_comp_extent_set(layout, start[2], start[2]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_add(layout);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_extent_set(layout, start[2], end[3]);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       rc = llapi_layout_comp_flags_set(layout, LCME_FL_EXTENSION);
+       ASSERTF(rc == 0, "errno %d", errno);
+
+       /* create composite file */
+       fd = llapi_layout_file_create(path, 0, 0660, layout);
+       ASSERTF(fd >= 0, "path = %s, fd = %d, errno = %d", path, fd, errno);
+
+       llapi_layout_free(layout);
+
+       /* traverse & verify all components */
+       layout = llapi_layout_get_by_path(path, 0);
+       ASSERTF(layout != NULL, "errno = %d", errno);
+
+       rc = llapi_layout_sanity(layout, false, false);
+       ASSERTF(rc == 0, "errno %d", errno);
+}
+
+#define TEST_DESC_LEN  80
 struct test_tbl_entry {
        void (*tte_fn)(void);
        char tte_desc[TEST_DESC_LEN];
@@ -1210,36 +1746,43 @@ struct test_tbl_entry {
 };
 
 static struct test_tbl_entry test_tbl[] = {
-       { &test0,  T0_DESC, false },
-       { &test1,  T1_DESC, false },
-       { &test2,  T2_DESC, false },
-       { &test3,  T3_DESC, false },
-       { &test4,  T4_DESC, false },
-       { &test5,  T5_DESC, false },
-       { &test6,  T6_DESC, false },
-       { &test7,  T7_DESC, false },
-       { &test8,  T8_DESC, false },
-       { &test9,  T9_DESC, false },
-       { &test10, T10_DESC, false },
-       { &test11, T11_DESC, false },
-       { &test12, T12_DESC, false },
-       { &test13, T13_DESC, false },
-       { &test14, T14_DESC, false },
-       { &test15, T15_DESC, false },
-       { &test16, T16_DESC, false },
-       { &test17, T17_DESC, false },
-       { &test18, T18_DESC, false },
-       { &test19, T19_DESC, false },
-       { &test20, T20_DESC, false },
-       { &test21, T21_DESC, false },
-       { &test22, T22_DESC, false },
-       { &test23, T23_DESC, false },
-       { &test24, T24_DESC, false },
-       { &test25, T25_DESC, false },
-       { &test26, T26_DESC, false },
-       { &test27, T27_DESC, false },
-       { &test28, T28_DESC, false },
+       { .tte_fn = &test0, .tte_desc = T0_DESC, .tte_skip = false },
+       { .tte_fn = &test1, .tte_desc = T1_DESC, .tte_skip = false },
+       { .tte_fn = &test2, .tte_desc = T2_DESC, .tte_skip = false },
+       { .tte_fn = &test3, .tte_desc = T3_DESC, .tte_skip = false },
+       { .tte_fn = &test4, .tte_desc = T4_DESC, .tte_skip = false },
+       { .tte_fn = &test5, .tte_desc = T5_DESC, .tte_skip = false },
+       { .tte_fn = &test6, .tte_desc = T6_DESC, .tte_skip = false },
+       { .tte_fn = &test7, .tte_desc = T7_DESC, .tte_skip = false },
+       { .tte_fn = &test8, .tte_desc = T8_DESC, .tte_skip = false },
+       { .tte_fn = &test9, .tte_desc = T9_DESC, .tte_skip = false },
+       { .tte_fn = &test10, .tte_desc = T10_DESC, .tte_skip = false },
+       { .tte_fn = &test11, .tte_desc = T11_DESC, .tte_skip = false },
+       { .tte_fn = &test12, .tte_desc = T12_DESC, .tte_skip = false },
+       { .tte_fn = &test13, .tte_desc = T13_DESC, .tte_skip = false },
+       { .tte_fn = &test14, .tte_desc = T14_DESC, .tte_skip = false },
+       { .tte_fn = &test15, .tte_desc = T15_DESC, .tte_skip = false },
+       { .tte_fn = &test16, .tte_desc = T16_DESC, .tte_skip = false },
+       { .tte_fn = &test17, .tte_desc = T17_DESC, .tte_skip = false },
+       { .tte_fn = &test18, .tte_desc = T18_DESC, .tte_skip = false },
+       { .tte_fn = &test19, .tte_desc = T19_DESC, .tte_skip = false },
+       { .tte_fn = &test20, .tte_desc = T20_DESC, .tte_skip = false },
+       { .tte_fn = &test21, .tte_desc = T21_DESC, .tte_skip = false },
+       { .tte_fn = &test22, .tte_desc = T22_DESC, .tte_skip = false },
+       { .tte_fn = &test23, .tte_desc = T23_DESC, .tte_skip = false },
+       { .tte_fn = &test24, .tte_desc = T24_DESC, .tte_skip = false },
+       { .tte_fn = &test25, .tte_desc = T25_DESC, .tte_skip = false },
+       { .tte_fn = &test26, .tte_desc = T26_DESC, .tte_skip = false },
+       { .tte_fn = &test27, .tte_desc = T27_DESC, .tte_skip = false },
+       { .tte_fn = &test28, .tte_desc = T28_DESC, .tte_skip = false },
+       { .tte_fn = &test29, .tte_desc = T29_DESC, .tte_skip = false },
+       { .tte_fn = &test30, .tte_desc = T30_DESC, .tte_skip = false },
+       { .tte_fn = &test31, .tte_desc = T31_DESC, .tte_skip = false },
+       { .tte_fn = &test32, .tte_desc = T32_DESC, .tte_skip = false },
+       { .tte_fn = &test33, .tte_desc = T33_DESC, .tte_skip = false },
+       { .tte_fn = &test34, .tte_desc = T34_DESC, .tte_skip = false },
 };
+
 #define NUM_TESTS      (sizeof(test_tbl) / sizeof(struct test_tbl_entry))
 
 void print_test_desc(int test_num, const char *test_desc, const char *status)
@@ -1261,7 +1804,8 @@ int test(void (*test_fn)(), const char *test_desc, bool test_skip, int test_num)
        char status_buf[128];
 
        if (test_skip) {
-               print_test_desc(test_num, test_desc, "skip");
+               if (!run_list_provided)
+                       print_test_desc(test_num, test_desc, "skip");
                return 0;
        }
 
@@ -1296,11 +1840,54 @@ int test(void (*test_fn)(), const char *test_desc, bool test_skip, int test_num)
        return rc;
 }
 
+/* 'str_tests' are the tests to be skipped, such as "1,3,4,.." */
+static void set_tests_skipped(char *str_tests)
+{
+       char *ptr = str_tests;
+       int tstno;
+
+       if (ptr == NULL || strlen(ptr) == 0)
+               return;
+
+       while (*ptr != '\0') {
+               tstno = strtoul(ptr, &ptr, 0);
+               if (tstno >= 0 && tstno < NUM_TESTS)
+                       test_tbl[tstno].tte_skip = true;
+               if (*ptr == ',')
+                       ptr++;
+               else
+                       break;
+       }
+}
+
+static void set_tests_to_run(char *str_tests)
+{
+       char *ptr = str_tests;
+       int tstno;
+       int i = 0;
+
+       if (ptr == NULL || strlen(ptr) == 0)
+               return;
+
+       for (i = 0; i < NUM_TESTS ; i++)
+               test_tbl[i].tte_skip = true;
+
+       while (*ptr != '\0') {
+               tstno = strtoul(ptr, &ptr, 0);
+               if (tstno >= 0 && tstno < NUM_TESTS)
+                       test_tbl[tstno].tte_skip = false;
+               if (*ptr == ',')
+                       ptr++;
+               else
+                       break;
+       }
+}
+
 static void process_args(int argc, char *argv[])
 {
        int c;
 
-       while ((c = getopt(argc, argv, "d:p:o:")) != -1) {
+       while ((c = getopt(argc, argv, "d:p:o:s:t:")) != -1) {
                switch (c) {
                case 'd':
                        lustre_dir = optarg;
@@ -1311,6 +1898,13 @@ static void process_args(int argc, char *argv[])
                case 'o':
                        num_osts = atoi(optarg);
                        break;
+               case 's':
+                       set_tests_skipped(optarg);
+                       break;
+               case 't':
+                       run_list_provided = true;
+                       set_tests_to_run(optarg);
+                       break;
                case '?':
                        fprintf(stderr, "Unknown option '%c'\n", optopt);
                        usage(argv[0]);
@@ -1359,5 +1953,6 @@ int main(int argc, char *argv[])
                if (test(tst->tte_fn, tst->tte_desc, tst->tte_skip, i) != 0)
                        rc++;
        }
+
        return rc;
 }