alloc: upgrade to fallocate
[xfstests-dev.git] / src / alloc.c
index 72830a7072d0cd3a216e741ee6f99f28a2bd849d..4a446ca827d8e1d377b53ffd5eb79b157ca541f7 100644 (file)
@@ -1,37 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * 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
- * 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/
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.
+ * All Rights Reserved.
  */
  
 #include "global.h"
 
+/*
+ * Block I/O parameterization.  A basic block (BB) is the lowest size of
+ * filesystem allocation, and must equal 512.  Length units given to bio
+ * routines are in BB's.
+ */
+
+/* Assume that if we have BTOBB, then we have the rest */
+#ifndef BTOBB
+#define BBSHIFT         9
+#define BBSIZE          (1<<BBSHIFT)
+#define BBMASK          (BBSIZE-1)
+#define BTOBB(bytes)    (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BTOBBT(bytes)   ((__u64)(bytes) >> BBSHIFT)
+#define BBTOB(bbs)      ((bbs) << BBSHIFT)
+#define OFFTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT)
+
+#define SEEKLIMIT32     0x7fffffff
+#define BBSEEKLIMIT32   BTOBBT(SEEKLIMIT32)
+#define SEEKLIMIT       0x7fffffffffffffffLL
+#define BBSEEKLIMIT     OFFTOBBT(SEEKLIMIT)
+#endif
+
+#ifndef OFFTOBB
+#define OFFTOBB(bytes)  (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT)
+#define BBTOOFF(bbs)    ((__u64)(bbs) << BBSHIFT)
+#endif
+
 #define        FSBTOBB(f)      (OFFTOBBT(FSBTOOFF(f)))
 #define        BBTOFSB(b)      (OFFTOFSB(BBTOOFF(b)))
 #define        OFFTOFSB(o)     ((o) / blocksize)
@@ -58,74 +59,151 @@ void usage(void)
            
 }
 
