Add new defrag range ioctl that can also compress files on demand.
authorChris Mason <chris.mason@oracle.com>
Thu, 11 Mar 2010 14:38:52 +0000 (09:38 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 11 Mar 2010 14:38:52 +0000 (09:38 -0500)
Makefile
btrfs-defrag.c [new file with mode: 0644]
ioctl.h

index f2a9d41..1000268 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ bindir = $(prefix)/bin
 LIBS=-luuid
 
 progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
-       btrfs-map-logical btrfs-list
+       btrfs-map-logical btrfs-list btrfs-defrag
 
 # make C=1 to enable sparse
 ifdef C
@@ -39,6 +39,9 @@ version:
 btrfs-list: $(objects) btrfs-list.o
        gcc $(CFLAGS) -o btrfs-list btrfs-list.o $(objects) $(LDFLAGS) $(LIBS)
 
+btrfs-defrag: $(objects) btrfs-defrag.o
+       gcc $(CFLAGS) -o btrfs-defrag btrfs-defrag.o $(objects) $(LDFLAGS) $(LIBS)
+
 btrfsctl: $(objects) btrfsctl.o
        gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS)
 
diff --git a/btrfs-defrag.c b/btrfs-defrag.c
new file mode 100644 (file)
index 0000000..9aab3ba
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2010 Oracle.  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 v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will 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 to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __CHECKER__
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include "ioctl.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <getopt.h>
+#include "kerncompat.h"
+#include "ctree.h"
+#include "transaction.h"
+#include "utils.h"
+#include "version.h"
+
+static u64 parse_size(char *s)
+{
+       int len = strlen(s);
+       char c;
+       u64 mult = 1;
+
+       if (!isdigit(s[len - 1])) {
+               c = tolower(s[len - 1]);
+               switch (c) {
+               case 'g':
+                       mult *= 1024;
+               case 'm':
+                       mult *= 1024;
+               case 'k':
+                       mult *= 1024;
+               case 'b':
+                       break;
+               default:
+                       fprintf(stderr, "Unknown size descriptor %c\n", c);
+                       exit(1);
+               }
+               s[len - 1] = '\0';
+       }
+       return atoll(s) * mult;
+}
+
+static void print_usage(void)
+{
+       printf("usage: btrfs-defrag [-c] [-f] [-s start] [-l len] "
+              "[-t threshold] file ...\n");
+       exit(1);
+}
+
+int main(int ac, char **av)
+{
+       int fd;
+       int compress = 0;
+       int flush = 0;
+       u64 start = 0;
+       u64 len = (u64)-1;
+       u32 thresh = 0;
+       int i;
+       int errors = 0;
+       int ret = 0;
+       int verbose = 0;
+       struct btrfs_ioctl_defrag_range_args range;
+
+       while(1) {
+               int c = getopt(ac, av, "vcfs:l:t:");
+               if (c < 0)
+                       break;
+               switch(c) {
+               case 'c':
+                       compress = 1;
+                       break;
+               case 'f':
+                       flush = 1;
+                       break;
+               case 'v':
+                       verbose = 1;
+                       break;
+               case 's':
+                       start = parse_size(optarg);
+                       break;
+               case 'l':
+                       len = parse_size(optarg);
+                       break;
+               case 't':
+                       thresh = parse_size(optarg);
+                       break;
+               default:
+                       print_usage();
+                       return 1;
+               }
+       }
+       if (ac - optind == 0)
+               print_usage();
+
+       memset(&range, 0, sizeof(range));
+       range.start = start;
+       range.len = len;
+       range.extent_thresh = thresh;
+       if (compress)
+               range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
+       if (flush)
+               range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
+
+       for (i = optind; i < ac; i++) {
+               fd = open(av[i], O_RDWR);
+               if (fd < 0) {
+                       fprintf(stderr, "failed to open %s\n", av[i]);
+                       perror("open:");
+                       errors++;
+                       continue;
+               }
+               ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range);
+               if (ret) {
+                       fprintf(stderr, "ioctl failed on %s ret %d\n",
+                               av[i], ret);
+                       errors++;
+               }
+               close(fd);
+       }
+       if (verbose)
+               printf("%s\n", BTRFS_BUILD_VERSION);
+       if (errors) {
+               fprintf(stderr, "total %d failures\n", errors);
+               exit(1);
+       }
+       return 0;
+}
+
diff --git a/ioctl.h b/ioctl.h
index 6a4a2d1..9713098 100644 (file)
--- a/ioctl.h
+++ b/ioctl.h
@@ -92,6 +92,34 @@ struct btrfs_ioctl_ino_lookup_args {
        char name[BTRFS_INO_LOOKUP_PATH_MAX];
 };
 
+/* flags for the defrag range ioctl */
+#define BTRFS_DEFRAG_RANGE_COMPRESS 1
+#define BTRFS_DEFRAG_RANGE_START_IO 2
+
+struct btrfs_ioctl_defrag_range_args {
+       /* start of the defrag operation */
+       __u64 start;
+
+       /* number of bytes to defrag, use (u64)-1 to say all */
+       __u64 len;
+
+       /*
+        * flags for the operation, which can include turning
+        * on compression for this one defrag
+        */
+       __u64 flags;
+
+       /*
+        * any extent bigger than this will be considered
+        * already defragged.  Use 0 to take the kernel default
+        * Use 1 to say every single extent must be rewritten
+        */
+       __u32 extent_thresh;
+
+       /* spare for later */
+       __u32 unused[5];
+};
+
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
                                   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -118,10 +146,10 @@ struct btrfs_ioctl_ino_lookup_args {
 /* 13 is for CLONE_RANGE */
 #define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
                                   struct btrfs_ioctl_vol_args)
-
 #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
                                   struct btrfs_ioctl_vol_args)
-
+#define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \
+                               struct btrfs_ioctl_defrag_range_args)
 #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
                                   struct btrfs_ioctl_search_args)
 #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \