Whamcloud - gitweb
LU-16027 tests: sanity:test_66: specify blocksize explicitly
[fs/lustre-release.git] / lustre / tests / fsx.c
index 0d1b1d4..fde6abe 100644 (file)
@@ -75,6 +75,9 @@
 #include <libcfs/util/string.h>
 #include <setjmp.h>
 
+#include <linux/lustre/lustre_idl.h>
+#include <lustre/lustreapi.h>
+
 /*
  * Each test run will work with one or more separate file descriptors for the
  * same file.  This allows testing cache coherency across multiple mountpoints
@@ -116,6 +119,7 @@ int logcount; /* total ops */
 int jmpbuf_good;
 jmp_buf jmpbuf;
 
+unsigned int mirror_ids[LUSTRE_MIRROR_COUNT_MAX];
 /*
  * Define operations
  */
@@ -133,11 +137,22 @@ jmp_buf jmpbuf;
 #define OP_PUNCH_HOLE          6
 #define OP_ZERO_RANGE          7
 #define OP_CLOSEOPEN           8
-#define OP_MAX_FULL            9
+#define OP_MIRROR_OPS          9
+#define OP_MAX_FULL            10
+
+#define MIRROR_EXTEND 0
+#define MIRROR_SPLIT 1
+#define MIRROR_RESYNC 2
+#define MIRROR_OPS 3
+
+char *mirror_op_str[] = {
+       [MIRROR_EXTEND] = "MIRROR_EXTEND",
+       [MIRROR_SPLIT]  = "MIRROR_SPLIT",
+       [MIRROR_RESYNC] = "MIRROR_RESYNC",
+};
 
 #define OP_SKIPPED 101
-/* _GNU_SOURCE defines O_DIRECT as 14th bit which is 0x4000(16384) */
-#define OP_DIRECT  16384
+#define OP_DIRECT O_DIRECT
 
 #ifndef FALLOC_FL_PUNCH_HOLE
 #define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */
@@ -182,6 +197,7 @@ int truncbdy = 1;                   /* -t flag */
 int writebdy = 1;                      /* -w flag */
 long monitorstart = -1;                        /* -m flag */
 long monitorend = -1;                  /* -m flag */
+long flrmode;                          /* -M flag */
 int lite;                              /* -L flag */
 long numops = -1;                      /* -N flag */
 int randomoplen = 1;                   /* -O flag disables it */
@@ -359,15 +375,15 @@ logdump(void)
                        break;
                case OP_TRUNCATE:
                        down = lp->args[0] < lp->args[1];
