Whamcloud - gitweb
LU-12488 tests: Fix sanityn 93 for DNE configs
[fs/lustre-release.git] / lustre / tests / fsx.c
index af93599..71711ab 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
  *
+ * Copyright (c) 2012, Intel Corporation.
+ *
  * @APPLE_LICENSE_HEADER_START@
  *
  * The contents of this file constitute Original Code as defined in and
@@ -33,7 +35,6 @@
  *     Sundry porting patches from Guy Harris 12/2001
  * $FreeBSD: src/tools/regression/fsx/fsx.c,v 1.1 2001/12/20 04:15:57 jkh Exp $
  */
-
 #include <sys/types.h>
 #include <sys/stat.h>
 #if defined(_UWIN) || defined(__linux__)
 #define NUMPRINTCOLUMNS 32     /* # columns of data to print on each line */
 
 /*
+ * Each test run will work with one or more separate file descriptors for the
+ * same file.  This allows testing cache coherency across multiple mountpoints
+ * of the same network filesystem on a single client.
+ */
+struct test_file {
+       char *path;
+       int fd;
+} *test_files = NULL;
+
+int num_test_files;
+enum fd_iteration_policy {
+       FD_SINGLE,
+       FD_ROTATE,
+       FD_RANDOM,
+};
+int fd_policy = FD_RANDOM;
+int fd_last;
+
+/*
  *     A log entry is an operation and a bunch of arguments.
  */
 
 struct log_entry {
-       int     operation;
-       struct timeval tv;
-       int     args[3];
+       int                     operation;
+       int                     args[3];
+       struct timeval          tv;
+       const struct test_file  *tf;
 };
 
 #define        LOGSIZE 100000
@@ -94,23 +115,23 @@ char       *original_buf;                  /* a pointer to the original data */
 char   *good_buf;                      /* a pointer to the correct data */
 char   *temp_buf;                      /* a pointer to the current data */
 char   *fname;                         /* name of our test file */
-char   logfile[1024];                  /* name of our log file */
-char   goodfile[1024];                 /* name of our test file */
+char   logfile[PATH_MAX];              /* name of our log file */
+char   goodfile[PATH_MAX];             /* name of our test file */
 
 off_t          file_size = 0;
 off_t          biggest = 0;
 char           state[256];
 unsigned long  testcalls = 0;          /* calls to function "test" */
 
-unsigned long  simulatedopcount = 0;   /* -b flag */
+long   simulatedopcount = 0;           /* -b flag */
 int    closeprob = 0;                  /* -c flag */
 int    debug = 0;                      /* -d flag */
-unsigned long  debugstart = 0;         /* -D flag */
-unsigned long  maxfilelen = 256 * 1024;        /* -l flag */
+long   debugstart = 0;                 /* -D flag */
+long   maxfilelen = 256 * 1024;        /* -l flag */
 int    sizechecks = 1;                 /* -n flag disables them */
 int    maxoplen = 64 * 1024;           /* -o flag */
 int    quiet = 0;                      /* -q flag */
-unsigned long progressinterval = 0;    /* -p flag */
+long   progressinterval = 0;           /* -p flag */
 int    readbdy = 1;                    /* -r flag */
 int    style = 0;                      /* -s flag */
 int    truncbdy = 1;                   /* -t flag */
@@ -122,12 +143,12 @@ long      numops = -1;                    /* -N flag */
 int    randomoplen = 1;                /* -O flag disables it */
 int    seed = 1;                       /* -S flag */
 int     mapped_writes = 1;              /* -W flag disables */
-int    mapped_reads = 1;               /* -R flag disables it */
+int    mapped_reads = 1;               /* -R flag disables it */
 int    fsxgoodfd = 0;
+int    o_direct;                       /* -Z */
 FILE * fsxlogf = NULL;
 int badoff = -1;
 
-
 void
 vwarnc(code, fmt, ap)
        int code;
@@ -178,22 +199,42 @@ prterr(char *prefix)
 
 
 void
-log4(int operation, int arg0, int arg1, int arg2, struct timeval *tv)
+log4(int operation, int arg0, int arg1, int arg2, struct timeval *tv,
+       const struct test_file *tf)
 {
        struct log_entry *le;
 
        le = &oplog[logptr];
-       le->tv = *tv;
        le->operation = operation;
        le->args[0] = arg0;
        le->args[1] = arg1;
        le->args[2] = arg2;
+       le->tv = *tv;
+       le->tf = tf;
        logptr++;
        logcount++;
        if (logptr >= LOGSIZE)
                logptr = 0;
 }
 
