diff --git a/Makefile b/Makefile index f2a9d41a..10002681 100644 --- 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 index 00000000..9aab3ba4 --- /dev/null +++ b/btrfs-defrag.c @@ -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 +#include +#include "ioctl.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 6a4a2d14..97130989 100644 --- 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, \