diff --git a/0113-Btrfs-progs-add-restriper-commands.patch b/0113-Btrfs-progs-add-restriper-commands.patch index 520fe72..0a41f3d 100644 --- a/0113-Btrfs-progs-add-restriper-commands.patch +++ b/0113-Btrfs-progs-add-restriper-commands.patch @@ -1,73 +1,131 @@ -From 192484f121dbbffd004303a760ef8b4dbd470ce2 Mon Sep 17 00:00:00 2001 +From b35dbf547122fa2502c8c7e5646d48148ffdee44 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov -Date: Tue, 23 Aug 2011 23:08:16 +0300 -Subject: [PATCH 14/35] Btrfs-progs: add restriper commands +Date: Mon, 16 Jan 2012 12:38:03 +0100 +Subject: [PATCH 15/43] Btrfs-progs: add restriper commands + +Import restriper commands under btrfs fi balance: + + btrfs fi balance start + btrfs fi balance cancel + btrfs fi balance pause + btrfs fi balance resume + btrfs fi balance status + +NOTE: Backwards compatibility is broken for now, to get the old "balance +everything" behaviour one has to call 'btrfs fi balance start' with no +options instead of 'btrfs fi balance'. This is because btrfs utility +sub-command parser is not flexible enough. Signed-off-by: Ilya Dryomov --- - btrfs.c | 21 +++ - btrfs_cmds.c | 505 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- - btrfs_cmds.h | 5 + - ctree.h | 9 + - ioctl.h | 46 +++++- - print-tree.c | 3 + - volumes.h | 42 +++++ - 7 files changed, 628 insertions(+), 3 deletions(-) + btrfs.c | 27 +++- + btrfs_cmds.c | 589 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- + btrfs_cmds.h | 8 +- + ctree.h | 23 ++- + ioctl.h | 53 ++++++ + print-tree.c | 6 + + volumes.h | 30 +++ + 7 files changed, 687 insertions(+), 49 deletions(-) -diff --git a/btrfs.c b/btrfs.c -index 66b0d80..52af8f7 100644 ---- a/btrfs.c -+++ b/btrfs.c -@@ -329,6 +329,27 @@ static struct Command commands[] = { - "Show status of running or finished scrub.", +Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs.c +=================================================================== +--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs.c ++++ btrfs-progs-v0.19-118-gfdb6c04/btrfs.c +@@ -295,9 +295,30 @@ static struct Command commands[] = { + "Show space usage information for a mount point.", NULL }, -+ { do_restripe, -1, -+ "filesystem restripe start", "[-d [filters]] [-m [filters]] " +- { do_balance, 1, +- "filesystem balance", "\n" +- "Balance the chunks across the device.", ++ { do_balance, -1, ++ "filesystem balance start", "[-d [filters]] [-m [filters]] " + "[-s [filters]] [-vf] \n" -+ "Start restriper." ++ "Balance chunks across the devices.", ++ NULL + }, -+ { do_restripe_cancel, 1, -+ "filesystem restripe cancel", "\n" -+ "Cancel restriper." ++ { do_balance_pause, 1, ++ "filesystem balance pause", "\n" ++ "Pause running balance.", ++ NULL + }, -+ { do_restripe_pause, 1, -+ "filesystem restripe pause", "\n" -+ "Pause restriper." ++ { do_balance_cancel, 1, ++ "filesystem balance cancel", "\n" ++ "Cancel running or paused balance.", ++ NULL + }, -+ { do_restripe_resume, 1, -+ "filesystem restripe resume", "\n" -+ "Resume interrupted restripe operation." ++ { do_balance_resume, 1, ++ "filesystem balance resume", "\n" ++ "Resume interrupted balance.", ++ NULL + }, -+ { do_restripe_progress, -1, -+ "filesystem restripe status", "[-v] \n" -+ "Show status of running or paused restripe operation." -+ }, - { do_scan, 999, - "device scan", "[...]\n" - "Scan all device for or the passed device for a btrfs\n" -diff --git a/btrfs_cmds.c b/btrfs_cmds.c -index 1bfc669..e4c5592 100644 ---- a/btrfs_cmds.c -+++ b/btrfs_cmds.c -@@ -1094,14 +1094,515 @@ int do_balance(int argc, char **argv) - e = errno; - close(fdmnt); - if(ret<0){ ++ { do_balance_progress, -1, ++ "filesystem balance status", "[-v] \n" ++ "Show status of running or paused balance.", + NULL + }, + { do_change_label, -1, +Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs_cmds.c +=================================================================== +--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs_cmds.c ++++ btrfs-progs-v0.19-118-gfdb6c04/btrfs_cmds.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1067,43 +1068,6 @@ int do_add_volume(int nargs, char **args + + } + +-/**** man: btrfs filesystem balance +- * +- * \Bbtrfs\b \Bfilesystem balance\b \I\i +- * +- * Balance chunks across the devices. +- * +- * Balance chunks across the devices. +- ****/ +- +-int do_balance(int argc, char **argv) +-{ +- +- int fdmnt, ret=0, e; +- struct btrfs_ioctl_vol_args args; +- char *path = argv[1]; +- +- fdmnt = open_file_or_dir(path); +- if (fdmnt < 0) { +- fprintf(stderr, "ERROR: can't access to '%s'\n", path); +- return 12; +- } +- +- memset(&args, 0, sizeof(args)); +- ret = ioctl(fdmnt, BTRFS_IOC_BALANCE, &args); +- e = errno; +- close(fdmnt); +- if(ret<0){ - fprintf(stderr, "ERROR: error during balancing '%s' - %s\n", - path, strerror(e)); -+ if (e == ECANCELED) { -+ fprintf(stderr, "restripe interrupted by user\n"); -+ } else { -+ fprintf(stderr, "ERROR: error during restriping '%s' " -+ "- %s\n", path, strerror(e)); -+ return 19; -+ } -+ } -+ return 0; -+} -+ -+static int parse_one_profile(char *profile, u64 *flags) +- +- return 19; +- } +- return 0; +-} +- +- +- + /**** man: btrfs device delete + * + * \Bbtrfs\b \Bdevice delete\b\I [..] \i +@@ -1188,6 +1152,575 @@ int do_set_default_subvol(int nargs, cha + return 0; + } + ++static int parse_one_profile(const char *profile, u64 *flags) +{ + if (!strcmp(profile, "raid0")) { + *flags |= BTRFS_BLOCK_GROUP_RAID0; @@ -102,7 +160,20 @@ index 1bfc669..e4c5592 100644 + return 0; +} + -+static int parse_range(char *range, u64 *start, u64 *end) ++static int parse_u64(const char *str, u64 *result) ++{ ++ char *endptr; ++ u64 val; ++ ++ val = strtoull(str, &endptr, 10); ++ if (*endptr) ++ return 1; ++ ++ *result = val; ++ return 0; ++} ++ ++static int parse_range(const char *range, u64 *start, u64 *end) +{ + char *dots; + @@ -117,13 +188,22 @@ index 1bfc669..e4c5592 100644 + *end = (u64)-1; + skipped++; + } else { -+ *end = strtoull(rest, (char **)NULL, 10); ++ if (parse_u64(rest, end)) ++ return 1; + } + if (dots == range) { + *start = 0; + skipped++; + } else { -+ *start = strtoull(range, (char **)NULL, 10); ++ if (parse_u64(range, start)) ++ return 1; ++ } ++ ++ if (*start >= *end) { ++ fprintf(stderr, "Range %llu..%llu doesn't make " ++ "sense\n", (unsigned long long)*start, ++ (unsigned long long)*end); ++ return 1; + } + + if (skipped <= 1) @@ -133,7 +213,7 @@ index 1bfc669..e4c5592 100644 + return 1; +} + -+static int parse_filters(char *filters, struct btrfs_restripe_args *rargs) ++static int parse_filters(char *filters, struct btrfs_balance_args *args) +{ + char *this_char; + char *value; @@ -153,74 +233,74 @@ index 1bfc669..e4c5592 100644 + "an argument\n"); + return 1; + } -+ if (parse_profiles(value, &rargs->profiles)) { ++ if (parse_profiles(value, &args->profiles)) { + fprintf(stderr, "Invalid profiles argument\n"); + return 1; + } -+ rargs->flags |= BTRFS_RESTRIPE_ARGS_PROFILES; ++ args->flags |= BTRFS_BALANCE_ARGS_PROFILES; + } else if (!strcmp(this_char, "usage")) { + if (!value || !*value) { + fprintf(stderr, "the usage filter requires " + "an argument\n"); + return 1; + } -+ rargs->usage = strtoull(value, (char **)NULL, 10); -+ if (rargs->usage < 1 || rargs->usage > 100) { ++ if (parse_u64(value, &args->usage) || ++ args->usage < 1 || args->usage > 100) { + fprintf(stderr, "Invalid usage argument: %s\n", + value); + return 1; + } -+ rargs->flags |= BTRFS_RESTRIPE_ARGS_USAGE; ++ args->flags |= BTRFS_BALANCE_ARGS_USAGE; + } else if (!strcmp(this_char, "devid")) { + if (!value || !*value) { + fprintf(stderr, "the devid filter requires " + "an argument\n"); + return 1; + } -+ rargs->devid = strtoull(value, (char **)NULL, 10); -+ if (rargs->devid == 0) { ++ if (parse_u64(value, &args->devid) || ++ args->devid == 0) { + fprintf(stderr, "Invalid devid argument: %s\n", + value); + return 1; + } -+ rargs->flags |= BTRFS_RESTRIPE_ARGS_DEVID; ++ args->flags |= BTRFS_BALANCE_ARGS_DEVID; + } else if (!strcmp(this_char, "drange")) { + if (!value || !*value) { + fprintf(stderr, "the drange filter requires " + "an argument\n"); + return 1; + } -+ if (parse_range(value, &rargs->pstart, &rargs->pend)) { ++ if (parse_range(value, &args->pstart, &args->pend)) { + fprintf(stderr, "Invalid drange argument\n"); + return 1; + } -+ rargs->flags |= BTRFS_RESTRIPE_ARGS_DRANGE; ++ args->flags |= BTRFS_BALANCE_ARGS_DRANGE; + } else if (!strcmp(this_char, "vrange")) { + if (!value || !*value) { + fprintf(stderr, "the vrange filter requires " + "an argument\n"); + return 1; + } -+ if (parse_range(value, &rargs->vstart, &rargs->vend)) { ++ if (parse_range(value, &args->vstart, &args->vend)) { + fprintf(stderr, "Invalid vrange argument\n"); + return 1; + } -+ rargs->flags |= BTRFS_RESTRIPE_ARGS_VRANGE; ++ args->flags |= BTRFS_BALANCE_ARGS_VRANGE; + } else if (!strcmp(this_char, "convert")) { + if (!value || !*value) { + fprintf(stderr, "the convert option requires " + "an argument\n"); + return 1; + } -+ if (parse_one_profile(value, &rargs->target)) { ++ if (parse_one_profile(value, &args->target)) { + fprintf(stderr, "Invalid convert argument\n"); + return 1; + } -+ rargs->flags |= BTRFS_RESTRIPE_ARGS_CONVERT; ++ args->flags |= BTRFS_BALANCE_ARGS_CONVERT; + } else if (!strcmp(this_char, "soft")) { -+ rargs->flags |= BTRFS_RESTRIPE_ARGS_SOFT; ++ args->flags |= BTRFS_BALANCE_ARGS_SOFT; + } else { -+ fprintf(stderr, "Unrecognized restripe option '%s'\n", ++ fprintf(stderr, "Unrecognized balance option '%s'\n", + this_char); + return 1; + } @@ -229,26 +309,26 @@ index 1bfc669..e4c5592 100644 + return 0; +} + -+static void dump_ioctl_restripe_args(struct btrfs_ioctl_restripe_args *args); ++static void dump_ioctl_balance_args(struct btrfs_ioctl_balance_args *args); + -+static struct option restripe_longopts[] = { -+ { "data", 2, NULL, 'd'}, -+ { "metadata", 2, NULL, 'm' }, -+ { "system", 2, NULL, 's' }, -+ { "force", 0, NULL, 'f' }, -+ { "verbose", 0, NULL, 'v' }, ++static struct option balance_longopts[] = { ++ { "data", optional_argument, NULL, 'd'}, ++ { "metadata", optional_argument, NULL, 'm' }, ++ { "system", optional_argument, NULL, 's' }, ++ { "force", no_argument, NULL, 'f' }, ++ { "verbose", no_argument, NULL, 'v' }, + { 0, 0, 0, 0} +}; - ++ +/* + * [-d [filters]] [-m [filters]] [-s [filters]] [-vf] + */ -+int do_restripe(int ac, char **av) ++int do_balance(int argc, char **argv) +{ + int fd; + char *path; -+ struct btrfs_ioctl_restripe_args args; -+ struct btrfs_restripe_args *ptrs[] = { &args.data, &args.sys, ++ struct btrfs_ioctl_balance_args args; ++ struct btrfs_balance_args *ptrs[] = { &args.data, &args.sys, + &args.meta, NULL }; + int force = 0; + int verbose = 0; @@ -261,29 +341,29 @@ index 1bfc669..e4c5592 100644 + memset(&args, 0, sizeof(args)); + + while (1) { -+ int opt = getopt_long(ac, av, "d::s::m::fv", restripe_longopts, -+ &longindex); ++ int opt = getopt_long(argc, argv, "d::s::m::fv", ++ balance_longopts, &longindex); + if (opt < 0) + break; + + switch (opt) { + case 'd': + nofilters = 0; -+ args.flags |= BTRFS_RESTRIPE_DATA; ++ args.flags |= BTRFS_BALANCE_DATA; + + if (parse_filters(optarg, &args.data)) + return 1; + break; + case 's': + nofilters = 0; -+ args.flags |= BTRFS_RESTRIPE_SYSTEM; ++ args.flags |= BTRFS_BALANCE_SYSTEM; + + if (parse_filters(optarg, &args.sys)) + return 1; + break; + case 'm': + nofilters = 0; -+ args.flags |= BTRFS_RESTRIPE_METADATA; ++ args.flags |= BTRFS_BALANCE_METADATA; + + if (parse_filters(optarg, &args.meta)) + return 1; @@ -295,25 +375,42 @@ index 1bfc669..e4c5592 100644 + verbose = 1; + break; + default: -+ fprintf(stderr, "Invalid arguments for restripe\n"); ++ fprintf(stderr, "Invalid arguments for balance\n"); + return 1; + } + } + -+ if (ac - optind != 1) { -+ fprintf(stderr, "Invalid arguments for restripe\n"); ++ if (argc - optind != 1) { ++ fprintf(stderr, "Invalid arguments for balance\n"); + return 1; + } + ++ /* ++ * allow -s only under --force, otherwise do with system chunks ++ * the same thing we were ordered to do with meta chunks ++ */ ++ if (args.flags & BTRFS_BALANCE_SYSTEM) { ++ if (!force) { ++ fprintf(stderr, ++"Refusing to explicitly operate on system chunks.\n" ++"Pass --force if you really want to do that.\n"); ++ return 1; ++ } ++ } else if (args.flags & BTRFS_BALANCE_METADATA) { ++ args.flags |= BTRFS_BALANCE_SYSTEM; ++ memcpy(&args.sys, &args.meta, ++ sizeof(struct btrfs_balance_args)); ++ } ++ + if (nofilters) { + /* relocate everything - no filters */ -+ args.flags |= BTRFS_RESTRIPE_TYPE_MASK; ++ args.flags |= BTRFS_BALANCE_TYPE_MASK; + } + + /* drange makes sense only when devid is set */ + for (i = 0; ptrs[i]; i++) { -+ if ((ptrs[i]->flags & BTRFS_RESTRIPE_ARGS_DRANGE) && -+ !(ptrs[i]->flags & BTRFS_RESTRIPE_ARGS_DEVID)) { ++ if ((ptrs[i]->flags & BTRFS_BALANCE_ARGS_DRANGE) && ++ !(ptrs[i]->flags & BTRFS_BALANCE_ARGS_DEVID)) { + fprintf(stderr, "drange filter can be used only if " + "devid filter is used\n"); + return 1; @@ -322,15 +419,15 @@ index 1bfc669..e4c5592 100644 + + /* soft makes sense only when convert for corresponding type is set */ + for (i = 0; ptrs[i]; i++) { -+ if ((ptrs[i]->flags & BTRFS_RESTRIPE_ARGS_SOFT) && -+ !(ptrs[i]->flags & BTRFS_RESTRIPE_ARGS_CONVERT)) { ++ if ((ptrs[i]->flags & BTRFS_BALANCE_ARGS_SOFT) && ++ !(ptrs[i]->flags & BTRFS_BALANCE_ARGS_CONVERT)) { + fprintf(stderr, "'soft' option can be used only if " + "changing profiles\n"); + return 1; + } + } + -+ path = av[optind]; ++ path = argv[optind]; + fd = open_file_or_dir(path); + if (fd < 0) { + fprintf(stderr, "ERROR: can't access to '%s'\n", path); @@ -338,31 +435,41 @@ index 1bfc669..e4c5592 100644 + } + + if (force) -+ args.flags |= BTRFS_RESTRIPE_FORCE; ++ args.flags |= BTRFS_BALANCE_FORCE; + if (verbose) -+ dump_ioctl_restripe_args(&args); ++ dump_ioctl_balance_args(&args); + -+ ret = ioctl(fd, BTRFS_IOC_RESTRIPE, &args); ++ ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, &args); + e = errno; + close(fd); + + if (ret < 0) { + if (e == ECANCELED) { -+ fprintf(stderr, "restripe interrupted by user\n"); ++ if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ) ++ fprintf(stderr, "balance paused by user\n"); ++ if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ) ++ fprintf(stderr, "balance canceled by user\n"); + } else { -+ fprintf(stderr, "ERROR: error during restriping '%s' " ++ fprintf(stderr, "ERROR: error during balancing '%s' " + "- %s\n", path, strerror(e)); ++ if (e != EINPROGRESS) ++ fprintf(stderr, "There may be more info in " ++ "syslog - try dmesg | tail\n"); + return 19; + } ++ } else { ++ printf("Done, had to relocate %llu out of %llu chunks\n", ++ (unsigned long long)args.stat.completed, ++ (unsigned long long)args.stat.considered); + } + + return 0; +} + -+int do_restripe_cancel(int ac, char **av) ++int do_balance_pause(int argc, char **argv) +{ + int fd; -+ char *path = av[1]; ++ char *path = argv[1]; + int ret; + int e; + @@ -372,38 +479,12 @@ index 1bfc669..e4c5592 100644 + return 12; + } + -+ ret = ioctl(fd, BTRFS_IOC_RESTRIPE_CTL, BTRFS_RESTRIPE_CTL_CANCEL); ++ ret = ioctl(fd, BTRFS_IOC_BALANCE_CTL, BTRFS_BALANCE_CTL_PAUSE); + e = errno; + close(fd); + + if (ret < 0) { -+ fprintf(stderr, "ERROR: restripe cancel on '%s' failed - %s\n", -+ path, (e == ENOTCONN) ? "Not in progress" : strerror(e)); -+ return 19; -+ } -+ -+ return 0; -+} -+ -+int do_restripe_pause(int ac, char **av) -+{ -+ int fd; -+ char *path = av[1]; -+ int ret; -+ int e; -+ -+ fd = open_file_or_dir(path); -+ if (fd < 0) { -+ fprintf(stderr, "ERROR: can't access to '%s'\n", path); -+ return 12; -+ } -+ -+ ret = ioctl(fd, BTRFS_IOC_RESTRIPE_CTL, BTRFS_RESTRIPE_CTL_PAUSE); -+ e = errno; -+ close(fd); -+ -+ if (ret < 0) { -+ fprintf(stderr, "ERROR: restripe pause on '%s' failed - %s\n", ++ fprintf(stderr, "ERROR: balance pause on '%s' failed - %s\n", + path, (e == ENOTCONN) ? "Not running" : strerror(e)); + return 19; + } @@ -411,10 +492,10 @@ index 1bfc669..e4c5592 100644 + return 0; +} + -+int do_restripe_resume(int ac, char **av) ++int do_balance_cancel(int argc, char **argv) +{ + int fd; -+ char *path = av[1]; ++ char *path = argv[1]; + int ret; + int e; + @@ -424,47 +505,85 @@ index 1bfc669..e4c5592 100644 + return 12; + } + -+ ret = ioctl(fd, BTRFS_IOC_RESTRIPE_CTL, BTRFS_RESTRIPE_CTL_RESUME); ++ ret = ioctl(fd, BTRFS_IOC_BALANCE_CTL, BTRFS_BALANCE_CTL_CANCEL); + e = errno; + close(fd); + + if (ret < 0) { -+ if (e == ECANCELED) { -+ fprintf(stderr, "restripe interrupted by user\n"); -+ } else if (e == ENOTCONN || e == EINPROGRESS) { -+ fprintf(stderr, "ERROR: restripe resume on '%s' " -+ "failed - %s\n", path, -+ (e == ENOTCONN) ? "Not in progress" : -+ "Already running"); -+ return 19; -+ } else { -+ fprintf(stderr, "ERROR: error during restriping '%s' " -+ "- %s\n", path, strerror(e)); -+ return 19; -+ } ++ fprintf(stderr, "ERROR: balance cancel on '%s' failed - %s\n", ++ path, (e == ENOTCONN) ? "Not in progress" : strerror(e)); ++ return 19; + } + + return 0; +} + -+static struct option restripe_progress_longopts[] = { -+ { "verbose", 0, NULL, 'v' }, ++int do_balance_resume(int argc, char **argv) ++{ ++ int fd; ++ char *path = argv[1]; ++ struct btrfs_ioctl_balance_args args; ++ int ret; ++ int e; ++ ++ fd = open_file_or_dir(path); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: can't access to '%s'\n", path); ++ return 12; ++ } ++ ++ memset(&args, 0, sizeof(args)); ++ args.flags |= BTRFS_BALANCE_RESUME; ++ ++ ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, &args); ++ e = errno; ++ close(fd); ++ ++ if (ret < 0) { ++ if (e == ECANCELED) { ++ if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ) ++ fprintf(stderr, "balance paused by user\n"); ++ if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ) ++ fprintf(stderr, "balance canceled by user\n"); ++ } else if (e == ENOTCONN || e == EINPROGRESS) { ++ fprintf(stderr, "ERROR: balance resume on '%s' " ++ "failed - %s\n", path, ++ (e == ENOTCONN) ? "Not in progress" : ++ "Already running"); ++ return 19; ++ } else { ++ fprintf(stderr, ++"ERROR: error during balancing '%s' - %s\n" ++"There may be more info in syslog - try dmesg | tail\n", path, strerror(e)); ++ return 19; ++ } ++ } else { ++ printf("Done, had to relocate %llu out of %llu chunks\n", ++ (unsigned long long)args.stat.completed, ++ (unsigned long long)args.stat.considered); ++ } ++ ++ return 0; ++} ++ ++static struct option balance_progress_longopts[] = { ++ { "verbose", no_argument, NULL, 'v' }, + { 0, 0, 0, 0} +}; + -+int do_restripe_progress(int ac, char **av) ++int do_balance_progress(int argc, char **argv) +{ + int fd; + char *path; -+ struct btrfs_ioctl_restripe_args args; ++ struct btrfs_ioctl_balance_args args; + int verbose = 0; + int longindex; + int ret; + int e; + + while (1) { -+ int opt = getopt_long(ac, av, "v", restripe_progress_longopts, -+ &longindex); ++ int opt = getopt_long(argc, argv, "v", ++ balance_progress_longopts, &longindex); + if (opt < 0) + break; + @@ -473,157 +592,200 @@ index 1bfc669..e4c5592 100644 + verbose = 1; + break; + default: -+ fprintf(stderr, "Invalid arguments for restripe " ++ fprintf(stderr, "Invalid arguments for balance " + "status\n"); + return 1; + } + } + -+ if (ac - optind != 1) { -+ fprintf(stderr, "Invalid arguments for restripe status\n"); ++ if (argc - optind != 1) { ++ fprintf(stderr, "Invalid arguments for balance status\n"); + return 1; + } + -+ path = av[optind]; ++ path = argv[optind]; + fd = open_file_or_dir(path); + if (fd < 0) { + fprintf(stderr, "ERROR: can't access to '%s'\n", path); + return 12; + } + -+ ret = ioctl(fd, BTRFS_IOC_RESTRIPE_PROGRESS, &args); ++ ret = ioctl(fd, BTRFS_IOC_BALANCE_PROGRESS, &args); + e = errno; + close(fd); + + if (ret < 0) { -+ fprintf(stderr, "ERROR: restripe status on '%s' failed - %s\n", ++ fprintf(stderr, "ERROR: balance status on '%s' failed - %s\n", + path, (e == ENOTCONN) ? "Not in progress" : strerror(e)); - return 19; - } ++ return 19; ++ } + -+ if (args.state & BTRFS_RESTRIPE_ST_RUNNING) { -+ printf("Restripe on '%s' is running", path); -+ if (args.state & BTRFS_RESTRIPE_ST_CANCEL_REQ) ++ if (args.state & BTRFS_BALANCE_STATE_RUNNING) { ++ printf("Balance on '%s' is running", path); ++ if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ) + printf(", cancel requested\n"); -+ else if (args.state & BTRFS_RESTRIPE_ST_PAUSE_REQ) ++ else if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ) + printf(", pause requested\n"); + else + printf("\n"); + } else { -+ printf("Restripe on '%s' is paused\n", path); ++ printf("Balance on '%s' is paused\n", path); + } + -+ printf("%llu out of about %llu chunks restriped (%llu considered), " -+ "%3.f%% left\n", args.stat.completed, args.stat.expected, -+ args.stat.considered, ++ printf("%llu out of about %llu chunks balanced (%llu considered), " ++ "%3.f%% left\n", (unsigned long long)args.stat.completed, ++ (unsigned long long)args.stat.expected, ++ (unsigned long long)args.stat.considered, + 100 * (1 - (float)args.stat.completed/args.stat.expected)); + + if (verbose) -+ dump_ioctl_restripe_args(&args); ++ dump_ioctl_balance_args(&args); + - return 0; - } - -+static void dump_restripe_args(struct btrfs_restripe_args *args) ++ return 0; ++} ++ ++static void dump_balance_args(struct btrfs_balance_args *args) +{ -+ if (args->flags & BTRFS_RESTRIPE_ARGS_CONVERT) { -+ printf("converting, target=%llu, soft is %s", args->target, -+ (args->flags & BTRFS_RESTRIPE_ARGS_SOFT) ? "on" : "off"); ++ if (args->flags & BTRFS_BALANCE_ARGS_CONVERT) { ++ printf("converting, target=%llu, soft is %s", ++ (unsigned long long)args->target, ++ (args->flags & BTRFS_BALANCE_ARGS_SOFT) ? "on" : "off"); + } else { + printf("balancing"); + } + -+ if (args->flags & BTRFS_RESTRIPE_ARGS_PROFILES) -+ printf(", profiles=%llu", args->profiles); -+ if (args->flags & BTRFS_RESTRIPE_ARGS_USAGE) -+ printf(", usage=%llu", args->usage); -+ if (args->flags & BTRFS_RESTRIPE_ARGS_DEVID) -+ printf(", devid=%llu", args->devid); -+ if (args->flags & BTRFS_RESTRIPE_ARGS_DRANGE) -+ printf(", drange=%llu..%llu", args->pstart, args->pend); -+ if (args->flags & BTRFS_RESTRIPE_ARGS_VRANGE) -+ printf(", vrange=%llu..%llu", args->vstart, args->vend); ++ if (args->flags & BTRFS_BALANCE_ARGS_PROFILES) ++ printf(", profiles=%llu", (unsigned long long)args->profiles); ++ if (args->flags & BTRFS_BALANCE_ARGS_USAGE) ++ printf(", usage=%llu", (unsigned long long)args->usage); ++ if (args->flags & BTRFS_BALANCE_ARGS_DEVID) ++ printf(", devid=%llu", (unsigned long long)args->devid); ++ if (args->flags & BTRFS_BALANCE_ARGS_DRANGE) ++ printf(", drange=%llu..%llu", ++ (unsigned long long)args->pstart, ++ (unsigned long long)args->pend); ++ if (args->flags & BTRFS_BALANCE_ARGS_VRANGE) ++ printf(", vrange=%llu..%llu", ++ (unsigned long long)args->vstart, ++ (unsigned long long)args->vend); + + printf("\n"); +} + -+static void dump_ioctl_restripe_args(struct btrfs_ioctl_restripe_args *args) ++static void dump_ioctl_balance_args(struct btrfs_ioctl_balance_args *args) +{ + printf("Dumping filters: flags 0x%llx, state 0x%llx, force is %s\n", -+ args->flags, args->state, -+ (args->flags & BTRFS_RESTRIPE_FORCE) ? "on" : "off"); -+ if (args->flags & BTRFS_RESTRIPE_DATA) { -+ printf(" DATA (flags 0x%llx): ", args->data.flags); -+ dump_restripe_args(&args->data); ++ (unsigned long long)args->flags, (unsigned long long)args->state, ++ (args->flags & BTRFS_BALANCE_FORCE) ? "on" : "off"); ++ if (args->flags & BTRFS_BALANCE_DATA) { ++ printf(" DATA (flags 0x%llx): ", ++ (unsigned long long)args->data.flags); ++ dump_balance_args(&args->data); + } -+ if (args->flags & BTRFS_RESTRIPE_METADATA) { -+ printf(" METADATA (flags 0x%llx): ", args->meta.flags); -+ dump_restripe_args(&args->meta); ++ if (args->flags & BTRFS_BALANCE_METADATA) { ++ printf(" METADATA (flags 0x%llx): ", ++ (unsigned long long)args->meta.flags); ++ dump_balance_args(&args->meta); + } -+ if (args->flags & BTRFS_RESTRIPE_SYSTEM) { -+ printf(" SYSTEM (flags 0x%llx): ", args->sys.flags); -+ dump_restripe_args(&args->sys); ++ if (args->flags & BTRFS_BALANCE_SYSTEM) { ++ printf(" SYSTEM (flags 0x%llx): ", ++ (unsigned long long)args->sys.flags); ++ dump_balance_args(&args->sys); + } +} ++ - - /**** man: btrfs device delete -diff --git a/btrfs_cmds.h b/btrfs_cmds.h -index 81182b1..2cd0ac1 100644 ---- a/btrfs_cmds.h -+++ b/btrfs_cmds.h -@@ -27,6 +27,11 @@ int do_scrub_start(int nargs, char **argv); + /**** man: btrfs filesystem label + * +Index: btrfs-progs-v0.19-118-gfdb6c04/btrfs_cmds.h +=================================================================== +--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfs_cmds.h ++++ btrfs-progs-v0.19-118-gfdb6c04/btrfs_cmds.h +@@ -22,12 +22,16 @@ int do_fssync(int nargs, char **argv); + int do_defrag(int argc, char **argv); + int do_show_filesystem(int nargs, char **argv); + int do_add_volume(int nargs, char **args); +-int do_balance(int nargs, char **argv); ++int do_remove_volume(int nargs, char **args); ++int do_balance(int argc, char **argv); ++int do_balance_pause(int argc, char **argv); ++int do_balance_cancel(int argc, char **argv); ++int do_balance_resume(int argc, char **argv); ++int do_balance_progress(int argc, char **argv); + int do_scrub_start(int nargs, char **argv); int do_scrub_status(int argc, char **argv); int do_scrub_resume(int argc, char **argv); int do_scrub_cancel(int nargs, char **argv); -+int do_restripe(int ac, char **av); -+int do_restripe_cancel(int ac, char **av); -+int do_restripe_pause(int ac, char **av); -+int do_restripe_resume(int ac, char **av); -+int do_restripe_progress(int ac, char **av); - int do_remove_volume(int nargs, char **args); +-int do_remove_volume(int nargs, char **args); int do_scan(int nargs, char **argv); int do_resize(int nargs, char **argv); -diff --git a/ctree.h b/ctree.h -index 54748c8..58ea3d3 100644 ---- a/ctree.h -+++ b/ctree.h + int do_subvol_list(int nargs, char **argv); +Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h +=================================================================== +--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h ++++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h @@ -61,6 +61,9 @@ struct btrfs_trans_handle; #define BTRFS_CSUM_TREE_OBJECTID 7ULL -+/* for storing restripe params in the root tree */ -+#define BTRFS_RESTRIPE_OBJECTID -4ULL ++/* for storing balance parameters in the root tree */ ++#define BTRFS_BALANCE_OBJECTID -4ULL + /* oprhan objectid for tracking unlinked/truncated files */ #define BTRFS_ORPHAN_OBJECTID -5ULL -@@ -705,6 +708,12 @@ struct btrfs_csum_item { - #define BTRFS_BLOCK_GROUP_DUP (1 << 5) - #define BTRFS_BLOCK_GROUP_RAID10 (1 << 6) +@@ -697,13 +700,17 @@ struct btrfs_csum_item { + } __attribute__ ((__packed__)); -+/* -+ * to avoid troubles.. -+ */ -+#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1 << 7) -+#define BTRFS_BLOCK_GROUP_RESERVED (1 << 7) + /* tag for the radix tree of block groups in ram */ +-#define BTRFS_BLOCK_GROUP_DATA (1 << 0) +-#define BTRFS_BLOCK_GROUP_SYSTEM (1 << 1) +-#define BTRFS_BLOCK_GROUP_METADATA (1 << 2) +-#define BTRFS_BLOCK_GROUP_RAID0 (1 << 3) +-#define BTRFS_BLOCK_GROUP_RAID1 (1 << 4) +-#define BTRFS_BLOCK_GROUP_DUP (1 << 5) +-#define BTRFS_BLOCK_GROUP_RAID10 (1 << 6) ++#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) ++#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) ++#define BTRFS_BLOCK_GROUP_METADATA (1ULL << 2) ++#define BTRFS_BLOCK_GROUP_RAID0 (1ULL << 3) ++#define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4) ++#define BTRFS_BLOCK_GROUP_DUP (1ULL << 5) ++#define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6) ++#define BTRFS_BLOCK_GROUP_RESERVED BTRFS_AVAIL_ALLOC_BIT_SINGLE + ++/* used in struct btrfs_balance_args fields */ ++#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) + struct btrfs_block_group_item { __le64 used; - __le64 chunk_objectid; -diff --git a/ioctl.h b/ioctl.h -index 1ae7537..af8b18b 100644 ---- a/ioctl.h -+++ b/ioctl.h -@@ -91,6 +91,45 @@ struct btrfs_ioctl_fs_info_args { +@@ -911,6 +918,8 @@ struct btrfs_root { + #define BTRFS_DEV_ITEM_KEY 216 + #define BTRFS_CHUNK_ITEM_KEY 228 + ++#define BTRFS_BALANCE_ITEM_KEY 248 ++ + /* + * string items are for debugging. They just store a short string of + * data in the FS +Index: btrfs-progs-v0.19-118-gfdb6c04/ioctl.h +=================================================================== +--- btrfs-progs-v0.19-118-gfdb6c04.orig/ioctl.h ++++ btrfs-progs-v0.19-118-gfdb6c04/ioctl.h +@@ -91,6 +91,54 @@ struct btrfs_ioctl_fs_info_args { __u64 reserved[124]; /* pad to 1k */ }; -+#define BTRFS_RESTRIPE_CTL_CANCEL 1 -+#define BTRFS_RESTRIPE_CTL_PAUSE 2 -+#define BTRFS_RESTRIPE_CTL_RESUME 3 ++/* balance control ioctl modes */ ++#define BTRFS_BALANCE_CTL_PAUSE 1 ++#define BTRFS_BALANCE_CTL_CANCEL 2 ++#define BTRFS_BALANCE_CTL_RESUME 3 + -+struct btrfs_restripe_args { ++/* ++ * this is packed, because it should be exactly the same as its disk ++ * byte order counterpart (struct btrfs_disk_balance_args) ++ */ ++struct btrfs_balance_args { + __u64 profiles; + __u64 usage; + __u64 devid; @@ -639,112 +801,107 @@ index 1ae7537..af8b18b 100644 + __u64 unused[8]; +} __attribute__ ((__packed__)); + -+struct btrfs_restripe_progress { ++struct btrfs_balance_progress { + __u64 expected; + __u64 considered; + __u64 completed; +}; + -+struct btrfs_ioctl_restripe_args { -+ __u64 flags; -+ __u64 state; ++#define BTRFS_BALANCE_STATE_RUNNING (1ULL << 0) ++#define BTRFS_BALANCE_STATE_PAUSE_REQ (1ULL << 1) ++#define BTRFS_BALANCE_STATE_CANCEL_REQ (1ULL << 2) + -+ struct btrfs_restripe_args data; -+ struct btrfs_restripe_args sys; -+ struct btrfs_restripe_args meta; ++struct btrfs_ioctl_balance_args { ++ __u64 flags; /* in/out */ ++ __u64 state; /* out */ + -+ struct btrfs_restripe_progress stat; ++ struct btrfs_balance_args data; /* in/out */ ++ struct btrfs_balance_args meta; /* in/out */ ++ struct btrfs_balance_args sys; /* in/out */ + -+ __u64 unused[72]; /* pad to 1k */ ++ struct btrfs_balance_progress stat; /* out */ ++ ++ __u64 unused[72]; /* pad to 1k */ +}; + struct btrfs_ioctl_search_key { /* which root are we searching. 0 is the tree of tree roots */ __u64 tree_id; -@@ -272,10 +311,15 @@ struct btrfs_ioctl_logical_ino_args { - #define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \ +@@ -284,6 +332,11 @@ struct btrfs_ioctl_compr_size_args { struct btrfs_ioctl_dev_info_args) #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ -- struct btrfs_ioctl_fs_info_args) -+ struct btrfs_ioctl_fs_info_args) + struct btrfs_ioctl_fs_info_args) ++#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \ ++ struct btrfs_ioctl_balance_args) ++#define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int) ++#define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \ ++ struct btrfs_ioctl_balance_args) #define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \ struct btrfs_ioctl_ino_path_args) #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ - struct btrfs_ioctl_ino_path_args) - -+#define BTRFS_IOC_RESTRIPE _IOW(BTRFS_IOCTL_MAGIC, 32, \ -+ struct btrfs_ioctl_restripe_args) -+#define BTRFS_IOC_RESTRIPE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int) -+#define BTRFS_IOC_RESTRIPE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \ -+ struct btrfs_ioctl_restripe_args) - #endif -diff --git a/print-tree.c b/print-tree.c -index 6039699..49f98af 100644 ---- a/print-tree.c -+++ b/print-tree.c -@@ -391,6 +391,9 @@ static void print_objectid(unsigned long long objectid, u8 type) +Index: btrfs-progs-v0.19-118-gfdb6c04/print-tree.c +=================================================================== +--- btrfs-progs-v0.19-118-gfdb6c04.orig/print-tree.c ++++ btrfs-progs-v0.19-118-gfdb6c04/print-tree.c +@@ -351,6 +351,9 @@ static void print_key_type(u8 type) + case BTRFS_DEV_EXTENT_KEY: + printf("DEV_EXTENT"); + break; ++ case BTRFS_BALANCE_ITEM_KEY: ++ printf("BALANCE_ITEM"); ++ break; + case BTRFS_STRING_ITEM_KEY: + printf("STRING_ITEM"); + break; +@@ -391,6 +394,9 @@ static void print_objectid(unsigned long case BTRFS_CSUM_TREE_OBJECTID: printf("CSUM_TREE"); break; -+ case BTRFS_RESTRIPE_OBJECTID: -+ printf("RESTRIPE"); ++ case BTRFS_BALANCE_OBJECTID: ++ printf("BALANCE"); + break; case BTRFS_ORPHAN_OBJECTID: printf("ORPHAN"); break; -diff --git a/volumes.h b/volumes.h -index 7104d36..6929aca 100644 ---- a/volumes.h -+++ b/volumes.h -@@ -91,6 +91,48 @@ struct btrfs_multi_bio { +Index: btrfs-progs-v0.19-118-gfdb6c04/volumes.h +=================================================================== +--- btrfs-progs-v0.19-118-gfdb6c04.orig/volumes.h ++++ btrfs-progs-v0.19-118-gfdb6c04/volumes.h +@@ -91,6 +91,37 @@ struct btrfs_multi_bio { #define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \ (sizeof(struct btrfs_bio_stripe) * (n))) +/* -+ * Restriper's general "type" filter. Shares bits with chunk type for -+ * simplicity, RESTRIPE prefix is used to avoid confusion. ++ * Restriper's general type filter + */ -+#define BTRFS_RESTRIPE_DATA (1ULL << 0) -+#define BTRFS_RESTRIPE_SYSTEM (1ULL << 1) -+#define BTRFS_RESTRIPE_METADATA (1ULL << 2) ++#define BTRFS_BALANCE_DATA (1ULL << 0) ++#define BTRFS_BALANCE_SYSTEM (1ULL << 1) ++#define BTRFS_BALANCE_METADATA (1ULL << 2) + -+#define BTRFS_RESTRIPE_TYPE_MASK (BTRFS_RESTRIPE_DATA | \ -+ BTRFS_RESTRIPE_SYSTEM | \ -+ BTRFS_RESTRIPE_METADATA) ++#define BTRFS_BALANCE_TYPE_MASK (BTRFS_BALANCE_DATA | \ ++ BTRFS_BALANCE_SYSTEM | \ ++ BTRFS_BALANCE_METADATA) + -+#define BTRFS_RESTRIPE_FORCE (1ULL << 3) ++#define BTRFS_BALANCE_FORCE (1ULL << 3) ++#define BTRFS_BALANCE_RESUME (1ULL << 4) + +/* -+ * Restripe filters ++ * Balance filters + */ -+#define BTRFS_RESTRIPE_ARGS_PROFILES (1ULL << 0) -+#define BTRFS_RESTRIPE_ARGS_USAGE (1ULL << 1) -+#define BTRFS_RESTRIPE_ARGS_DEVID (1ULL << 2) -+#define BTRFS_RESTRIPE_ARGS_DRANGE (1ULL << 3) -+#define BTRFS_RESTRIPE_ARGS_VRANGE (1ULL << 4) ++#define BTRFS_BALANCE_ARGS_PROFILES (1ULL << 0) ++#define BTRFS_BALANCE_ARGS_USAGE (1ULL << 1) ++#define BTRFS_BALANCE_ARGS_DEVID (1ULL << 2) ++#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3) ++#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4) + +/* + * Profile changing flags. When SOFT is set we won't relocate chunk if + * it already has the target profile (even though it may be + * half-filled). + */ -+#define BTRFS_RESTRIPE_ARGS_CONVERT (1ULL << 8) -+#define BTRFS_RESTRIPE_ARGS_SOFT (1ULL << 9) -+ -+/* -+ * Restripe state bits -+ */ -+#define RESTRIPE_RUNNING 0 -+#define RESTRIPE_CANCEL_REQ 1 -+#define RESTRIPE_PAUSE_REQ 2 -+ -+#define BTRFS_RESTRIPE_ST_RUNNING (1ULL << RESTRIPE_RUNNING) -+#define BTRFS_RESTRIPE_ST_CANCEL_REQ (1ULL << RESTRIPE_CANCEL_REQ) -+#define BTRFS_RESTRIPE_ST_PAUSE_REQ (1ULL << RESTRIPE_PAUSE_REQ) ++#define BTRFS_BALANCE_ARGS_CONVERT (1ULL << 8) ++#define BTRFS_BALANCE_ARGS_SOFT (1ULL << 9) + int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 chunk_tree, u64 chunk_objectid, --- -1.7.6.233.gd79bc - diff --git a/0114-btrfs-progs-Add-ioctl-to-read-compressed-size-of-a-f.patch b/0114-btrfs-progs-Add-ioctl-to-read-compressed-size-of-a-f.patch new file mode 100644 index 0000000..570a68c --- /dev/null +++ b/0114-btrfs-progs-Add-ioctl-to-read-compressed-size-of-a-f.patch @@ -0,0 +1,181 @@ +From 72218a2090e1cbafe9baa97aaa465a28438c3dbb Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Mon, 19 Dec 2011 17:51:11 +0100 +Subject: [PATCH 16/43] btrfs-progs: Add ioctl to read compressed size of a + file + +Signed-off-by: David Sterba +--- + btrfs.c | 9 ++++++- + btrfs_cmds.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + btrfs_cmds.h | 1 + + ioctl.h | 13 ++++++++++ + man/btrfs.8.in.old | 10 +++++++ + 5 files changed, 100 insertions(+), 1 deletions(-) + +diff --git a/btrfs.c b/btrfs.c +index e78f194..f5b8fd4 100644 +--- a/btrfs.c ++++ b/btrfs.c +@@ -325,7 +325,14 @@ static struct Command commands[] = { + "filesystem label", " []\n" + "With one argument, get the label of filesystem on .\n" + "If is passed, set the filesystem label to .\n" +- "The filesystem must be unmounted.\n" ++ "The filesystem must be unmounted." ++ }, ++ { do_compr_size, -1, ++ "filesystem csize", "[-s start] [-e end] \n" ++ "Read ordinary and compressed size of extents in the range [start,end)\n" ++ "-s start range start inclusive, accepts K/M/G modifiers\n" ++ "-e end range end exclusive, accepts K/M/G modifiers\n", ++ NULL + }, + { do_scrub_start, -1, + "scrub start", "[-Bdqr] |\n" +diff --git a/btrfs_cmds.c b/btrfs_cmds.c +index 12346e5..c8196d1 100644 +--- a/btrfs_cmds.c ++++ b/btrfs_cmds.c +@@ -2058,3 +2058,71 @@ out: + free(inodes); + return ret; + } ++ ++int do_compr_size(int argc, char **argv) ++{ ++ int ret; ++ int fd; ++ struct btrfs_ioctl_compr_size_args args; ++ ++ args.start = 0; ++ args.end = (u64)-1; ++ optind = 1; ++ while (1) { ++ int c = getopt(argc, argv, "s:e:r"); ++ if (c < 0) ++ break; ++ switch (c) { ++ case 's': ++ args.start = parse_size(optarg); ++ break; ++ case 'e': ++ args.end = parse_size(optarg); ++ break; ++ default: ++ fprintf(stderr, "ERROR: Invalid arguments for csize\n"); ++ return 1; ++ } ++ } ++ ++ if (args.start > args.end) { ++ fprintf(stderr, "ERROR: Invalid range for csize\n"); ++ return 1; ++ } ++ ++ if (argc - optind == 0) { ++ fprintf(stderr, "ERROR: Invalid arguments for csize\n"); ++ return 1; ++ } ++ argc -= optind; ++ ++ fd = open_file_or_dir(argv[optind]); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]); ++ return 1; ++ } ++ ++ ret = ioctl(fd, BTRFS_IOC_COMPR_SIZE, &args); ++ if (ret < 0) { ++ fprintf(stderr, "ERROR: ioctl returned %d, errno %d %s\n", ++ ret, errno, strerror(errno)); ++ return errno; ++ } ++ ++ printf("File name: %s\n", argv[optind]); ++ if (args.end == (u64)-1) ++ printf("File range: %llu-EOF\n", ++ (unsigned long long)args.start); ++ else ++ printf("File range: %llu-%llu\n", ++ (unsigned long long)args.start, ++ (unsigned long long)args.end); ++ ++ printf("Compressed size: %llu\n", ++ (unsigned long long)(args.compressed_size << 9)); ++ printf("Uncompressed size: %llu\n", ++ (unsigned long long)(args.size << 9)); ++ printf("Ratio: %3.2f%%\n", ++ 100.0 * args.compressed_size / args.size); ++ return 0; ++} +diff --git a/btrfs_cmds.h b/btrfs_cmds.h +index 53d51d6..07dad7a 100644 +--- a/btrfs_cmds.h ++++ b/btrfs_cmds.h +@@ -46,3 +46,4 @@ int open_file_or_dir(const char *fname); + int do_ino_to_path(int nargs, char **argv); + int do_logical_to_ino(int nargs, char **argv); + char *path_for_root(int fd, u64 root); ++int do_compr_size(int argc, char **argv); +diff --git a/ioctl.h b/ioctl.h +index 78aebce..a820098 100644 +--- a/ioctl.h ++++ b/ioctl.h +@@ -272,6 +272,17 @@ struct btrfs_ioctl_logical_ino_args { + __u64 inodes; + }; + ++struct btrfs_ioctl_compr_size_args { ++ /* Range start, inclusive */ ++ __u64 start; /* in */ ++ /* Range end, exclusive */ ++ __u64 end; /* in */ ++ __u64 size; /* out */ ++ __u64 compressed_size; /* out */ ++ __u64 reserved[2]; ++}; ++ ++ + /* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */ + #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ + struct btrfs_ioctl_vol_args) +@@ -330,5 +341,7 @@ struct btrfs_ioctl_logical_ino_args { + struct btrfs_ioctl_ino_path_args) + #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ + struct btrfs_ioctl_ino_path_args) ++#define BTRFS_IOC_COMPR_SIZE _IOR(BTRFS_IOCTL_MAGIC, 51, \ ++ struct btrfs_ioctl_compr_size_args) + + #endif +diff --git a/man/btrfs.8.in.old b/man/btrfs.8.in.old +index be478e0..b7dacea 100644 +--- a/man/btrfs.8.in.old ++++ b/man/btrfs.8.in.old +@@ -31,6 +31,8 @@ btrfs \- control a btrfs filesystem + .PP + \fBbtrfs\fP \fBfilesystem defragment\fP\fI | [|...]\fP + .PP ++\fBbtrfs\fP \fBfilesystem csize \fP\fI [-s start] [-e end] \fP ++.PP + \fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices| [...]]\fP + .PP + \fBbtrfs\fP \fBdevice show\fP\fI [--all-devices||