-                       prt("TRUNCATE %s\tfrom 0x%05x to 0x%05x",
-                           down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
+                       prt("TRUNC%s 0x%05x to 0x%05x",
+                           down ? "_DN" : "_UP", lp->args[1], lp->args[0]);
                        if (badoff >= lp->args[!down] &&
                            badoff < lp->args[!!down])
-                               prt("\t******WWWW");
+                               prt("\t******TTTT");
                        break;
                case OP_FALLOCATE:
                        /* 0: offset 1: length 2: where alloced */
-                       prt("FALLOC  \tfrom 0x%05x to 0x%05x\t(0x%05x bytes)%s",
+                       prt("FALLOC   0x%05x thru 0x%05x\t(0x%05x bytes)%s",
                            lp->args[0], lp->args[0] + lp->args[1],
                            lp->args[1], falloc_type[lp->args[2]]);
                        if (badoff >= lp->args[0] &&
@@ -395,6 +411,17 @@ logdump(void)
                        prt("CLOSE/OPEN%s",
                            lp->operation & OP_DIRECT ? "_OD" : "   ");
                        break;
+               case OP_MIRROR_OPS: {
+                       prt("%s ", mirror_op_str[lp->args[0]]);
+                       if (lp->args[0] == MIRROR_EXTEND)
+                               prt("to %d mirrors", lp->args[1] + 1);
+                       else if (lp->args[0] == MIRROR_SPLIT)
+                               prt("mirror %d to %d mirrors", lp->args[2],
+                                   lp->args[1] - 1);
+                       else if (lp->args[0] == MIRROR_RESYNC)
+                               prt("%d mirrors", lp->args[1]);
+                       break;
+               }
                case OP_SKIPPED:
                        prt("SKIPPED (no operation)");
                        break;
@@ -454,6 +481,7 @@ void
 report_failure(int status)
 {
        logdump();
+       prt("Using seed %d\n", seed);
 
        if (fsxgoodfd) {
                if (good_buf) {
@@ -583,9 +611,7 @@ open_test_files(char **argv, int argc)
 
        for (i = 0, tf = test_files; i < num_test_files; i++, tf++) {
                tf->path = argv[i];
-#ifdef O_DIRECT
                tf->o_direct = (random() % (o_direct + 1)) ? OP_DIRECT : 0;
-#endif
                tf->fd = open(tf->path,
                              O_RDWR | (lite ? 0 : O_CREAT | O_TRUNC) |
                              tf->o_direct, 0666);
@@ -690,13 +716,37 @@ output_line(struct test_file *tf, int op, unsigned int offset,
            (monitorend == -1 || offset <= monitorend)))))))
                return;
 
-       prt("%06lu%s %lu.%06u %-10s %#08x %s %#08x\t(0x0%x bytes)\n",
+       prt("%06lu%s %lu.%06u %-10s %#08x %s %#08x\t(0x%x bytes)\n",
            testcalls, fill_tf_buf(tf), tv.tv_sec, (int)tv.tv_usec,
            ops[op], offset, op == OP_TRUNCATE || op == OP_PUNCH_HOLE ?
            " to " : "thru", offset + size - 1,
             (int)size < 0 ? -(int)size : size);
 }
 
+void
+mirror_output_line(struct test_file *tf, int op, int mirrors, int id)
+{
+       if (!(!quiet &&
+             ((progressinterval && testcalls % progressinterval == 0) ||
+              (debug && (monitorstart == -1)))))
+               return;
+
+       prt("%06lu %lu.%06u %-10s ",
+           testcalls, tv.tv_sec, (int)tv.tv_usec, mirror_op_str[op]);
+
+       switch (op) {
+       case MIRROR_EXTEND:
+               prt("to %d mirrors\n", mirrors + 1);
+               break;
+       case MIRROR_SPLIT:
+               prt("mirror %d to %d mirrors\n", id, mirrors - 1);
+               break;
+       case MIRROR_RESYNC:
+               prt("%d mirrors\n", mirrors);
+               break;
+       }
+}
+
 void output_debug(unsigned int offset, unsigned int size, const char *what)
 {
        struct timeval t;
@@ -1255,9 +1305,7 @@ docloseopen(void)
                return;
 
        tf = get_tf();
-#ifdef O_DIRECT
        direct = (random() % (o_direct + 1)) ? OP_DIRECT : 0;
-#endif
        log4(OP_CLOSEOPEN + direct, file_size, (unsigned int)file_size, 0);
 
        if (fd_policy != FD_SINGLE)
@@ -1280,6 +1328,162 @@ docloseopen(void)
                     tf->o_direct ? "open(O_DIRECT) done" : "open done");
 }
 
+static int
+get_mirror_ids(int fd, unsigned int *ids)
+{
+       struct llapi_layout *layout;
+       uint16_t count;
+       int rc;
+
+       layout = llapi_layout_get_by_fd(fd, 0);
+       if (layout == NULL)
+               return 0;
+
+       /* only get mirror count */
+       rc = llapi_layout_mirror_count_get(layout, &count);
+       if (rc < 0)
+               prt("llapi_layout_mirror_count_get: %d\n", rc);
+       if (count == 0)
+               return 0;
+
+       count = 0;
+
+       rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
+       if (rc < 0) {
+               prt("llapi_layout_comp_use(USE_FIRST): %d\n", rc);
+               goto free;
+       }
+
+       do {
+               unsigned int id;
+
+               rc = llapi_layout_mirror_id_get(layout, &id);
+               if (rc < 0) {
+                       prt("llapi_layout_mirror_id_get: %d\n", rc);
+                       goto free;
+               }
+
+               if (!count || ids[count - 1] != id)
+                       ids[count++] = id;
+
+               rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
+               if (rc < 0) {
+                       prt("llapi_layout_comp_use(USE_NEXT): %d\n", rc);
+                       goto free;
+               }
+       } while (rc == 0);
+
+free:
+       llapi_layout_free(layout);
+
+       return rc < 0 ? rc : count;
+}
+
+void
+do_mirror_ops(int op)
+{
+       int mirror_count;
+       char cmd[PATH_MAX * 2];
+       int i = 0;
+       int rc;
+
+       if (testcalls <= simulatedopcount)
+               return;
+
+       tf = get_tf();
+
+       mirror_count = get_mirror_ids(tf->fd, mirror_ids);
+       if (mirror_count < 0) {
+               prterr("get_mirror_ids");
+               report_failure(182);
+       }
+
+       switch (op) {
+       case MIRROR_EXTEND:
+               if (mirror_count == LUSTRE_MIRROR_COUNT_MAX)
+                       return;
+               snprintf(cmd, sizeof(cmd), "lfs mirror extend -N -c-1 %s",
+                        tf->path);
+               break;
+       case MIRROR_SPLIT:
+               if (mirror_count == 0 || mirror_count == 1)
+                       return;
+
+               i = random() % mirror_count;
+               if (i == 0)
+                       i++;
+
+               snprintf(cmd, sizeof(cmd),
+                        "lfs mirror split -d --mirror-id=%d %s",
+                        mirror_ids[i], tf->path);
+               break;
+       case MIRROR_RESYNC:
+               if (mirror_count < 2)
+                       return;
+
+               snprintf(cmd, sizeof(cmd),
+                        "lfs mirror resync %s", tf->path);
+               break;
+       }
+
+       if (close(tf->fd))
+               report_failure(183);
+       output_debug(monitorstart, 0, "close done");
+
+       log4(OP_MIRROR_OPS, op, mirror_count, i);
+
+       mirror_output_line(tf, op, mirror_count, i);
+
+       rc = system(cmd);
+       if (rc < 0) {
+               prt("%s: %d\n", cmd, errno);
+               report_failure(184);
+       } else if (WIFEXITED(rc)) {
+               rc = WEXITSTATUS(rc);
+               if (rc > 0) {
+                       prt("%s: %d\n", cmd, rc);
+                       report_failure(184);
+               }
+       }
+       output_debug(monitorstart, 0, cmd);
+
+       switch (op) {
+       case MIRROR_SPLIT:
+               if (mirror_count == 2)
+                       break;
+       case MIRROR_EXTEND:
+       case MIRROR_RESYNC:
+               /* verify mirror */
+               snprintf(cmd, sizeof(cmd),
+                        "lfs mirror verify %s", tf->path);
+
+               rc = system(cmd);
+               if (rc < 0) {
+                       prt("%s: %d\n", cmd, errno);
+                       report_failure(184);
+               } else if (WIFEXITED(rc)) {
+                       rc = WEXITSTATUS(rc);
+                       if (rc > 0) {
+                               prt("%s: %d\n", cmd, rc);
+                               snprintf(cmd, sizeof(cmd),
+                                        "lfs mirror verify -v %s", tf->path);
+                               rc = system(cmd);
+                               report_failure(184);
+                       }
+               }
+       }
+
+       output_debug(monitorstart, 0, cmd);
+
+       tf->fd = open(tf->path, O_RDWR | tf->o_direct, 0);
+       if (tf->fd < 0) {
+               prterr(tf->o_direct ? "open(O_DIRECT)" : "open");
+               report_failure(185);
+       }
+       output_debug(monitorstart, 0,
+                    tf->o_direct ? "open(O_DIRECT) done" : "open done");
+}
+
 #define TRIM_OFF_LEN(off, len, size)   \
 do {                                   \
        if (size)                       \
@@ -1390,6 +1594,10 @@ test(void)
                if (closeopen)
                        docloseopen();
                break;
+       case OP_MIRROR_OPS:
+               if (flrmode)
+                       do_mirror_ops(random() % MIRROR_OPS);
+               break;
        default:
                prterr("unknown operation %d: Operation not supported");
                report_failure(42);
@@ -1467,7 +1675,7 @@ usage(void)
 "          order with 'rotate' or chose them at 'random'.  (default random)\n"
 "      -L: fsxLite - no file creations & no file size changes\n"
 /* OSX: -I: start interactive mode since operation opnum\n\ */
-/* OSX: -M: slow motion mode, wait 1 second before each op\n\ */
+"      -M: mirror file test mode\n"
 "      -N numops: total # operations to do (default infinity)\n"
 "      -O: use oplen (see -o flag) for every op (default random)\n"
 "      -P: save .fsxlog and .fsxgood files in dirpath (default ./)\n"
@@ -1475,9 +1683,7 @@ usage(void)
 "      -S seed: for random # generator (default 1) 0 gets timestamp\n"
 /* OSX: -T datasize: atomic data element write size [1,2,4] (default 4)\n\ */
 "      -W: mapped write operations DISabled\n"
-#ifdef O_DIRECT
 "      -Z[P]: O_DIRECT file IO [1 in P chance for each open] (default off)\n"
-#endif
 "      fname: this filename is REQUIRED (no default)\n",
        page_size);
        exit(90);
@@ -1557,7 +1763,7 @@ main(int argc, char **argv)
        setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
 
        while ((ch = getopt(argc, argv,
-                           "b:c:dfl:m:no:p:qr:s:t:w:xyzD:FHI:LN:OP:RS:WZ::"))
+                           "b:c:dfl:m:no:p:qr:s:t:w:xyzD:FHI:LMN:OP:RS:WZ::"))
               != EOF)
                switch (ch) {
                case 'b':
@@ -1660,6 +1866,9 @@ main(int argc, char **argv)
                case 'L':
                        lite = 1;
                        break;
+               case 'M':
+                       flrmode = 1;
+                       break;
                case 'N':
                        numops = getnum(optarg, &endp);
                        if (numops < 0)
@@ -1693,12 +1902,10 @@ main(int argc, char **argv)
                                fprintf(stdout, "mapped writes DISABLED\n");
                        break;
                case 'Z':
-#ifdef O_DIRECT
                        if (optarg)
                                o_direct = getnum(optarg, &endp);
                        if (!optarg || o_direct == 0)
                                o_direct = 1;
-#endif
                        break;
                default:
                        usage();