+const char *
+fill_tf_buf(const struct test_file *tf)
+{
+       static int max_tf_len;
+       static char tf_buf[32];
+
+       if (fd_policy == FD_SINGLE)
+               return "";
+
+       if (max_tf_len == 0)
+               max_tf_len = snprintf(tf_buf, sizeof(tf_buf) - 1,
+                                     "%u", num_test_files - 1);
+
+       sprintf(tf_buf, "[%0*lu]", max_tf_len,
+               (unsigned long)(tf - test_files));
+
+       return tf_buf;
+}
 
 void
 logdump(void)
@@ -214,7 +255,7 @@ logdump(void)
 
                opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
                lp = &oplog[i];
-               prt("%d: %lu.%06lu ", opnum,
+               prt("%d%s: %lu.%06lu ", opnum, fill_tf_buf(lp->tf),
                    lp->tv.tv_sec, lp->tv.tv_usec);
 
                switch (lp->operation) {
@@ -388,20 +429,6 @@ check_buffers(unsigned offset, unsigned size)
        }
 }
 
-struct test_file {
-       char *path;
-       int fd;
-} *test_files = NULL;
-
-int num_test_files = 0;
-enum fd_iteration_policy {
-       FD_SINGLE,
-       FD_ROTATE,
-       FD_RANDOM,
-};
-int fd_policy = FD_RANDOM;
-int fd_last = 0;
-
 struct test_file *
 get_tf(void)
 {
@@ -471,8 +498,8 @@ open_test_files(char **argv, int argc)
        for (i = 0, tf = test_files; i < num_test_files; i++, tf++) {
 
                tf->path = argv[i];
-               tf->fd = open(tf->path, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC),
-                               0666);
+               tf->fd = open(tf->path, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC)|
+                               o_direct, 0666);
                if (tf->fd < 0) {
                        prterr(tf->path);
                        exit(91);
@@ -529,8 +556,15 @@ check_trunc_hack(void)
        struct stat statbuf;
        int fd = get_fd();
 
-       ftruncate(fd, (off_t)0);
-       ftruncate(fd, (off_t)100000);
+        /* should not ignore ftruncate(2)'s return value */
+        if (ftruncate(fd, (off_t)0) < 0) {
+                prterr("trunc_hack: ftruncate(0)");
+                exit(1);
+        }
+        if (ftruncate(fd, (off_t)100000) < 0) {
+                prterr("trunc_hack: ftruncate(100000)");
+                exit(1);
+        }
        if (fstat(fd, &statbuf)) {
                prterr("trunc_hack: fstat");
                statbuf.st_size = -1;
@@ -539,58 +573,16 @@ check_trunc_hack(void)
                prt("no extend on truncate! not posix!\n");
                exit(130);
        }
-       ftruncate(fd, 0);
-}
-
-static char *tf_buf = NULL;
-static int max_tf_len = 0;
-
-void
-alloc_tf_buf(void)
-{
-       char dummy = '\0';
-       int highest = num_test_files - 1;
-       int len;
-
-       len = snprintf(&dummy, 0, "%u ", highest);
-       if (len < 1) {
-               prterr("finding max tf_buf");
-               exit(1);
-       }
-       len++;
-       tf_buf = malloc(len);
-       if (tf_buf == NULL) {
-               prterr("allocating tf_buf");
-               exit(1);
-       }
-       max_tf_len = snprintf(tf_buf, len, "%u ", highest);
-       if (max_tf_len < 1) {
-               prterr("fiding max_tv_len\n");
-               exit(1);
-       }
-       if (max_tf_len != len - 1) {
-               warn("snprintf() gave %d instead of %d?\n",
-                               max_tf_len, len - 1);
-               exit(1);
-       }
-}
-
-char *
-fill_tf_buf(struct test_file *tf)
-{
-       if (tf_buf == NULL)
-               alloc_tf_buf();
-
-       sprintf(tf_buf,"%lu ", (unsigned long)(tf - test_files));
-       return tf_buf;
+        if (ftruncate(fd, 0) < 0) {
+                prterr("trunc_hack: ftruncate(0) (2nd call)");
+                exit(1);
+        }
 }
 
 void
 output_line(struct test_file *tf, int op, unsigned offset,
                unsigned size, struct timeval *tv)
 {
-       char *tf_num = "";
-
        char *ops[] = {
                [OP_READ] = "read",
                [OP_WRITE] = "write",
@@ -599,9 +591,6 @@ output_line(struct test_file *tf, int op, unsigned offset,
                [OP_MAPWRITE] = "mapwrite",
        };
 
-       if (fd_policy != FD_SINGLE)
-               tf_num = fill_tf_buf(tf);
-
        /* W. */
        if (!(!quiet && ((progressinterval &&
                        testcalls % progressinterval == 0) ||
@@ -611,9 +600,9 @@ output_line(struct test_file *tf, int op, unsigned offset,
                          (monitorend == -1 || offset <= monitorend)))))))
                return;
 
