fstests: Replace all __[u]intNN_t types with standard [u]intNN_t
[xfstests-dev.git] / src / randholes.c
index 6b7627c082a4a0009a3d675564297f2d26d2f219..a16670f06547be59bca9e4bdf068d3653f635590 100644 (file)
 /*
- * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
- * 
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
+ * Copyright (c) 2000-2003, 2010 SGI
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation.
- * 
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * 
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like.  Any license provided herein, whether implied or
- * otherwise, applies only to this software file.  Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- * 
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- * 
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- * 
- * http://www.sgi.com 
- * 
- * For further information regarding this notice, see: 
- * 
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
  
+#include <inttypes.h>
+
 #include "global.h"
 
-unsigned char  *valid; /* Bit-vector array showing which blocks have been written */
-int            nvalid; /* number of bytes in valid array */
+#define        power_of_2(x)   ((x) && !((x) & ((x) - 1)))
+#define        DEFAULT_FILESIZE        ((uint64_t) (256 * 1024 * 1024))
+#define        DEFAULT_BLOCKSIZE       512
+
 #define        SETBIT(ARRAY, N)        ((ARRAY)[(N)/8] |= (1 << ((N)%8)))
 #define        BITVAL(ARRAY, N)        ((ARRAY)[(N)/8] & (1 << ((N)%8)))
 
-__uint64_t filesize;
-unsigned int blocksize;
-int count;
-int verbose;
-int wsync;
-int direct;
-int alloconly;
-int rt;
-int extsize;
-int preserve;
-int test;
-__uint64_t fileoffset;
-struct dioattr diob;
-struct fsxattr rtattr;
-
-#define        READ_XFER       10      /* block to read at a time when checking */
-
-void usage(char *progname);
-int findblock(void);
-void writeblks(int fd);
-int readblks(int fd);
-void dumpblock(int *buffer, __uint64_t offset, int blocksize);
-
-void
+/* Bit-vector array showing which blocks have been written */
+static unsigned char   *valid;
+
+static uint64_t filesize;
+static uint64_t fileoffset;
+
+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
+ * and the Irix fcntl() interfaces to XFS for user space.  The
+ * "cmd" argument is just the last part of the command, e.g.
+ * pass FSGETXATTR in place of either XFS_IOC_FSGETXATTR (Linux)
+ * F_FSGETXATTR (Irix).
+ *
+ */
+#  define xfscntl(filename, fd, cmd, arg) \
+               xfsctl((filename), (fd), XFS_IOC_ ## cmd, (arg))
+
+static void
 usage(char *progname)
 {
-       fprintf(stderr, "usage: %s [-l filesize] [-b blocksize] [-c count] [-o write offset] [-s seed] [-x extentsize] [-w] [-v] [-d] [-r] [-a] [-p] filename\n",
-                       progname);
+       fprintf(stderr,
+               "usage: %s [-l filesize] [-b blocksize] [-c count]\n"
+               "\t\t[-o write_offset] [-s seed] [-r [-x extentsize]]\n"
+               "\t\t[-w] [-v] [-d] [-a] [-p] [-t] filename\n\n",
+               progname);
+       fprintf(stderr, "\tdefault filesize is %" PRIu64 " bytes\n",
+               DEFAULT_FILESIZE);
+       fprintf(stderr, "\tdefault blocksize is %u bytes\n",
+               DEFAULT_BLOCKSIZE);
+       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);
        exit(1);
 }
 
-int
-main(int argc, char *argv[])
+/* Returns filename if successful or a null pointer if an error occurs */
+static char *
+parseargs(int argc, char *argv[])
 {
-       int seed, ch, fd, oflags;
-       char *filename = NULL;
-        int r;
+       int seed;
+       int ch;
 
-       filesize = ((__uint64_t)256)*1024*1024;
-       blocksize = 512;
-       count = filesize/blocksize;
+       filesize = DEFAULT_FILESIZE;
+       blocksize = DEFAULT_BLOCKSIZE;
+       count = (int) filesize / blocksize;
        verbose = 0;
        wsync = 0;
        seed = time(NULL);
-        test = 0;
+       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   = strtoll(optarg, NULL, 16); break;
+               case 'l':       filesize   = strtoull(optarg, NULL, 16); break;
                case 's':       seed       = atoi(optarg);      break;
                case 'c':       count      = atoi(optarg);      break;
-               case 'o':       fileoffset = strtoll(optarg, NULL, 16); 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 'r':       rt++; direct++;                 break;
                case 'a':       alloconly++;                    break;
                case 'p':       preserve++;                     break;
-                case 't':       test++; preserve++;             break;
+               case 't':       test++; preserve++;             break;
                default:        usage(argv[0]);                 break;
                }
        }
-       if (optind == argc-1)
-               filename = argv[optind];
-       else
+       if (optind != argc - 1)
                usage(argv[0]);
