fstests: Replace all __[u]intNN_t types with standard [u]intNN_t
[xfstests-dev.git] / src / randholes.c
index 8fcf78bddf0a97b16dcb9b727fa95f695bad9b08..a16670f06547be59bca9e4bdf068d3653f635590 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2003, 2010 SGI
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
 
 #include "global.h"
 
-unsigned char  *valid; /* Bit-vector array showing which blocks have been written */
-int            nvalid; /* number of bytes in valid array */
-#define        SETBIT(ARRAY, N)        ((ARRAY)[(N)/8] |= (1 << ((N)%8)))
-#define        BITVAL(ARRAY, N)        ((ARRAY)[(N)/8] & (1 << ((N)%8)))
-
 #define        power_of_2(x)   ((x) && !((x) & ((x) - 1)))
-#define        DEFAULT_FILESIZE        ((__uint64_t) (256 * 1024 * 1024))
+#define        DEFAULT_FILESIZE        ((uint64_t) (256 * 1024 * 1024))
 #define        DEFAULT_BLOCKSIZE       512
 
-__uint64_t filesize;
+#define        SETBIT(ARRAY, N)        ((ARRAY)[(N)/8] |= (1 << ((N)%8)))
+#define        BITVAL(ARRAY, N)        ((ARRAY)[(N)/8] & (1 << ((N)%8)))
 
-unsigned int blocksize;
-int count;
-int verbose;
-int wsync;
-int direct;
-int alloconly;
-int rt;
-int extsize;   /* used only for real-time */
-int preserve;
-int test;
-__uint64_t fileoffset;
+/* Bit-vector array showing which blocks have been written */
+static unsigned char   *valid;
 
-struct fsxattr rtattr;
+static uint64_t filesize;
+static uint64_t fileoffset;
 
-#define        READ_XFER       10      /* block to read at a time when checking */
+static unsigned int blocksize;
+static int count;
+static int verbose;
+static int wsync;
+static int direct;
+static int alloconly;
+static int rt;
+static int extsize;    /* used only for real-time */
+static int preserve;
+static int test;
+
+#define        READ_XFER       256     /* blocks to read at a time when checking */
 
 /*
  * Define xfscntl() to mask the difference between the Linux
@@ -55,15 +54,10 @@ struct fsxattr rtattr;
  * F_FSGETXATTR (Irix).
  *
  */