-       prt("%06lu %lu.%06lu %.*s%-10s %#08x %s %#08x\t(0x%x bytes)\n",
-               testcalls, tv->tv_sec, tv->tv_usec, max_tf_len,
-               tf_num, ops[op],
+       prt("%06lu%s %lu.%06lu %-10s %#08x %s %#08x\t(0x%x bytes)\n",
+               testcalls, fill_tf_buf(tf), tv->tv_sec, tv->tv_usec,
+               ops[op],
                offset, op == OP_TRUNCATE ? " to " : "thru",
                offset + size - 1, size);
 }
@@ -628,21 +617,23 @@ doread(unsigned offset, unsigned size)
        int fd = tf->fd;
 
        offset -= offset % readbdy;
+       if (o_direct)
+               size -= size % readbdy;
        gettimeofday(&t, NULL);
        if (size == 0) {
-               if (!quiet && testcalls > simulatedopcount)
+               if (!quiet && testcalls > simulatedopcount && !o_direct)
                        prt("skipping zero size read\n");
-               log4(OP_SKIPPED, OP_READ, offset, size, &t);
+               log4(OP_SKIPPED, OP_READ, offset, size, &t, tf);
                return;
        }
        if (size + offset > file_size) {
                if (!quiet && testcalls > simulatedopcount)
                        prt("skipping seek/read past end of file\n");
-               log4(OP_SKIPPED, OP_READ, offset, size, &t);
+               log4(OP_SKIPPED, OP_READ, offset, size, &t, tf);
                return;
        }
 
-       log4(OP_READ, offset, size, 0, &t);
+       log4(OP_READ, offset, size, 0, &t, tf);
 
        if (testcalls <= simulatedopcount)
                return;
@@ -689,17 +680,17 @@ domapread(unsigned offset, unsigned size)
        if (size == 0) {
                if (!quiet && testcalls > simulatedopcount)
                        prt("skipping zero size read\n");
-               log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t);
+               log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t, tf);
                return;
        }
        if (size + offset > file_size) {
                if (!quiet && testcalls > simulatedopcount)
                        prt("skipping seek/read past end of file\n");
-               log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t);
+               log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t, tf);
                return;
        }
 
-       log4(OP_MAPREAD, offset, size, 0, &t);
+       log4(OP_MAPREAD, offset, size, 0, &t, tf);
 
        if (testcalls <= simulatedopcount)
                return;
@@ -767,15 +758,17 @@ dowrite(unsigned offset, unsigned size)
        int fd = tf->fd;
 
        offset -= offset % writebdy;
+       if (o_direct)
+               size -= size % writebdy;
        gettimeofday(&t, NULL);
        if (size == 0) {
-               if (!quiet && testcalls > simulatedopcount)
+               if (!quiet && testcalls > simulatedopcount && !o_direct)
                        prt("skipping zero size write\n");
-               log4(OP_SKIPPED, OP_WRITE, offset, size, &t);
+               log4(OP_SKIPPED, OP_WRITE, offset, size, &t, tf);
                return;
        }
 
