Whamcloud - gitweb
LU-17402 kernel: update dotdot patch path for RHEL 8.10
[fs/lustre-release.git] / lustre / tests / llapi_layout_test.c
index 385b886..051e048 100644 (file)
@@ -49,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",                     \
@@ -67,14 +68,18 @@ do {                                                                        \
                DIE("assertion '%s' failed: "fmt, #cond, ## __VA_ARGS__);\
 } while (0)                                                            \
 
+#define IN_RANGE(value, low, high) ((value >= low) && (value <= high))
+
 static char *lustre_dir;
 static char *poolname;
+static bool run_list_provided;
 static int num_osts = -1;
 
-void usage(char *prog)
+static void usage(char *prog)
 {
        printf("Usage: %s [-d lustre_dir] [-p pool_name] [-o num_osts] "
-              "[-s $n,$m,..]\n", prog);
+              "[-s $n,$m,... (skip tests)] [-t $n,$m,... (run tests)]\n",
+              prog);
        exit(0);
 }
 
@@ -83,7 +88,7 @@ void usage(char *prog)
 #define T0_STRIPE_SIZE         1048576
 #define T0_OST_OFFSET          (num_osts - 1)
 #define T0_DESC                "Read/write layout attributes then create a file"
-void test0(void)
+static void test0(void)
 {
        int rc;
        int fd;
@@ -134,7 +139,7 @@ void test0(void)
        llapi_layout_free(layout);
 }
 
-void __test1_helper(struct llapi_layout *layout)
+static void __test1_helper(struct llapi_layout *layout)
 {
        uint64_t ost0;
        uint64_t ost1;
@@ -165,19 +170,20 @@ void __test1_helper(struct llapi_layout *layout)
 }
 
 #define T1_DESC                "Read test0 file by path and verify attributes"
-void test1(void)
+static void test1(void)
 {
        char path[PATH_MAX];
 
        snprintf(path, sizeof(path), "%s/%s", lustre_dir, T0FILE);
        struct llapi_layout *layout = llapi_layout_get_by_path(path, 0);
+
        ASSERTF(layout != NULL, "errno = %d", errno);
        __test1_helper(layout);
        llapi_layout_free(layout);
 }
 
 #define T2_DESC                "Read test0 file by FD and verify attributes"
-void test2(void)
+static void test2(void)
 {
        int fd;
        int rc;
@@ -189,6 +195,7 @@ void test2(void)
        ASSERTF(fd >= 0, "open(%s): errno = %d", path, errno);
 
        struct llapi_layout *layout = llapi_layout_get_by_fd(fd, 0);
+
        ASSERTF(layout != NULL, "errno = %d", errno);
 
        rc = close(fd);
@@ -199,7 +206,7 @@ void test2(void)
 }
 
 #define T3_DESC                "Read test0 file by FID and verify attributes"