-#ifdef __sgi__ /* Irix */
-#  define xfscntl(filename, fd, cmd, arg) \
-               fcntl((fd), F_ ## cmd, (arg))
-#else  /* ! __sgi__ */
 #  define xfscntl(filename, fd, cmd, arg) \
                xfsctl((filename), (fd), XFS_IOC_ ## cmd, (arg))
-#endif /* ! __sgi__ */
 
-void
+static void
 usage(char *progname)
 {
        fprintf(stderr,
@@ -78,61 +72,149 @@ usage(char *progname)
        fprintf(stderr, "\tdefault count is %d block-sized writes\n",
                (int) (DEFAULT_FILESIZE / DEFAULT_BLOCKSIZE));
        fprintf(stderr, "\tdefault write_offset is %" PRIu64 " bytes\n",
-               (__uint64_t) 0);
+               (uint64_t) 0);
        exit(1);
 }
 
-int
+/* Returns filename if successful or a null pointer if an error occurs */
+static char *
+parseargs(int argc, char *argv[])
+{
+       int seed;
+       int ch;
+
+       filesize = DEFAULT_FILESIZE;
+       blocksize = DEFAULT_BLOCKSIZE;
+       count = (int) filesize / blocksize;
+       verbose = 0;
+       wsync = 0;
+       seed = time(NULL);
+       test = 0;
+       while ((ch = getopt(argc, argv, "b:l:s:c:o:x:vwdrapt")) != EOF) {
+               switch(ch) {
+               case 'b':       blocksize  = atoi(optarg);      break;
+               case 'l':       filesize   = strtoull(optarg, NULL, 16); break;
+               case 's':       seed       = atoi(optarg);      break;
+               case 'c':       count      = atoi(optarg);      break;
+               case 'o':       fileoffset = strtoull(optarg, NULL, 16); break;
+               case 'x':       extsize    = atoi(optarg);      break;
+               case 'v':       verbose++;                      break;
+               case 'w':       wsync++;                        break;
+               case 'd':       direct++;                       break;
+               case 'r':       rt++; direct++;                 break;
+               case 'a':       alloconly++;                    break;
+               case 'p':       preserve++;                     break;
+               case 't':       test++; preserve++;             break;
+               default:        usage(argv[0]);                 break;
+               }
+       }
+       if (optind != argc - 1)
+               usage(argv[0]);
+
+       if ((filesize % blocksize) != 0) {
+               filesize -= filesize % blocksize;
+               printf("filesize not a multiple of blocksize, "
+                       "reducing filesize to %llu\n",
+                      (unsigned long long) filesize);
+       }
+       if ((fileoffset % blocksize) != 0) {
+               fileoffset -= fileoffset % blocksize;
+               printf("fileoffset not a multiple of blocksize, "
+                       "reducing fileoffset to %llu\n",
+                      (unsigned long long) fileoffset);
+       }
+       if (count > (filesize/blocksize)) {
+               count = (filesize/blocksize);
+               printf("count of blocks written is too large, "
+                       "setting to %d\n", count);
+       } else if (count < 1) {
+               count = 1;
+               printf("count of blocks written is too small, "
+                       "setting to %d\n", count);
+       }
+       printf("randholes: Seed = %d (use \"-s %d\" "
+               "to re-execute this test)\n", seed, seed);
+       srandom(seed);
+
+        printf("randholes: blocksize=%d, filesize=%llu, seed=%d\n"
+               "randholes: count=%d, offset=%llu, extsize=%d\n",
+                blocksize, (unsigned long long)filesize, seed,
+              count, (unsigned long long)fileoffset, extsize);
+        printf("randholes: verbose=%d, wsync=%d, direct=%d, "
+               "rt=%d, alloconly=%d, preserve=%d, test=%d\n",
+                verbose, wsync, direct ? 1 : 0, rt, alloconly, preserve, test);
+
+       /* Last argument is the file name.  Return it. */
+
+       return argv[optind];    /* Success */
+}
+
+/*
+ * Determine the next random block number to which to write.
+ * If an already-written block is selected, choose the next
+ * unused higher-numbered block.  Returns the block number,
+ * or -1 if we exhaust available blocks looking for an unused
+ * one.
+ */
+static int
 findblock(void)
 {
        int block, numblocks;
 
        numblocks = filesize / blocksize;
        block = random() % numblocks;
-       if (BITVAL(valid, block) == 0)
-               return(block);
 
-       for (  ; BITVAL(valid, block) != 0; block++) {
-               if (block == (numblocks-1))
-                       block = -1;
+       while (BITVAL(valid, block)) {
+               if (++block == numblocks) {
+                       printf("returning block -1\n");
+                       return -1;
+               }
        }
-       if (block == -1)
-               printf("returning block -1\n");
-       return(block);
+       return block;
 }
 
-void
-dumpblock(int *buffer, __uint64_t offset, int blocksize)
+static void
+dumpblock(int *buffer, uint64_t offset, int blocksize)
 {
        int     i;
 
        for (i = 0; i < (blocksize / 16); i++) {
                printf("%llx: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                      (unsigned long long)offset, *buffer, *(buffer + 1), *(buffer + 2),
-                      *(buffer + 3));
+                      (unsigned long long) offset, *buffer, *(buffer + 1),
+                      *(buffer + 2), *(buffer + 3));
                offset += 16;
                buffer += 4;
        }
 }
 
-void
+static void
 writeblks(char *fname, int fd, size_t alignment)
 {
-       __uint64_t offset;
-       char *buffer;
+       uint64_t offset;
+       char *buffer = NULL;
        int block;
+       int ret;
        struct flock64 fl;
 
-       if (test)
-               buffer = NULL;
-       else {
-               if (posix_memalign((void **) &buffer, alignment, blocksize)) {
-                       perror("malloc");
+       if (!test) {
+               ret = posix_memalign((void **) &buffer, alignment, blocksize);
+               if (ret) {
+                       fprintf(stderr, "posix_memalign: %s\n", strerror(ret));
                        exit(1);
                }
                memset(buffer, 0, blocksize);
        }
 
+       /*
+        * Avoid allocation patterns being perturbed by different speculative
+        * preallocation beyond EOF configurations by first truncating the file
+        * to the expected maximum file size.
+        */
+       if (ftruncate(fd, filesize) < 0) {
+               perror("ftruncate");
+               exit(EXIT_FAILURE);
+       }
+
        do {
                if (verbose && ((count % 100) == 0)) {
                        printf(".");
@@ -144,7 +226,7 @@ writeblks(char *fname, int fd, size_t alignment)
                    exit(1);
                }
 
-               offset = (__uint64_t) block * blocksize;
+               offset = (uint64_t) block * blocksize;
                if (alloconly) {
                         if (test) continue;
                         
@@ -170,8 +252,8 @@ writeblks(char *fname, int fd, size_t alignment)
                         * into it.  We'll verify this when we read
                         * it back in again.
                         */
-                       *(__uint64_t *) buffer = fileoffset + offset;
-                       *(__uint64_t *) (buffer + 256) = fileoffset + offset;
+                       *(uint64_t *) buffer = fileoffset + offset;
+                       *(uint64_t *) (buffer + 256) = fileoffset + offset;
 
                        if (write(fd, buffer, blocksize) < blocksize) {
                                perror("write");
@@ -188,10 +270,10 @@ writeblks(char *fname, int fd, size_t alignment)
        free(buffer);
 }
 
-int
+static int
 readblks(int fd, size_t alignment)
 {
-       unsigned long offset;
+       uint64_t offset;
        char *buffer, *tmp;
        unsigned int xfer, block, i;
         int err=0;
@@ -199,8 +281,9 @@ readblks(int fd, size_t alignment)
        if (alloconly)
                return 0;
        xfer = READ_XFER*blocksize;
-       if (posix_memalign((void **) &buffer, alignment, xfer)) {
-               perror("malloc");
+       err = posix_memalign((void **) &buffer, alignment, xfer);
+       if (err) {
+               fprintf(stderr, "posix_memalign: %s\n", strerror(err));
                exit(1);
        }
        memset(buffer, 0, xfer);
@@ -211,49 +294,48 @@ readblks(int fd, size_t alignment)
                perror("lseek");
                exit(1);
        }
-       for (offset = 0, block = 0; offset < filesize; offset += xfer) {
+       block = 0;
+       offset = 0;
+       while (offset < filesize) {
                if ((i = read(fd, buffer, xfer) < xfer)) {
                        if (i < 2)
                                break;
                        perror("read");
                        exit(1);
                }
-               for (tmp = buffer, i = 0; i < READ_XFER; i++, block++, tmp += blocksize) {
+               tmp = buffer;
+               for (i = 0; i < READ_XFER; i++) {
+                       uint64_t want;
+                       uint64_t first;
+                       uint64_t second;
+
                        if (verbose && ((block % 100) == 0)) {
                                printf("+");
                                fflush(stdout);
                        }
-                       if (BITVAL(valid, block) == 0) {
-                               if ((*(__uint64_t *)tmp != 0LL) ||
-                                   (*(__uint64_t *)(tmp+256) != 0LL)) {
-                                       printf("mismatched data at offset=%llx, expected 0x%llx, got 0x%llx and 0x%llx\n",
-                                              (unsigned long long)fileoffset + block * blocksize,
-                                              0LL,
-                                              *(unsigned long long *)tmp,
-                                              *(unsigned long long *)(tmp+256));
-                                        err++;
-                               }
-                       } else {
-                               if ( (*(__uint64_t *)tmp !=
-                                     fileoffset + block * blocksize) ||
-                                    (*(__uint64_t *)(tmp+256) !=
-                                     fileoffset + block * blocksize) ) {
-                                       printf("mismatched data at offset=%llx, "
-                                              "expected 0x%llx, got 0x%llx and 0x%llx\n",
-                                              (unsigned long long)fileoffset + block * blocksize,
-                                              (unsigned long long)fileoffset + block * blocksize,
-                                              *(unsigned long long *)tmp,
-                                              *(unsigned long long *)(tmp+256));
-                                        err++;
-                               }
+
+                       want = BITVAL(valid, block) ? offset : 0;
+                       first = *(uint64_t *) tmp;
+                       second = *(uint64_t *) (tmp + 256);
+                       if (first != want || second != want) {
+                               printf("mismatched data at offset=0x%" PRIx64
+                                       ", expected 0x%" PRIx64
+                                       ", got 0x%" PRIx64
+                                       " and 0x%" PRIx64 "\n",
+                                        fileoffset + offset, want,
+                                        first, second);
+                               err++;
                        }
                        if (verbose > 2) {
                                printf("block %d blocksize %d\n", block,
                                       blocksize);
-                               dumpblock((int *)tmp,
-                                         fileoffset + block * blocksize,
+                               dumpblock((int *)tmp, fileoffset + offset,
                                          blocksize);
                        }
+
+                       block++;
+                       offset += blocksize;
+                       tmp += blocksize;
                }
        }
        if (verbose)
@@ -269,7 +351,7 @@ readblks(int fd, size_t alignment)
  * system; otherwise pointer alignment is fine.  Returns the
  * alignment multiple, or 0 if an error occurs.
  */
-size_t
+static size_t
 get_alignment(char *filename, int fd)
 {
        struct dioattr dioattr;
@@ -307,130 +389,95 @@ get_alignment(char *filename, int fd)
        return (size_t) dioattr.d_mem;
 }
 
-int
-main(int argc, char *argv[])
+static int
+realtime_setup(char *filename, int fd)
 {
-       int seed, ch, fd, oflags;
-       char *filename = NULL;
-        int r;
-       size_t alignment;
+       struct fsxattr rtattr;
 
-       filesize = DEFAULT_FILESIZE;
-       blocksize = DEFAULT_BLOCKSIZE;
-       count = (int) filesize / blocksize;
-       verbose = 0;
-       wsync = 0;
-       seed = time(NULL);
-        test = 0;
-       while ((ch = getopt(argc, argv, "b:l:s:c:o:x:vwdrapt")) != EOF) {
-               switch(ch) {
-               case 'b':       blocksize  = atoi(optarg);      break;
-               case 'l':       filesize   = strtoull(optarg, NULL, 16); break;
-               case 's':       seed       = atoi(optarg);      break;
-               case 'c':       count      = atoi(optarg);      break;
-               case 'o':       fileoffset = strtoull(optarg, NULL, 16); break;
-               case 'x':       extsize    = atoi(optarg);      break;
-               case 'v':       verbose++;                      break;
-               case 'w':       wsync++;                        break;
-               case 'd':       direct++;                       break;
-               case 'r':       rt++;                           break;
-               case 'a':       alloconly++;                    break;
-               case 'p':       preserve++;                     break;
-                case 't':       test++; preserve++;             break;
-               default:        usage(argv[0]);                 break;
-               }
-       }
-       if (optind == argc-1)
-               filename = argv[optind];
-       else
-               usage(argv[0]);
-       if ((filesize % blocksize) != 0) {
-               filesize -= filesize % blocksize;
-               printf("filesize not a multiple of blocksize, reducing filesize to %llu\n",
-                      (unsigned long long)filesize);
-       }
-       if ((fileoffset % blocksize) != 0) {
-               fileoffset -= fileoffset % blocksize;
-               printf("fileoffset not a multiple of blocksize, reducing fileoffset to %llu\n",
-                      (unsigned long long)fileoffset);
+       (void) memset(&rtattr, 0, sizeof rtattr);
+       if (xfscntl(filename, fd, FSGETXATTR, &rtattr) < 0) {
+               perror("FSGETXATTR)");
+               return 1;
        }
-       if (count > (filesize/blocksize)) {
-               count = (filesize/blocksize);
-               printf("count of blocks written is too large, setting to %d\n",
-                             count);
-       } else if (count < 1) {
-               count = 1;
-               printf("count of blocks written is too small, setting to %d\n",
-                             count);
+       if ((rtattr.fsx_xflags & XFS_XFLAG_REALTIME) == 0 ||
+           (extsize && rtattr.fsx_extsize != extsize * blocksize)) {
+               rtattr.fsx_xflags |= XFS_XFLAG_REALTIME;
+               if (extsize)
+                       rtattr.fsx_extsize = extsize * blocksize;
+               if (xfscntl(filename, fd, FSSETXATTR, &rtattr) < 0) {
+                       perror("FSSETXATTR)");
+                       return 1;
+               }
        }
-       printf("randholes: Seed = %d (use \"-s %d\" to re-execute this test)\n", seed, seed);
-       srandom(seed);
 
-        printf("randholes: blocksize=%d, filesize=%llu, seed=%d\n"
-               "randholes: count=%d, offset=%llu, extsize=%d\n",
-                blocksize, (unsigned long long)filesize, seed,
-              count, (unsigned long long)fileoffset, extsize);
-        printf("randholes: verbose=%d, wsync=%d, direct=%d, rt=%d, alloconly=%d, preserve=%d, test=%d\n",
-                verbose, wsync, direct, rt, alloconly, preserve, test);
+       return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+       char    *filename;
+       size_t  size;
+       int     oflags;
+       int     fd;
+       size_t  alignment;
+       int     errors;
+
+       filename = parseargs(argc, argv);
+       if (! filename)
+               return 1;
 
        /*
-        * Open the file, write rand block in random places, read them all
-        * back to check for correctness, then close the file.
+        * Allocate a bitmap big enough to track the range of
+        * blocks we'll be dealing with.
         */
-       nvalid = (filesize / blocksize) / 8 + 1;
-       if ((valid = (unsigned char *)calloc(1, (unsigned)nvalid)) == NULL) {
+       size = (filesize / blocksize) / 8 + 1;
+       valid = malloc(size);
+       if ((valid = malloc(size)) == NULL) {
                perror("malloc");
                return 1;
        }
-       if (rt)
-               direct++;
+       memset(valid, 0, size);
 
-        oflags=test?(O_RDONLY):(O_RDWR | O_CREAT);
-       oflags |=   (preserve ? 0 : O_TRUNC) |
-                   (wsync ? O_SYNC : 0) |
-                   (direct ? O_DIRECT : 0);
+       /* Lots of arguments affect how we open the file */
+       oflags = test ? O_RDONLY : O_RDWR|O_CREAT;
+       oflags |= preserve ? 0 : O_TRUNC;
+       oflags |= wsync ? O_SYNC : 0;
+       oflags |= direct ? O_DIRECT : 0;
 
+       /*
+        * Open the file, write rand block in random places, read them all
+        * back to check for correctness, then close the file.
+        */
        if ((fd = open(filename, oflags, 0666)) < 0) {
                perror("open");
                return 1;
        }
-
-       if (rt) {
-               if (xfscntl(filename, fd, FSGETXATTR, &rtattr) < 0) {
-                       perror("xfsnctl(FSGETXATTR)");
-                       return 1;
-               }
-               if ((rtattr.fsx_xflags & XFS_XFLAG_REALTIME) == 0 ||
-                   (extsize && rtattr.fsx_extsize != extsize * blocksize)) {
-                       rtattr.fsx_xflags |= XFS_XFLAG_REALTIME;
-                       if (extsize)
-                               rtattr.fsx_extsize = extsize * blocksize;
-                       if (xfscntl(filename, fd, FSSETXATTR, &rtattr) < 0) {
-                               perror("xfscntl(FSSETXATTR)");
-                               return 1;
-                       }
-               }
-       }
-
+       if (rt && realtime_setup(filename, fd))
+               return 1;
        alignment = get_alignment(filename, fd);
        if (! alignment)
                return 1;
 
-        printf(test?"write (skipped)\n":"write\n");
+        printf("write%s\n", test ? " (skipped)" : "");
        writeblks(filename, fd, alignment);
+
         printf("readback\n");
-       r = readblks(fd, alignment);
+       errors = readblks(fd, alignment);
+
        if (close(fd) < 0) {
                perror("close");
                return 1;
        }
        free(valid);
 
-        if (r) {
-            printf("randholes: %d errors found during readback\n", r);
-            return 2;
-        } else {
-            printf("randholes: ok\n");
-            return 0;
+        if (errors) {
+               printf("randholes: %d errors found during readback\n", errors);
+               return 2;
         }
+
+       printf("randholes: ok\n");
+
+       return 0;
 }
+