-       log4(OP_WRITE, offset, size, file_size, &t);
+       log4(OP_WRITE, offset, size, file_size, &t, tf);
 
        gendata(original_buf, good_buf, offset, size);
        if (file_size < offset + size) {
@@ -833,12 +826,12 @@ domapwrite(unsigned offset, unsigned size)
        if (size == 0) {
                if (!quiet && testcalls > simulatedopcount)
                        prt("skipping zero size write\n");
-               log4(OP_SKIPPED, OP_MAPWRITE, offset, size, &t);
+               log4(OP_SKIPPED, OP_MAPWRITE, offset, size, &t, tf);
                return;
        }
        cur_filesize = file_size;
 
-       log4(OP_MAPWRITE, offset, size, 0, &t);
+       log4(OP_MAPWRITE, offset, size, 0, &t, tf);
 
        gendata(original_buf, good_buf, offset, size);
        if (file_size < offset + size) {
@@ -933,7 +926,7 @@ dotruncate(unsigned size)
                        prt("truncating to largest ever: 0x%x\n", size);
        }
 
-       log4(OP_TRUNCATE, size, (unsigned)file_size, 0, &t);
+       log4(OP_TRUNCATE, size, (unsigned)file_size, 0, &t, tf);
 
        if (size > file_size)
                memset(good_buf + file_size, '\0', size - file_size);
@@ -994,7 +987,7 @@ docloseopen(void)
                return;
 
        gettimeofday(&t, NULL);
-       log4(OP_CLOSEOPEN, file_size, (unsigned)file_size, 0, &t);
+       log4(OP_CLOSEOPEN, file_size, (unsigned)file_size, 0, &t, tf);
 
        if (debug)
                prt("%06lu %lu.%06lu close/open\n", testcalls, t.tv_sec,
@@ -1007,7 +1000,7 @@ docloseopen(void)
                gettimeofday(&t, NULL);
                prt("       %lu.%06lu close done\n", t.tv_sec, t.tv_usec);
        }
-       tf->fd = open(tf->path, O_RDWR, 0);
+       tf->fd = open(tf->path, O_RDWR|o_direct, 0);
        if (tf->fd < 0) {
                prterr("docloseopen: open");
                report_failure(181);
@@ -1128,10 +1121,11 @@ usage(void)
 "      -P: save .fsxlog and .fsxgood files in dirpath (default ./)\n"
 "      -S seed: for random # generator (default 1) 0 gets timestamp\n"
 "      -W: mapped write operations DISabled\n"
-"        -R: read() system calls only (mapped reads disabled)\n"
-"      -I: When multiple paths to the file are given each operation uses"
-"           a different path.  Iterate through them in order with 'rotate'"
-"           or chose then at 'random'.  (defaults to random)\n"
+"      -R: read() system calls only (mapped reads disabled)\n"
+"      -Z: O_DIRECT (use -R, -W, -r and -w too)\n"
+"      -I: When multiple paths to the file are given each operation uses\n"
+"          a different path.  Iterate through them in order with 'rotate'\n"
+"          or chose then at 'random'.  (defaults to random)\n"
 "      fname: this filename is REQUIRED (no default)\n");
        exit(90);
 }
@@ -1186,7 +1180,7 @@ main(int argc, char **argv)
        setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
 
        while ((ch = getopt(argc, argv,
-                               "b:c:dl:m:no:p:qr:s:t:w:D:I:LN:OP:RS:W"))
+                               "b:c:dl:m:no:p:qr:s:t:w:D:I:LN:OP:RS:WZ"))
               != EOF)
                switch (ch) {
                case 'b':
@@ -1284,9 +1278,9 @@ main(int argc, char **argv)
                        randomoplen = 0;
                        break;
                case 'P':
-                       strncpy(goodfile, optarg, sizeof(goodfile));
+                       strncpy(goodfile, optarg, sizeof(goodfile) - 1);
                        strcat(goodfile, "/");
-                       strncpy(logfile, optarg, sizeof(logfile));
+                       strncpy(logfile, optarg, sizeof(logfile) - 1);
                        strcat(logfile, "/");
                        dirpath = 1;
                        break;
@@ -1307,6 +1301,9 @@ main(int argc, char **argv)
                        if (!quiet)
                                fprintf(stdout, "mapped writes DISABLED\n");
                        break;
+               case 'Z':
+                       o_direct = O_DIRECT;
+                       break;
 
                default:
                        usage();
@@ -1367,10 +1364,36 @@ main(int argc, char **argv)
        original_buf = (char *) malloc(maxfilelen);
        for (i = 0; i < maxfilelen; i++)
                original_buf[i] = random() % 256;
-       good_buf = (char *) malloc(maxfilelen);
-       memset(good_buf, '\0', maxfilelen);
-       temp_buf = (char *) malloc(maxoplen);
-       memset(temp_buf, '\0', maxoplen);
+       if (o_direct) {
+               int ret;
+
+               ret = posix_memalign((void **)&good_buf, writebdy, maxfilelen);
+               if (ret) {
+                       prt("main: posix_memalign failed: %s\n", strerror(ret));
+                       exit(96);
+               }
+
+               ret = posix_memalign((void **)&temp_buf, readbdy, maxoplen);
+               if (ret) {
+                       prt("main: posix_memalign failed: %s\n", strerror(ret));
+                       exit(97);
+               }
+       } else {
+               good_buf = malloc(maxfilelen);
+               if (!good_buf) {
+                       prt("malloc failed.\n");
+                       exit(98);
+               }
+
+               temp_buf = malloc(maxoplen);
+               if (!temp_buf) {
+                       prt("malloc failed.\n");
+                       exit(99);
+               }
+       }
+       memset(good_buf, 0, maxfilelen);
+       memset(temp_buf, 0, maxoplen);
+
        if (lite) {     /* zero entire existing file */
                ssize_t written;
                int fd = get_fd();