-void test3(void)
+static void test3(void)
 {
        int rc;
        struct llapi_layout *layout;
@@ -225,7 +232,7 @@ void test3(void)
 #define T4_STRIPE_COUNT                2
 #define T4_STRIPE_SIZE         2097152
 #define T4_DESC                "Verify compatibility with 'lfs setstripe'"
-void test4(void)
+static void test4(void)
 {
        int rc;
        uint64_t ost0;
@@ -234,7 +241,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);
@@ -253,6 +260,7 @@ void test4(void)
 
        errno = 0;
        struct llapi_layout *layout = llapi_layout_get_by_path(path, 0);
+
        ASSERTF(layout != NULL, "errno = %d", errno);
 
        rc = llapi_layout_stripe_count_get(layout, &count);
@@ -279,7 +287,7 @@ void test4(void)
 
 #define T5FILE         "t5"
 #define T5_DESC                "llapi_layout_get_by_path ENOENT handling"
-void test5(void)
+static void test5(void)
 {
        int rc;
        char path[PATH_MAX];
@@ -296,16 +304,17 @@ void test5(void)
 }
 
 #define T6_DESC                "llapi_layout_get_by_fd EBADF handling"
-void test6(void)
+static void test6(void)
 {
        errno = 0;
        struct llapi_layout *layout = llapi_layout_get_by_fd(9999, 0);
+
        ASSERTF(layout == NULL && errno == EBADF, "errno = %d", errno);
 }
 
 #define T7FILE         "t7"
 #define T7_DESC                "llapi_layout_get_by_path EACCES handling"
-void test7(void)
+static void test7(void)
 {
        int fd;
        int rc;
@@ -340,16 +349,18 @@ void test7(void)
        ASSERTF(rc == 0, "errno = %d", errno);
        errno = 0;
        struct llapi_layout *layout = llapi_layout_get_by_path(path, 0);
+
        ASSERTF(layout == NULL && errno == EACCES, "errno = %d", errno);
        rc = seteuid(myuid);
        ASSERTF(rc == 0, "errno = %d", errno);
 }
 
 /* llapi_layout_get_by_path() returns default layout for file with no
- * striping attributes. */
+ * striping attributes.
+ */
 #define T8FILE         "t8"
 #define T8_DESC                "llapi_layout_get_by_path ENODATA handling"
-void test8(void)
+static void test8(void)
 {
        int fd;
        int rc;
@@ -389,7 +400,7 @@ void test8(void)
 
 /* Verify llapi_layout_patter_set() return values for various inputs. */
 #define T9_DESC                "verify llapi_layout_pattern_set() return values"
-void test9(void)
+static void test9(void)
 {
        struct llapi_layout *layout;
        int rc;
@@ -420,7 +431,7 @@ void test9(void)
 
 /* Verify stripe_count interfaces return errors as expected */
 #define T10_DESC       "stripe_count error handling"
-void test10(void)
+static void test10(void)
 {
        int rc;
        uint64_t count;
@@ -462,7 +473,7 @@ void test10(void)
 
 /* Verify stripe_size interfaces return errors as expected */
 #define T11_DESC       "stripe_size error handling"
-void test11(void)
+static void test11(void)
 {
        int rc;
        uint64_t size;
@@ -505,7 +516,7 @@ void test11(void)
 
 /* Verify pool_name interfaces return errors as expected */
 #define T12_DESC       "pool_name error handling"
-void test12(void)
+static void test12(void)
 {
        int rc;
        struct llapi_layout *layout;
@@ -546,7 +557,7 @@ void test12(void)
 #define T13FILE                        "t13"
 #define T13_STRIPE_COUNT       2
 #define T13_DESC               "ost_index error handling"
-void test13(void)
+static void test13(void)
 {
        int rc;
        int fd;
@@ -611,7 +622,7 @@ void test13(void)
 
 /* Verify llapi_layout_file_create() returns errors as expected */
 #define T14_DESC       "llapi_layout_file_create error handling"
-void test14(void)
+static void test14(void)
 {
        int rc;
        struct llapi_layout *layout = llapi_layout_alloc();
@@ -628,7 +639,7 @@ void test14(void)
 #define T15FILE                        "t15"
 #define T15_STRIPE_COUNT       2
 #define T15_DESC       "Can't change striping attributes of existing file"
-void test15(void)
+static void test15(void)
 {
        int rc;
        int fd;
@@ -671,7 +682,7 @@ void test15(void)
 /* Default stripe attributes are applied as expected. */
 #define T16FILE                "t16"
 #define T16_DESC       "Default stripe attributes are applied as expected"
-void test16(void)
+static void test16(void)
 {
        int             rc;
        int             fd;
@@ -713,7 +724,7 @@ void test16(void)
        rc = llapi_layout_stripe_count_get(filelayout, &fcount);
        ASSERTF(rc == 0, "errno = %d", errno);
        ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT ||
-               dcount == LLAPI_LAYOUT_WIDE,
+               IN_RANGE(dcount, LLAPI_LAYOUT_WIDE_MIN, LLAPI_LAYOUT_WIDE_MAX),
                "%"PRIu64" != %"PRIu64, fcount, dcount);
 
        rc = llapi_layout_stripe_size_get(filelayout, &fsize);
@@ -736,7 +747,7 @@ void test16(void)
        rc = llapi_layout_stripe_size_get(filelayout, &fsize);
        ASSERTF(rc == 0, "errno = %d", errno);
        ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT ||
-               dcount == LLAPI_LAYOUT_WIDE,
+               IN_RANGE(dcount, LLAPI_LAYOUT_WIDE_MIN, LLAPI_LAYOUT_WIDE_MAX),
                "%"PRIu64" != %"PRIu64, fcount, dcount);
        ASSERTF(fsize == dsize, "%"PRIu64" != %"PRIu64, fsize, dsize);
 
@@ -747,7 +758,7 @@ void test16(void)
 /* Setting stripe count to LLAPI_LAYOUT_WIDE uses all available OSTs. */
 #define T17FILE                "t17"
 #define T17_DESC       "LLAPI_LAYOUT_WIDE is honored"
-void test17(void)
+static void test17(void)
 {
        int rc;
        int fd;
@@ -762,7 +773,7 @@ void test17(void)
        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, LLAPI_LAYOUT_WIDE);
+       rc = llapi_layout_stripe_count_set(layout, LLAPI_LAYOUT_WIDE_MIN);
        ASSERTF(rc == 0, "errno = %d", errno);
        fd = llapi_layout_file_create(path, 0, 0640, layout);
        ASSERTF(fd >= 0, "errno = %d", errno);
@@ -790,7 +801,7 @@ void test17(void)
 /* Setting pool with "fsname.pool" notation. */
 #define T18FILE                "t18"
 #define T18_DESC       "Setting pool with fsname.pool notation"
-void test18(void)
+static void test18(void)
 {
        int rc;
        int fd;
@@ -832,7 +843,7 @@ void test18(void)
 }
 
 #define T19_DESC       "Maximum length pool name is NULL-terminated"
-void test19(void)
+static void test19(void)
 {
        struct llapi_layout *layout;
        char *name = "0123456789abcde";
@@ -851,7 +862,7 @@ void test19(void)
 
 #define T20FILE                "t20"
 #define T20_DESC       "LLAPI_LAYOUT_DEFAULT is honored"
-void test20(void)
+static void test20(void)
 {
        int             rc;
        int             fd;
@@ -896,7 +907,7 @@ void test20(void)
        rc = llapi_layout_stripe_count_get(deflayout, &dcount);
        ASSERTF(rc == 0, "errno = %d", errno);
        ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT ||
-               dcount == LLAPI_LAYOUT_WIDE,
+               IN_RANGE(dcount, LLAPI_LAYOUT_WIDE_MIN, LLAPI_LAYOUT_WIDE_MAX),
                "%"PRIu64" != %"PRIu64, fcount, dcount);
 
        rc = llapi_layout_stripe_size_get(filelayout, &fsize);
@@ -910,7 +921,7 @@ void test20(void)
 }
 
 #define T21_DESC       "llapi_layout_file_create fails for non-Lustre file"
-void test21(void)
+static void test21(void)
 {
        struct llapi_layout *layout;
        char template[PATH_MAX];
@@ -936,7 +947,7 @@ void test21(void)
 
 #define T22FILE                "t22"
 #define T22_DESC       "llapi_layout_file_create applied mode correctly"
-void test22(void)
+static void test22(void)
 {
        int             rc;
        int             fd;
@@ -951,7 +962,7 @@ void test22(void)
        rc = unlink(path);
        ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno);
 
-       umask_orig = umask(S_IWGRP | S_IWOTH);
+       umask_orig = umask(0022);
 
        fd = llapi_layout_file_create(path, 0, mode_in, NULL);
        ASSERTF(fd >= 0, "errno = %d", errno);
@@ -969,7 +980,7 @@ void test22(void)
 }
 
 #define T23_DESC       "llapi_layout_get_by_path fails for non-Lustre file"
-void test23(void)
+static void test23(void)
 {
        struct llapi_layout *layout;
        char template[PATH_MAX];
@@ -991,10 +1002,11 @@ void test23(void)
 }
 
 /* llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED) returns expected layout
- * for file with unspecified layout. */
+ * for file with unspecified layout.
+ */
 #define T24FILE                "t24"
 #define T24_DESC       "LAYOUT_GET_EXPECTED works with existing file"
-void test24(void)
+static void test24(void)
 {
        int fd;
        int rc;
@@ -1032,10 +1044,11 @@ void test24(void)
 }
 
 /* llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED) returns expected layout
- * for directory with unspecified layout. */
+ * for directory with unspecified layout.
+ */
 #define T25DIR         "d25"
 #define T25_DESC       "LAYOUT_GET_EXPECTED works with directory"
-void test25(void)
+static void test25(void)
 {
        int rc;
        struct llapi_layout *layout;
@@ -1070,11 +1083,12 @@ void test25(void)
 }
 
 /* llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED) correctly combines
- * specified attributes of parent directory with attributes filesystem root. */
+ * specified attributes of parent directory with attributes filesystem root.
+ */
 #define T26DIR         "d26"
 #define T26_DESC       "LAYOUT_GET_EXPECTED partially specified parent"
 #define T26_STRIPE_SIZE        (1048576 * 4)
-void test26(void)
+static void test26(void)
 {
        int rc;
        struct llapi_layout *layout;
@@ -1083,7 +1097,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);
@@ -1118,11 +1132,12 @@ void test26(void)
 }
 
 /* llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED) work with
- * non existing file. */
+ * non existing file.
+ */
 #define T27DIR         "d27"
 #define T27_DESC       "LAYOUT_GET_EXPECTED with non existing file"
 #define T27_STRIPE_SIZE        (1048576 * 3)
-void test27(void)
+static void test27(void)
 {
        int rc;
        struct llapi_layout *layout;
@@ -1130,11 +1145,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);
@@ -1169,17 +1184,18 @@ void test27(void)
 }
 
 /* llapi_layout_stripe_count_get returns LLAPI_LAYOUT_WIDE for a directory
- * with a stripe_count of -1. */
+ * with a stripe_count of -1.
+ */
 #define T28DIR         "d28"
 #define T28_DESC       "LLAPI_LAYOUT_WIDE returned as expected"
-void test28(void)
+static void test28(void)
 {
        int rc;
        struct llapi_layout *layout;
        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);
 
@@ -1200,14 +1216,16 @@ void test28(void)
 
        rc = llapi_layout_stripe_count_get(layout, &count);
        ASSERTF(rc == 0, "errno = %d\n", errno);
-       ASSERTF(count == LLAPI_LAYOUT_WIDE, "count = %"PRIu64"\n", count);
+       ASSERTF((count >= LLAPI_LAYOUT_WIDE_MIN &&
+                count <= LLAPI_LAYOUT_WIDE_MAX),
+                "count = %"PRIu64"\n", count);
 
        llapi_layout_free(layout);
 }
 
 #define T29FILE                "f29"
 #define T29_DESC       "set ost index to non-zero stripe number"
-void test29(void)
+static void test29(void)
 {
        int rc, fd, i;
        uint64_t ost0, ost1, nost;
@@ -1320,7 +1338,7 @@ void test29(void)
 
 #define T30FILE                "f30"
 #define T30_DESC       "create composite file, traverse components"
-void test30(void)
+static void test30(void)
 {
        int rc, fd;
        uint64_t start[3], end[3];
@@ -1350,7 +1368,8 @@ void test30(void)
        ASSERTF(rc == 0, "errno %d", errno);
 
        /* add component without adjusting previous component's extent
-        * end will fail. */
+        * end will fail.
+        */
        rc = llapi_layout_comp_add(layout);
        ASSERTF(rc == -1 && errno == EINVAL, "rc %d, errno %d", rc, errno);
 
@@ -1361,8 +1380,10 @@ void test30(void)
        ASSERTF(rc == 0, "errno %d", errno);
 
        /* set non-contiguous extent will fail */
-       rc = llapi_layout_comp_extent_set(layout, end[0] * 2, end[1]);
-       ASSERTF(rc == -1 && errno == EINVAL, "rc %d, errno %d", rc, errno);
+       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);
@@ -1420,7 +1441,7 @@ void test30(void)
 
 #define T31FILE                "f31"
 #define T31_DESC       "add/delete component to/from existing file"
-void test31(void)
+static void test31(void)
 {
        int rc, fd, i;
        uint64_t start[2], end[2];
@@ -1529,7 +1550,210 @@ void test31(void)
                "s: %"PRIu64", e: %"PRIu64"", s, e);
 }
 
-#define TEST_DESC_LEN  50
+#define T32FILE                        "t32"
+#define T32_STRIPE_COUNT       (num_osts*2)
+#define T32_DESC               "Test overstriping with layout_file_create"
+static 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"
+static 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"
+static 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 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 0-len that 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];
@@ -1569,11 +1793,15 @@ static struct test_tbl_entry test_tbl[] = {
        { .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)
+static void print_test_desc(int test_num, const char *test_desc,
+                           const char *status)
 {
        int i;
 
@@ -1584,15 +1812,18 @@ void print_test_desc(int test_num, const char *test_desc, const char *status)
 }
 
 /* This function runs a single test by forking the process.  This way,
- * if there is a segfault during a test, the test program won't crash. */
-int test(void (*test_fn)(), const char *test_desc, bool test_skip, int test_num)
+ * if there is a segfault during a test, the test program won't crash.
+ */
+static int test(void (*test_fn)(), const char *test_desc, bool test_skip,
+               int test_num)
 {
        int rc = 0;
        pid_t pid;
        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;
        }
 
@@ -1619,7 +1850,8 @@ int test(void (*test_fn)(), const char *test_desc, bool test_skip, int test_num)
                print_test_desc(test_num, test_desc, status_buf);
        } else if (pid == 0) {
                /* Run the test in the child process.  Exit with 0 for success,
-                * non-zero for failure */
+                * non-zero for failure
+                */
                test_fn();
                exit(0);
        }
@@ -1647,11 +1879,34 @@ static void set_tests_skipped(char *str_tests)
        }
 }
 
+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:s:")) != -1) {
+       while ((c = getopt(argc, argv, "d:p:o:s:t:")) != -1) {
                switch (c) {
                case 'd':
                        lustre_dir = optarg;
@@ -1665,6 +1920,10 @@ static void process_args(int argc, char *argv[])
                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]);
@@ -1705,13 +1964,16 @@ int main(int argc, char *argv[])
        }
 
        /* Play nice with Lustre test scripts. Non-line buffered output
-        * stream under I/O redirection may appear incorrectly. */
+        * stream under I/O redirection may appear incorrectly.
+        */
        setvbuf(stdout, NULL, _IOLBF, 0);
 
        for (i = 0; i < NUM_TESTS; i++) {
                struct test_tbl_entry *tst = &test_tbl[i];
+
                if (test(tst->tte_fn, tst->tte_desc, tst->tte_skip, i) != 0)
                        rc++;
        }
+
        return rc;
 }