-int            fd;
-int            blocksize = 0;
+int            fd = -1;
+int            blocksize;
+char           *filename;
 
 /* params are in bytes */
 void map(off64_t off, off64_t len)
 {
-    struct getbmap     bm[2]={{0}};
+    struct getbmap     bm[2];
     
+    bzero(bm, sizeof(bm));
+
     bm[0].bmv_count = 2;
     bm[0].bmv_offset = OFFTOBB(off);
     if (len==(off64_t)-1) { /* unsigned... */
         bm[0].bmv_length = -1;
         printf("    MAP off=%lld, len=%lld [%lld-]\n", 
-                (__s64)off, (__s64)len,
-                (__s64)BBTOFSB(bm[0].bmv_offset));
+                (long long)off, (long long)len,
+                (long long)BBTOFSB(bm[0].bmv_offset));
     } else {
         bm[0].bmv_length = OFFTOBB(len);
         printf("    MAP off=%lld, len=%lld [%lld,%lld]\n", 
-                (__s64)off, (__s64)len,
-                (__s64)BBTOFSB(bm[0].bmv_offset),
-                (__s64)BBTOFSB(bm[0].bmv_length));
+                (long long)off, (long long)len,
+                (long long)BBTOFSB(bm[0].bmv_offset),
+                (long long)BBTOFSB(bm[0].bmv_length));
     }
     
     printf("        [ofs,count]: start..end\n");
     for (;;) {
-           if (ioctl(fd, XFS_IOC_GETBMAP, bm) < 0) {
+#ifdef XFS_IOC_GETBMAP
+           if (xfsctl(filename, fd, XFS_IOC_GETBMAP, bm) < 0) {
+#else
+#ifdef F_GETBMAP
+           if (fcntl(fd, F_GETBMAP, bm) < 0) {
+#else
+bozo!
+#endif
+#endif
                    perror("getbmap");
                    break;
            }
+
            if (bm[0].bmv_entries == 0)
                    break;
+
            printf("        [%lld,%lld]: ",
-                   (__s64)BBTOFSB(bm[1].bmv_offset),
-                   (__s64)BBTOFSB(bm[1].bmv_length));
+                   (long long)BBTOFSB(bm[1].bmv_offset),
+                   (long long)BBTOFSB(bm[1].bmv_length));
+
            if (bm[1].bmv_block == -1)
                    printf("hole");
            else
                    printf("%lld..%lld",
-                           (__s64)BBTOFSB(bm[1].bmv_block),
-                           (__s64)BBTOFSB(bm[1].bmv_block +
+                           (long long)BBTOFSB(bm[1].bmv_block),
+                           (long long)BBTOFSB(bm[1].bmv_block +
                                    bm[1].bmv_length - 1));
            printf("\n");
     }
 }
 
+#ifdef HAVE_FALLOCATE
+# define USE_LINUX_PREALLOCATE
+enum linux_opno {
+       FREESP = 0,
+       ALLOCSP,
+       UNRESVSP,
+       RESVSP,
+};
+
+/* emulate the irix preallocation functions with linux vfs calls */
+static int
+linux_preallocate(
+       int                     fd,
+       enum linux_opno         opno,
+       const struct flock64    *f)
+{
+       struct stat             sbuf;
+       int                     ret;
+
+       assert(f->l_whence == SEEK_SET);
+
+       switch (opno) {
+       case FREESP:
+               return ftruncate(fd, f->l_start);
+       case ALLOCSP:
+               ret = fstat(fd, &sbuf);
+               if (ret)
+                       return ret;
+
+               return fallocate(fd, 0, sbuf.st_size,
+                               f->l_start - sbuf.st_size);
+       case UNRESVSP:
+               return fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+                               f->l_start, f->l_len);
+       case RESVSP:
+               return fallocate(fd, FALLOC_FL_KEEP_SIZE, f->l_start, f->l_len);
+       }
+
+       /* should never get here */
+       errno = EINVAL;
+       return -1;
+}
+#endif
+
 int
 main(int argc, char **argv)
 {
        int             c;
        char            *dirname = NULL;
        int             done = 0;
+       int             status = 0;
        struct flock64  f;
-       char            *filename = NULL;
        off64_t         len;
        char            line[1024];
        off64_t         off;
        int             oflags;
-       static char     *opnames[] =
-               { "freesp", "allocsp", "unresvsp", "resvsp" };
+       static char     *opnames[] = { "freesp",
+                                      "allocsp",
+                                      "unresvsp",
+                                      "resvsp" };
        int             opno;
-       static int      optab[] =
-               { XFS_IOC_FREESP64, XFS_IOC_ALLOCSP64, XFS_IOC_UNRESVSP64, XFS_IOC_RESVSP64 };
+
+#if defined(HAVE_FALLOCATE)
+       /* see static function above */
+#elif defined(XFS_IOC_FREESP64)
+#define USE_XFSCTL
+       /* Assume that if we have FREESP64 then we have the rest */
+       static int      optab[] = { XFS_IOC_FREESP64,
+                                   XFS_IOC_ALLOCSP64,
+                                   XFS_IOC_UNRESVSP64,
+                                   XFS_IOC_RESVSP64 };
+#elif defined(F_FREESP64)
+#define USE_FCNTL
+       static int      optab[] = { F_FREESP64,
+                                   F_ALLOCSP64,
+                                   F_UNRESVSP64,
+                                   F_RESVSP64 };
+#else
+# error Dont know how to preallocate space!
+#endif
        int             rflag = 0;
        struct statvfs64        svfs;
        int             tflag = 0;
         int             nflag = 0;
        int             unlinkit = 0;
-       __int64_t       v;
+       int64_t         v;
 
        while ((c = getopt(argc, argv, "b:d:f:rtn")) != -1) {
                switch (c) {
@@ -181,32 +259,60 @@ main(int argc, char **argv)
                perror(filename);
                exit(1);
        }
-       if (unlinkit)
-               unlink(filename);
        if (!blocksize) {
-               if (fstatvfs64(fd, &svfs) < 0) {
-                       perror(filename);
-                       exit(1);
-               }
+               if (fstatvfs64(fd, &svfs) < 0) {
+                       perror(filename);
+                       status = 1;
+                       goto done;
+               }
                blocksize = (int)svfs.f_bsize;
-        }
-        if (blocksize<0) {
-                fprintf(stderr,"illegal blocksize %d\n", blocksize);
-                exit(1);
-        }
+       }
+       if (blocksize<0) {
+               fprintf(stderr,"illegal blocksize %d\n", blocksize);
+               status = 1;
+               goto done;
+       }
        printf("    blocksize %d\n", blocksize);
        if (rflag) {
                struct fsxattr a;
 
-               if (ioctl(fd, XFS_IOC_FSGETXATTR, &a) < 0) {
+#ifdef XFS_IOC_FSGETXATTR
+               if (xfsctl(filename, fd, XFS_IOC_FSGETXATTR, &a) < 0) {
                        perror("XFS_IOC_FSGETXATTR");
-                       exit(1);
+                       status = 1;
+                       goto done;
+               }
+#else
+#ifdef F_FSGETXATTR
+               if (fcntl(fd, F_FSGETXATTR, &a) < 0) {
+                       perror("F_FSGETXATTR");
+                       status = 1;
+                       goto done;
                }
+#else
+bozo!
+#endif
+#endif
+
                a.fsx_xflags |= XFS_XFLAG_REALTIME;
-               if (ioctl(fd, XFS_IOC_FSSETXATTR, &a) < 0) {
+
+#ifdef XFS_IOC_FSSETXATTR
+               if (xfsctl(filename, fd, XFS_IOC_FSSETXATTR, &a) < 0) {
                        perror("XFS_IOC_FSSETXATTR");
-                       exit(1);
+                       status = 1;
+                       goto done;
+               }
+#else
+#ifdef F_FSSETXATTR
+               if (fcntl(fd, F_FSSETXATTR, &a) < 0) {
+                       perror("F_FSSETXATTR");
+                       status = 1;
+                       goto done;
                }
+#else
+bozo!
+#endif
+#endif
        }
        while (!done) {
                 char *p;
@@ -246,10 +352,18 @@ main(int argc, char **argv)
                                len = v;
                         
                         printf("    CMD %s, off=%lld, len=%lld\n", 
-                                opnames[opno], (__s64)off, (__s64)len);
+                                opnames[opno], (long long)off, (long long)len);
                         
                        f.l_len = len;
-                       c = ioctl(fd, optab[opno], &f);
+#if defined(USE_LINUX_PREALLOCATE)
+                       c = linux_preallocate(fd, opno, &f);
+#elif defined(USE_XFSCTL)
+                       c = xfsctl(filename, fd, optab[opno], &f);
+#elif defined(USE_FCNTL)
+                       c = fcntl(fd, optab[opno], &f);
+#else
+# error Dont know how to preallocate space!
+#endif
                        if (c < 0) {
                                perror(opnames[opno]);
                                break;
@@ -284,7 +398,7 @@ main(int argc, char **argv)
                                off = FSBTOOFF(v);
                        else
                                off = v;
-                        printf("    TRUNCATE off=%lld\n", (__s64)off);
+                        printf("    TRUNCATE off=%lld\n", (long long)off);
                        if (ftruncate64(fd, off) < 0) {
                                perror("ftruncate");
                                break;
@@ -307,8 +421,12 @@ main(int argc, char **argv)
                        break;
                }
        }
-        if (!nflag) printf("\n");
-       close(fd);
-       exit(0);
+       if (!nflag) printf("\n");
+done:
+       if (fd != -1)
+               close(fd);
+       if (unlinkit)
+               unlink(filename);
+       exit(status);
        /* NOTREACHED */
 }