+
        if ((filesize % blocksize) != 0) {
                filesize -= filesize % blocksize;
-               printf("filesize not a multiple of blocksize, reducing filesize to %lld\n",
-                                filesize);
+               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 %lld\n",
-                      fileoffset);
+               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);
+               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("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);
+       printf("randholes: Seed = %d (use \"-s %d\" "
+               "to re-execute this test)\n", seed, seed);
        srandom(seed);
-        
-        printf("randholes: blocksize=%d, filesize=%Ld, seed=%d\n"
-               "randholes: count=%d, offset=%Ld, extsize=%d\n",
-                blocksize, filesize, seed, count, 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);
-        
-       /*
-        * Open the file, write rand block in random places, read them all
-        * back to check for correctness, then close the file.
-        */
-       nvalid = (filesize / blocksize) / 8 + 1;
-       if ((valid = (unsigned char *)calloc(1, (unsigned)nvalid)) == NULL) {
-               perror("malloc");
-               return 1;
-       }
-       if (rt)
-               direct++;
-        
-        oflags=test?(O_RDONLY):(O_RDWR | O_CREAT);
-       oflags |=   (preserve ? 0 : O_TRUNC) |
-                   (wsync ? O_SYNC : 0) |
-                   (direct ? O_DIRECT : 0);
-        
-       if ((fd = open(filename, oflags, 0666)) < 0) {
-               perror("open");
-               return 1;
-       }
-       if (rt) {
-               if (ioctl(fd, XFS_IOC_FSGETXATTR, &rtattr) < 0) {
-                       perror("ioctl(XFS_IOC_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 (ioctl(fd, XFS_IOC_FSSETXATTR, &rtattr) < 0) {
-                               perror("ioctl(XFS_IOC_FSSETXATTR)");
-                               return 1;
-                       }
-               }
-       }
-       if (direct) {
-               if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) {
-                       perror("ioctl(XFS_IOC_FIOINFO)");
-                       return 1;
-               }
-               if (blocksize % diob.d_miniosz) {
-                       fprintf(stderr, "blocksize %d must be a multiple of %d for direct I/O\n", blocksize, diob.d_miniosz);
-                       return 1;
+
+        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;
+
+       while (BITVAL(valid, block)) {
+               if (++block == numblocks) {
+                       printf("returning block -1\n");
+                       return -1;
                }
        }
-        printf(test?"write (skipped)\n":"write\n");
-       writeblks(fd);
-        printf("readback\n");
-       r=readblks(fd);
-       if (close(fd) < 0) {
-               perror("close");
-               return 1;
+       return block;
+}
+
+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));
+               offset += 16;
+               buffer += 4;
        }
-       free(valid);
-        
-        if (r) {
-            printf("randholes: %d errors found during readback\n", r);
-            return 2;
-        } else {
-            printf("randholes: ok\n");
-            return 0;
-        }
 }
 
-void
-writeblks(int fd)
+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 (direct)
-               buffer = memalign(diob.d_mem, blocksize);
-       else
-               buffer = malloc(blocksize);
-       if (buffer == NULL) {
-               perror("malloc");
-               exit(1);
+       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);
        }
-       memset(buffer, 0, blocksize);
 
-       for (  ; count > 0; count--) {
+       do {
                if (verbose && ((count % 100) == 0)) {
                        printf(".");
                        fflush(stdout);
                }
                block = findblock();
-               offset = (__uint64_t)block * blocksize;
+               if (block < 0) {
+                   perror("findblock");
+                   exit(1);
+               }
+
+               offset = (uint64_t) block * blocksize;
                if (alloconly) {
                         if (test) continue;
                         
-                       fl.l_start = offset;
+                       fl.l_start = fileoffset + offset;
                        fl.l_len = blocksize;
                        fl.l_whence = 0;
-                       if (ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0) {
-                               perror("ioctl(XFS_IOC_RESVSP64)");
+
+                       if (xfscntl(fname, fd, RESVSP64, &fl) < 0) {
+                               perror("xfsnctl(RESVSP64)");
                                exit(1);
                        }
                        continue;
@@ -241,30 +246,34 @@ writeblks(int fd)
                                perror("lseek");
                                exit(1);
                        }
-                }
-               *(__uint64_t *)buffer = *(__uint64_t *)(buffer+256) =
-                       fileoffset + offset;
-                if (!test) {
+                       /*
+                        * Before writing, record offset at the base
+                        * of the buffer and at offset 256 bytes
+                        * into it.  We'll verify this when we read
+                        * it back in again.
+                        */
+                       *(uint64_t *) buffer = fileoffset + offset;
+                       *(uint64_t *) (buffer + 256) = fileoffset + offset;
+
                        if (write(fd, buffer, blocksize) < blocksize) {
                                perror("write");
                                exit(1);
                        }
                 }
-                if (test && verbose>1) printf("NOT ");
                if (verbose > 1) {
-                       printf("writing data at offset=%llx, value 0x%llx and 0x%llx\n",
-                              fileoffset + offset,
-                              *(__uint64_t *)buffer, *(__uint64_t *)(buffer+256));
+                       printf("%swriting data at offset=%llx\n",
+                               test ? "NOT " : "",
+                               (unsigned long long) (fileoffset + offset));
                }
-       }
+       } while (--count);
 
        free(buffer);
 }
 
-int
-readblks(int fd)
+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;
@@ -272,12 +281,9 @@ readblks(int fd)
        if (alloconly)
                return 0;
        xfer = READ_XFER*blocksize;
-       if (direct)
-               buffer = memalign(diob.d_mem, xfer);
-       else
-               buffer = malloc(xfer);
-       if (buffer == NULL) {
-               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);
@@ -288,48 +294,48 @@ readblks(int fd)
                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",
-                                              fileoffset + block * blocksize,
-                                              0LL,
-                                              *(__uint64_t *)tmp,
-                                              *(__uint64_t *)(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",
-                                              fileoffset + block * blocksize,
-                                              fileoffset + block * blocksize,
-                                              *(__uint64_t *)tmp,
-                                              *(__uint64_t *)(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)
@@ -339,35 +345,139 @@ readblks(int fd)
         return err;
 }
 
-int
-findblock(void)
+/*
+ * Determine the memory alignment required for I/O buffers.  For
+ * direct I/O we request the needed information from the file
+ * system; otherwise pointer alignment is fine.  Returns the
+ * alignment multiple, or 0 if an error occurs.
+ */
+static size_t
+get_alignment(char *filename, int fd)
 {
-       int block, numblocks;
+       struct dioattr dioattr;
 
-       numblocks = filesize / blocksize;
-       block = random() % numblocks;
-       if (BITVAL(valid, block) == 0)
-               return(block);
+       if (! direct)
+               return sizeof (void *);
 
-       for (  ; BITVAL(valid, block) != 0; block++) {
-               if (block == (numblocks-1))
-                       block = -1;
+       memset(&dioattr, 0, sizeof dioattr);
+       if (xfscntl(filename, fd, DIOINFO, &dioattr) < 0) {
+               perror("xfscntl(FIOINFO)");
+               return 0;
        }
-       if (block == -1)
-               printf("returning block -1\n");
-       return(block);
+
+       /* Make sure the alignment meets the needs of posix_memalign() */
+
+       if (dioattr.d_mem % sizeof (void *) || ! power_of_2(dioattr.d_mem)) {
+               perror("d_mem bad");
+               return 0;
+       }
+
+       /*
+        * Also make sure user doesn't specify a block size that's
+        * incompatible with the underlying file system.
+        */
+       if (! dioattr.d_miniosz) {
+               perror("miniosz == 0!");
+               return 0;
+       }
+       if (blocksize % dioattr.d_miniosz) {
+               fprintf(stderr, "blocksize %d must be a multiple of "
+                       "%d for direct I/O\n", blocksize, dioattr.d_miniosz);
+               return 0;
+       }
+
+       return (size_t) dioattr.d_mem;
 }
 
-void
-dumpblock(int *buffer, __uint64_t offset, int blocksize)
+static int
+realtime_setup(char *filename, int fd)
 {
-       int     i;
+       struct fsxattr rtattr;
 
-       for (i = 0; i < (blocksize / 16); i++) {
-               printf("%llx: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                      offset, *buffer, *(buffer + 1), *(buffer + 2),
-                      *(buffer + 3));
-               offset += 16;
-               buffer += 4;
+       (void) memset(&rtattr, 0, sizeof rtattr);
+       if (xfscntl(filename, fd, FSGETXATTR, &rtattr) < 0) {
+               perror("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("FSSETXATTR)");
+                       return 1;
+               }
+       }
+
+       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;
+
+       /*
+        * Allocate a bitmap big enough to track the range of
+        * blocks we'll be dealing with.
+        */
+       size = (filesize / blocksize) / 8 + 1;
+       valid = malloc(size);
+       if ((valid = malloc(size)) == NULL) {
+               perror("malloc");
+               return 1;
        }
+       memset(valid, 0, size);
+
+       /* 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 && realtime_setup(filename, fd))
+               return 1;
+       alignment = get_alignment(filename, fd);
+       if (! alignment)
+               return 1;
+
+        printf("write%s\n", test ? " (skipped)" : "");
+       writeblks(filename, fd, alignment);
+
+        printf("readback\n");
+       errors = readblks(fd, alignment);
+
+       if (close(fd) < 0) {
+               perror("close");
+               return 1;
+       }
+       free(valid);
+
+        if (errors) {
+               printf("randholes: %d errors found during readback\n", errors);
+               return 2;
+        }
+
+       printf("randholes: ok\n");
+
+       return 0;
 }
+