diff --git a/0001-Btrfs-progs-fix-check-to-test-trim-support.patch b/0001-Btrfs-progs-fix-check-to-test-trim-support.patch new file mode 100644 index 0000000..6784929 --- /dev/null +++ b/0001-Btrfs-progs-fix-check-to-test-trim-support.patch @@ -0,0 +1,30 @@ +From f7025683c14debd0ca3ee21dc64699a185849b35 Mon Sep 17 00:00:00 2001 +From: Rakesh Pandit +Date: Tue, 22 Apr 2014 16:30:27 +0300 +Subject: [PATCH 03/42] Btrfs-progs: fix check to test trim support + +It was added in 25d82d22 but broke recently in 4724d7b0 while making +discard interruptible. + +Signed-off-by: Rakesh Pandit +Signed-off-by: David Sterba +--- + utils.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/utils.c b/utils.c +index 3e9c527a492c..187ad3b9b12b 100644 +--- a/utils.c ++++ b/utils.c +@@ -626,7 +626,7 @@ int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret, + * is not necessary for the mkfs functionality but just an + * optimization. + */ +- if (discard_blocks(fd, 0, 0) == 0) { ++ if (discard_range(fd, 0, 0) == 0) { + fprintf(stderr, "Performing full device TRIM (%s) ...\n", + pretty_size(block_count)); + discard_blocks(fd, 0, block_count); +-- +1.9.0 + diff --git a/0002-Btrfs-progs-fsck-fix-double-free-memory-crash.patch b/0002-Btrfs-progs-fsck-fix-double-free-memory-crash.patch new file mode 100644 index 0000000..4a419ed --- /dev/null +++ b/0002-Btrfs-progs-fsck-fix-double-free-memory-crash.patch @@ -0,0 +1,35 @@ +From 4c92a4a31b51950d8d0f167a0391586803802f4c Mon Sep 17 00:00:00 2001 +From: Rakesh Pandit +Date: Sun, 20 Apr 2014 16:17:53 +0300 +Subject: [PATCH 08/42] Btrfs-progs: fsck: fix double free memory crash + +Fix double free of memory if btrfs_open_devices fails: +*** Error in `btrfs': double free or corruption (fasttop): 0x000000000066e020 *** + +Crash happened because when open failed on device inside +btrfs_open_devices it freed all memory by calling btrfs_close_devices but +inside disk-io.c we call btrfs_close_again it again. + +Signed-off-by: Rakesh Pandit +Signed-off-by: David Sterba +--- + disk-io.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/disk-io.c b/disk-io.c +index 19b95a724f1b..8db0335bc81b 100644 +--- a/disk-io.c ++++ b/disk-io.c +@@ -1091,8 +1091,7 @@ static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, + + ret = btrfs_open_devices(fs_devices, oflags); + if (ret) +- goto out_devices; +- ++ goto out; + + disk_super = fs_info->super_copy; + if (!(flags & OPEN_CTREE_RECOVER_SUPER)) +-- +1.9.0 + diff --git a/0003-Btrfs-progs-mkfs-Remove-zero_end-1-since-it-has-been.patch b/0003-Btrfs-progs-mkfs-Remove-zero_end-1-since-it-has-been.patch new file mode 100644 index 0000000..6eea32d --- /dev/null +++ b/0003-Btrfs-progs-mkfs-Remove-zero_end-1-since-it-has-been.patch @@ -0,0 +1,44 @@ +From e7cd3d7fa55bb26d9b4579fececc863db6555d97 Mon Sep 17 00:00:00 2001 +From: Li Yang +Date: Mon, 21 Apr 2014 05:38:08 -0400 +Subject: [PATCH 09/42] Btrfs-progs: mkfs: Remove 'zero_end =1' since it has + been set to a value + +In utils.c, zero_end is used as a parameter, should not force it to 1. +In mkfs.c, zero_end is set to 1 or 0(-b) at the beginning, should not +force it to 1 unconditionally. + +Signed-off-by: Li Yang +Signed-off-by: David Sterba +--- + mkfs.c | 1 - + utils.c | 1 - + 2 files changed, 2 deletions(-) + +diff --git a/mkfs.c b/mkfs.c +index dbd83f5ce168..f2b577922c9e 100644 +--- a/mkfs.c ++++ b/mkfs.c +@@ -1543,7 +1543,6 @@ int main(int ac, char **av) + + btrfs_register_one_device(file); + +- zero_end = 1; + while (dev_cnt-- > 0) { + int old_mixed = mixed; + +diff --git a/utils.c b/utils.c +index 44c0e4ab39f2..29953d9dd2a9 100644 +--- a/utils.c ++++ b/utils.c +@@ -613,7 +613,6 @@ int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret, + } + if (max_block_count) + block_count = min(block_count, max_block_count); +- zero_end = 1; + + if (block_count < 1024 * 1024 * 1024 && !(*mixed)) { + printf("SMALL VOLUME: forcing mixed metadata/data groups\n"); +-- +1.9.0 + diff --git a/0004-btrfs-progs-fix-wrong-max-system-array-size-check-in.patch b/0004-btrfs-progs-fix-wrong-max-system-array-size-check-in.patch new file mode 100644 index 0000000..c457c54 --- /dev/null +++ b/0004-btrfs-progs-fix-wrong-max-system-array-size-check-in.patch @@ -0,0 +1,34 @@ +From b014a6150ebaa97cee780fca184df626c173c30e Mon Sep 17 00:00:00 2001 +From: Gui Hecheng +Date: Mon, 21 Apr 2014 20:13:31 +0800 +Subject: [PATCH 10/42] btrfs-progs: fix wrong max system array size check in + user space + +For system chunk array, +We copy a "disk_key" and an chunk item each time, +so there should be enough space to hold both of them, +not only the chunk item. + +Signed-off-by: Gui Hecheng +Signed-off-by: David Sterba +--- + volumes.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/volumes.c b/volumes.c +index 77ffd3252c38..b39f374305bc 100644 +--- a/volumes.c ++++ b/volumes.c +@@ -630,7 +630,8 @@ int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, + u8 *ptr; + + array_size = btrfs_super_sys_array_size(super_copy); +- if (array_size + item_size > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) ++ if (array_size + item_size + sizeof(disk_key) ++ > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) + return -EFBIG; + + ptr = super_copy->sys_chunk_array + array_size; +-- +1.9.0 + diff --git a/0001-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch b/0005-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch similarity index 75% rename from 0001-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch rename to 0005-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch index 9cdce66..bfc88a9 100644 --- a/0001-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch +++ b/0005-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch @@ -1,23 +1,25 @@ -From f555e06e2d266f52cdeb12218f8175eba2a17020 Mon Sep 17 00:00:00 2001 +From b5230eca8a9214c7290ed818ff9792eb5d3e142b Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 11 Apr 2014 13:22:50 +0200 -Subject: [PATCH] btrfs-progs: move arg_strtou64 to a separate file for library +Subject: [PATCH 12/42] btrfs-progs: move arg_strtou64 to a separate file for + library Linking with libbtrfs fails because arg_strtou64 is not defined and we cannot just add utils.o to library objects because it's not library-clean. Reported-by: Arvin Schnell +Reported-by: Anton Farygin Signed-off-by: David Sterba --- - Makefile | 5 +++-- - libutils.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - utils.c | 33 --------------------------------- - 3 files changed, 46 insertions(+), 35 deletions(-) - create mode 100644 libutils.c + Makefile | 5 +++-- + utils-lib.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + utils.c | 33 --------------------------------- + 3 files changed, 45 insertions(+), 35 deletions(-) + create mode 100644 utils-lib.c diff --git a/Makefile b/Makefile -index da0519766443..9ae7115d23a3 100644 +index 51d53fadf5af..76565e8b2307 100644 --- a/Makefile +++ b/Makefile @@ -9,14 +9,15 @@ CFLAGS = -g -O1 -fno-strict-aliasing @@ -26,7 +28,7 @@ index da0519766443..9ae7115d23a3 100644 extent-cache.o extent_io.o volumes.o utils.o repair.o \ - qgroup.o raid6.o free-space-cache.o list_sort.o props.o + qgroup.o raid6.o free-space-cache.o list_sort.o props.o \ -+ libutils.o ++ utils-lib.o cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \ cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \ @@ -34,16 +36,16 @@ index da0519766443..9ae7115d23a3 100644 cmds-property.o libbtrfs_objects = send-stream.o send-utils.o rbtree.o btrfs-list.o crc32c.o \ - uuid-tree.o -+ uuid-tree.o libutils.o ++ uuid-tree.o utils-lib.o libbtrfs_headers = send-stream.h send-utils.h send.h rbtree.h btrfs-list.h \ crc32c.h list.h kerncompat.h radix-tree.h extent-cache.h \ extent_io.h ioctl.h ctree.h btrfsck.h -diff --git a/libutils.c b/libutils.c +diff --git a/utils-lib.c b/utils-lib.c new file mode 100644 -index 000000000000..074f771e0b6e +index 000000000000..9d53c6e5c710 --- /dev/null -+++ b/libutils.c -@@ -0,0 +1,43 @@ ++++ b/utils-lib.c +@@ -0,0 +1,42 @@ +#define _GNU_SOURCE + +#include "kerncompat.h" @@ -56,8 +58,8 @@ index 000000000000..074f771e0b6e +#endif /* BTRFS_FLAT_INCLUDES */ + +/* -+ * This function should be only used when parsing -+ * command arg, it won't return error to it's ++ * This function should be only used when parsing command arg, it won't return ++ * error to its caller and rather exit directly just like usage(). + */ +u64 arg_strtou64(const char *str) +{ @@ -70,10 +72,10 @@ index 000000000000..074f771e0b6e + str); + exit(1); + } ++ + /* -+ * if we pass a negative number to strtoull, -+ * it will return an unexpected number to us, -+ * so let's do the check ourselves. ++ * if we pass a negative number to strtoull, it will return an ++ * unexpected number to us, so let's do the check ourselves. + */ + if (str[0] == '-') { + fprintf(stderr, "ERROR: %s: negative value is invalid.\n", @@ -86,12 +88,11 @@ index 000000000000..074f771e0b6e + } + return value; +} -+ diff --git a/utils.c b/utils.c -index 3e9c527a492c..134f43a76fe9 100644 +index 29953d9dd2a9..e130849c7bb5 100644 --- a/utils.c +++ b/utils.c -@@ -1539,39 +1539,6 @@ scan_again: +@@ -1538,39 +1538,6 @@ scan_again: return 0; } diff --git a/0006-Btrfs-progs-fsck-clear-out-log-tree-in-repair-mode.patch b/0006-Btrfs-progs-fsck-clear-out-log-tree-in-repair-mode.patch new file mode 100644 index 0000000..bfc20cb --- /dev/null +++ b/0006-Btrfs-progs-fsck-clear-out-log-tree-in-repair-mode.patch @@ -0,0 +1,71 @@ +From 3ecff1d8f1eaa5e0d065c439cf72032dd01da751 Mon Sep 17 00:00:00 2001 +From: Wang Shilong +Date: Thu, 24 Apr 2014 11:19:16 +0800 +Subject: [PATCH 13/42] Btrfs-progs: fsck: clear out log tree in repair mode + +Repair mode will commit transaction which will make us +fail to load log tree anymore. + +Give a warning to common users, if they really want to +coninue, we will clear out log tree. + +Signed-off-by: Wang Shilong +Signed-off-by: David Sterba +--- + cmds-check.c | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/cmds-check.c b/cmds-check.c +index 1fe97b3a38c0..7457618fb702 100644 +--- a/cmds-check.c ++++ b/cmds-check.c +@@ -6616,6 +6616,22 @@ out: + return ret; + } + ++static int zero_log_tree(struct btrfs_root *root) ++{ ++ struct btrfs_trans_handle *trans; ++ int ret; ++ ++ trans = btrfs_start_transaction(root, 1); ++ if (IS_ERR(trans)) { ++ ret = PTR_ERR(trans); ++ return ret; ++ } ++ btrfs_set_super_log_root(root->fs_info->super_copy, 0); ++ btrfs_set_super_log_root_level(root->fs_info->super_copy, 0); ++ ret = btrfs_commit_transaction(trans, root); ++ return ret; ++} ++ + static struct option long_options[] = { + { "super", 1, NULL, 's' }, + { "repair", 0, NULL, 0 }, +@@ -6720,6 +6736,23 @@ int cmd_check(int argc, char **argv) + } + + root = info->fs_root; ++ /* ++ * repair mode will force us to commit transaction which ++ * will make us fail to load log tree when mounting. ++ */ ++ if (repair && btrfs_super_log_root(info->super_copy)) { ++ ret = ask_user("repair mode will force to clear out log tree, Are you sure?"); ++ if (!ret) { ++ ret = 1; ++ goto close_out; ++ } ++ ret = zero_log_tree(root); ++ if (ret) { ++ fprintf(stderr, "fail to zero log tree\n"); ++ goto close_out; ++ } ++ } ++ + uuid_unparse(info->super_copy->fsid, uuidbuf); + printf("Checking filesystem on %s\nUUID: %s\n", argv[optind], uuidbuf); + +-- +1.9.0 + diff --git a/0007-Btrfs-progs-fsck-avoid-pinning-same-block-several-ti.patch b/0007-Btrfs-progs-fsck-avoid-pinning-same-block-several-ti.patch new file mode 100644 index 0000000..7208e07 --- /dev/null +++ b/0007-Btrfs-progs-fsck-avoid-pinning-same-block-several-ti.patch @@ -0,0 +1,38 @@ +From 20e9fa6f969b3c6a4b3ff9941c351e90320aed61 Mon Sep 17 00:00:00 2001 +From: Wang Shilong +Date: Thu, 24 Apr 2014 11:19:17 +0800 +Subject: [PATCH 14/42] Btrfs-progs: fsck: avoid pinning same block several + times + +This can not only give some speedups but also avoid forever loop +with a really broken filesystem. + +Signed-off-by: Wang Shilong +Signed-off-by: David Sterba +--- + cmds-check.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/cmds-check.c b/cmds-check.c +index 7457618fb702..57d3f36eea1f 100644 +--- a/cmds-check.c ++++ b/cmds-check.c +@@ -6190,6 +6190,15 @@ static int pin_down_tree_blocks(struct btrfs_fs_info *fs_info, + int ret; + int i; + ++ /* ++ * If we have pinned this block before, don't pin it again. ++ * This can not only avoid forever loop with broken filesystem ++ * but also give us some speedups. ++ */ ++ if (test_range_bit(&fs_info->pinned_extents, eb->start, ++ eb->start + eb->len - 1, EXTENT_DIRTY, 0)) ++ return 0; ++ + btrfs_pin_extent(fs_info, eb->start, eb->len); + + leafsize = btrfs_super_leafsize(fs_info->super_copy); +-- +1.9.0 + diff --git a/0008-Btrfs-progs-fsck-add-ability-to-check-reloc-roots.patch b/0008-Btrfs-progs-fsck-add-ability-to-check-reloc-roots.patch new file mode 100644 index 0000000..9e240ff --- /dev/null +++ b/0008-Btrfs-progs-fsck-add-ability-to-check-reloc-roots.patch @@ -0,0 +1,92 @@ +From 26bf4f0a10dd192e4dc5494d2cf9398c666eaab6 Mon Sep 17 00:00:00 2001 +From: Wang Shilong +Date: Thu, 24 Apr 2014 18:51:10 +0800 +Subject: [PATCH 15/42] Btrfs-progs: fsck: add ability to check reloc roots + +When encountering system crash or balance enospc errors, +there maybe still some reloc roots left. + +The way we store reloc root is different from fs root: + +reloc root's root key(BTRFS_RELOC_TREE_OBJECTID, ROOT_ITEM, objectid) +fs root's root key(objectid, ROOT_ITEM, -1) +reloc data's root key(BTRFS_DATA_RELOC_TREE_OBJECTID, ROOT_ITEM, 0) + +So this patch use right key to search corresponding root node, and +avoid using normal fs root cache for reloc roots. + +Signed-off-by: Wang Shilong +Signed-off-by: David Sterba +--- + cmds-check.c | 33 ++++++++++++++++++++++++++------- + 1 file changed, 26 insertions(+), 7 deletions(-) + +diff --git a/cmds-check.c b/cmds-check.c +index 57d3f36eea1f..103efc5718ec 100644 +--- a/cmds-check.c ++++ b/cmds-check.c +@@ -299,8 +299,22 @@ static struct inode_record *clone_inode_rec(struct inode_record *orig_rec) + return rec; + } + +-static void print_inode_error(int errors) ++static void print_inode_error(struct btrfs_root *root, struct inode_record *rec) + { ++ u64 root_objectid = root->root_key.objectid; ++ int errors = rec->errors; ++ ++ if (!errors) ++ return; ++ /* reloc root errors, we print its corresponding fs root objectid*/ ++ if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) { ++ root_objectid = root->root_key.offset; ++ fprintf(stderr, "reloc"); ++ } ++ fprintf(stderr, "root %llu inode %llu errors %x", ++ (unsigned long long) root_objectid, ++ (unsigned long long) rec->ino, rec->errors); ++ + if (errors & I_ERR_NO_INODE_ITEM) + fprintf(stderr, ", no inode item"); + if (errors & I_ERR_NO_ORPHAN_ITEM) +@@ -1598,10 +1612,7 @@ static int check_inode_recs(struct btrfs_root *root, + rec->errors |= I_ERR_NO_INODE_ITEM; + if (rec->found_link != rec->nlink) + rec->errors |= I_ERR_LINK_COUNT_WRONG; +- fprintf(stderr, "root %llu inode %llu errors %x", +- (unsigned long long) root->root_key.objectid, +- (unsigned long long) rec->ino, rec->errors); +- print_inode_error(rec->errors); ++ print_inode_error(root, rec); + list_for_each_entry(backref, &rec->backrefs, list) { + if (!backref->found_dir_item) + backref->errors |= REF_ERR_NO_DIR_ITEM; +@@ -2060,8 +2071,14 @@ static int check_fs_roots(struct btrfs_root *root, + btrfs_item_key_to_cpu(leaf, &key, path.slots[0]); + if (key.type == BTRFS_ROOT_ITEM_KEY && + fs_root_objectid(key.objectid)) { +- key.offset = (u64)-1; +- tmp_root = btrfs_read_fs_root(root->fs_info, &key); ++ if (key.objectid == BTRFS_TREE_RELOC_OBJECTID) { ++ tmp_root = btrfs_read_fs_root_no_cache( ++ root->fs_info, &key); ++ } else { ++ key.offset = (u64)-1; ++ tmp_root = btrfs_read_fs_root( ++ root->fs_info, &key); ++ } + if (IS_ERR(tmp_root)) { + err = 1; + goto next; +@@ -2069,6 +2086,8 @@ static int check_fs_roots(struct btrfs_root *root, + ret = check_fs_root(tmp_root, root_cache, &wc); + if (ret) + err = 1; ++ if (key.objectid == BTRFS_TREE_RELOC_OBJECTID) ++ btrfs_free_fs_root(tmp_root); + } else if (key.type == BTRFS_ROOT_REF_KEY || + key.type == BTRFS_ROOT_BACKREF_KEY) { + process_root_ref(leaf, path.slots[0], &key, +-- +1.9.0 + diff --git a/0009-btrfs-progs-prevent-close_root-if-the-root-to-close-.patch b/0009-btrfs-progs-prevent-close_root-if-the-root-to-close-.patch new file mode 100644 index 0000000..91fc8da --- /dev/null +++ b/0009-btrfs-progs-prevent-close_root-if-the-root-to-close-.patch @@ -0,0 +1,43 @@ +From 07bb42ca797d78333b0fd47189a6504cd25b28d5 Mon Sep 17 00:00:00 2001 +From: Gui Hecheng +Date: Thu, 24 Apr 2014 11:39:28 +0800 +Subject: [PATCH 16/42] btrfs-progs: prevent close_root if the root to close is + potentially NULL + +Originally only if 'block_only' is specified, the 'fs_root == NULL' +will be checked. But if 'block_only' is not specified and close_root +will be called blindly without checking 'fs_root == NULL', which is +unsafe. + +Signed-off-by: Gui Hecheng +Signed-off-by: David Sterba +--- + btrfs-debug-tree.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/btrfs-debug-tree.c b/btrfs-debug-tree.c +index 8ae7270dc2fe..cb6c1061b329 100644 +--- a/btrfs-debug-tree.c ++++ b/btrfs-debug-tree.c +@@ -177,13 +177,14 @@ int main(int ac, char **av) + fprintf(stderr, "unable to open %s\n", av[optind]); + exit(1); + } ++ + root = info->fs_root; ++ if (!root) { ++ fprintf(stderr, "unable to open %s\n", av[optind]); ++ exit(1); ++ } + + if (block_only) { +- if (!root) { +- fprintf(stderr, "unable to open %s\n", av[optind]); +- exit(1); +- } + leaf = read_tree_block(root, + block_only, + root->leafsize, 0); +-- +1.9.0 + diff --git a/0010-btrfs-progs-fix-mkfs.btrfs-segfault-with-features-op.patch b/0010-btrfs-progs-fix-mkfs.btrfs-segfault-with-features-op.patch new file mode 100644 index 0000000..f14ffe2 --- /dev/null +++ b/0010-btrfs-progs-fix-mkfs.btrfs-segfault-with-features-op.patch @@ -0,0 +1,37 @@ +From 61e0b6eaf4d98ddea540ebbf6b7ad7202ffc6786 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Holger=20Hoffst=C3=A4tte?= + +Date: Sat, 26 Apr 2014 09:41:04 +0000 +Subject: [PATCH 19/42] btrfs-progs: fix mkfs.btrfs segfault with --features + option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The mkfs.btrfs --features long option takes an argument but does not +declare it. Consequently getopt does not allocate an argument, which +makes an unconditional strdup() crash during options parsing. +Fix by declaring the argument in the options alias array. + +Signed-off-by: Holger Hoffstätte +Signed-off-by: David Sterba +--- + mkfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mkfs.c b/mkfs.c +index 4f5ee07e5ef9..16e92221a547 100644 +--- a/mkfs.c ++++ b/mkfs.c +@@ -350,7 +350,7 @@ static struct option long_options[] = { + { "version", 0, NULL, 'V' }, + { "rootdir", 1, NULL, 'r' }, + { "nodiscard", 0, NULL, 'K' }, +- { "features", 0, NULL, 'O' }, ++ { "features", 1, NULL, 'O' }, + { NULL, 0, NULL, 0} + }; + +-- +1.9.0 + diff --git a/0011-btrfs-progs-Enhance-the-command-btrfs-filesystem-df.patch b/0011-btrfs-progs-Enhance-the-command-btrfs-filesystem-df.patch new file mode 100644 index 0000000..e324301 --- /dev/null +++ b/0011-btrfs-progs-Enhance-the-command-btrfs-filesystem-df.patch @@ -0,0 +1,771 @@ +From 04a9855f53cb7e4ad874cec28acfa537f00a28ba Mon Sep 17 00:00:00 2001 +From: Goffredo Baroncelli +Date: Thu, 13 Feb 2014 20:19:01 +0100 +Subject: [PATCH 22/42] btrfs-progs: Enhance the command btrfs filesystem df + +Enhance the command "btrfs filesystem df" to show space usage information +for a mount point(s). It shows also an estimation of the space available, +on the basis of the current one used. + +Signed-off-by: Goffredo Baroncelli +Signed-off-by: David Sterba +--- + Makefile | 2 +- + cmds-fi-disk_usage.c | 516 +++++++++++++++++++++++++++++++++++++++++++++++++++ + cmds-fi-disk_usage.h | 25 +++ + cmds-filesystem.c | 92 +-------- + ctree.h | 5 +- + utils.c | 12 ++ + utils.h | 1 + + 7 files changed, 560 insertions(+), 93 deletions(-) + create mode 100644 cmds-fi-disk_usage.c + create mode 100644 cmds-fi-disk_usage.h + +diff --git a/Makefile b/Makefile +index 76565e8b2307..50fb9b0ff2e3 100644 +--- a/Makefile ++++ b/Makefile +@@ -15,7 +15,7 @@ cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ + cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \ + cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \ + cmds-restore.o cmds-rescue.o chunk-recover.o super-recover.o \ +- cmds-property.o ++ cmds-property.o cmds-fi-disk_usage.o + libbtrfs_objects = send-stream.o send-utils.o rbtree.o btrfs-list.o crc32c.o \ + uuid-tree.o utils-lib.o + libbtrfs_headers = send-stream.h send-utils.h send.h rbtree.h btrfs-list.h \ +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +new file mode 100644 +index 000000000000..4012c781f20d +--- /dev/null ++++ b/cmds-fi-disk_usage.c +@@ -0,0 +1,516 @@ ++/* ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "utils.h" ++#include "kerncompat.h" ++#include "ctree.h" ++ ++#include "commands.h" ++ ++#include "version.h" ++ ++#define DF_HUMAN_UNIT (1<<0) ++ ++/* ++ * To store the size information about the chunks: ++ * the chunks info are grouped by the tuple (type, devid, num_stripes), ++ * i.e. if two chunks are of the same type (RAID1, DUP...), are on the ++ * same disk, have the same stripes then their sizes are grouped ++ */ ++struct chunk_info { ++ u64 type; ++ u64 size; ++ u64 devid; ++ u64 num_stripes; ++}; ++ ++/* ++ * Pretty print the size ++ * PAY ATTENTION: it return a statically buffer ++ */ ++static char *df_pretty_sizes(u64 size, int mode) ++{ ++ static char buf[30]; ++ ++ if (mode & DF_HUMAN_UNIT) ++ (void)pretty_size_snprintf(size, buf, sizeof(buf)); ++ else ++ sprintf(buf, "%llu", size); ++ ++ return buf; ++} ++ ++/* ++ * Add the chunk info to the chunk_info list ++ */ ++static int add_info_to_list(struct chunk_info **info_ptr, ++ int *info_count, ++ struct btrfs_chunk *chunk) ++{ ++ ++ u64 type = btrfs_stack_chunk_type(chunk); ++ u64 size = btrfs_stack_chunk_length(chunk); ++ int num_stripes = btrfs_stack_chunk_num_stripes(chunk); ++ int j; ++ ++ for (j = 0 ; j < num_stripes ; j++) { ++ int i; ++ struct chunk_info *p = 0; ++ struct btrfs_stripe *stripe; ++ u64 devid; ++ ++ stripe = btrfs_stripe_nr(chunk, j); ++ devid = btrfs_stack_stripe_devid(stripe); ++ ++ for (i = 0 ; i < *info_count ; i++) ++ if ((*info_ptr)[i].type == type && ++ (*info_ptr)[i].devid == devid && ++ (*info_ptr)[i].num_stripes == num_stripes ) { ++ p = (*info_ptr) + i; ++ break; ++ } ++ ++ if (!p) { ++ int size = sizeof(struct btrfs_chunk) * (*info_count+1); ++ struct chunk_info *res = realloc(*info_ptr, size); ++ ++ if (!res) { ++ fprintf(stderr, "ERROR: not enough memory\n"); ++ return -1; ++ } ++ ++ *info_ptr = res; ++ p = res + *info_count; ++ (*info_count)++; ++ ++ p->devid = devid; ++ p->type = type; ++ p->size = 0; ++ p->num_stripes = num_stripes; ++ } ++ ++ p->size += size; ++ ++ } ++ ++ return 0; ++ ++} ++ ++/* ++ * Helper to sort the chunk type ++ */ ++static int cmp_chunk_block_group(u64 f1, u64 f2) ++{ ++ ++ u64 mask; ++ ++ if ((f1 & BTRFS_BLOCK_GROUP_TYPE_MASK) == ++ (f2 & BTRFS_BLOCK_GROUP_TYPE_MASK)) ++ mask = BTRFS_BLOCK_GROUP_PROFILE_MASK; ++ else if (f2 & BTRFS_BLOCK_GROUP_SYSTEM) ++ return -1; ++ else if (f1 & BTRFS_BLOCK_GROUP_SYSTEM) ++ return +1; ++ else ++ mask = BTRFS_BLOCK_GROUP_TYPE_MASK; ++ ++ if ((f1 & mask) > (f2 & mask)) ++ return +1; ++ else if ((f1 & mask) < (f2 & mask)) ++ return -1; ++ else ++ return 0; ++} ++ ++/* ++ * Helper to sort the chunk ++ */ ++static int cmp_chunk_info(const void *a, const void *b) ++{ ++ return cmp_chunk_block_group( ++ ((struct chunk_info *)a)->type, ++ ((struct chunk_info *)b)->type); ++} ++ ++/* ++ * This function load all the chunk info from the 'fd' filesystem ++ */ ++static int load_chunk_info(int fd, ++ struct chunk_info **info_ptr, ++ int *info_count) ++{ ++ ++ int ret; ++ struct btrfs_ioctl_search_args args; ++ struct btrfs_ioctl_search_key *sk = &args.key; ++ struct btrfs_ioctl_search_header *sh; ++ unsigned long off = 0; ++ int i, e; ++ ++ ++ memset(&args, 0, sizeof(args)); ++ ++ /* ++ * there may be more than one ROOT_ITEM key if there are ++ * snapshots pending deletion, we have to loop through ++ * them. ++ */ ++ ++ ++ sk->tree_id = BTRFS_CHUNK_TREE_OBJECTID; ++ ++ sk->min_objectid = 0; ++ sk->max_objectid = (u64)-1; ++ sk->max_type = 0; ++ sk->min_type = (u8)-1; ++ sk->min_offset = 0; ++ sk->max_offset = (u64)-1; ++ sk->min_transid = 0; ++ sk->max_transid = (u64)-1; ++ sk->nr_items = 4096; ++ ++ while (1) { ++ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); ++ e = errno; ++ if (ret < 0) { ++ fprintf(stderr, ++ "ERROR: can't perform the search - %s\n", ++ strerror(e)); ++ return -99; ++ } ++ /* the ioctl returns the number of item it found in nr_items */ ++ ++ if (sk->nr_items == 0) ++ break; ++ ++ off = 0; ++ for (i = 0; i < sk->nr_items; i++) { ++ struct btrfs_chunk *item; ++ sh = (struct btrfs_ioctl_search_header *)(args.buf + ++ off); ++ ++ off += sizeof(*sh); ++ item = (struct btrfs_chunk *)(args.buf + off); ++ ++ if (add_info_to_list(info_ptr, info_count, item)) { ++ *info_ptr = 0; ++ free(*info_ptr); ++ return -100; ++ } ++ ++ off += sh->len; ++ ++ sk->min_objectid = sh->objectid; ++ sk->min_type = sh->type; ++ sk->min_offset = sh->offset+1; ++ ++ } ++ if (!sk->min_offset) /* overflow */ ++ sk->min_type++; ++ else ++ continue; ++ ++ if (!sk->min_type) ++ sk->min_objectid++; ++ else ++ continue; ++ ++ if (!sk->min_objectid) ++ break; ++ } ++ ++ qsort(*info_ptr, *info_count, sizeof(struct chunk_info), ++ cmp_chunk_info); ++ ++ return 0; ++ ++} ++ ++/* ++ * Helper to sort the struct btrfs_ioctl_space_info ++ */ ++static int cmp_btrfs_ioctl_space_info(const void *a, const void *b) ++{ ++ return cmp_chunk_block_group( ++ ((struct btrfs_ioctl_space_info *)a)->flags, ++ ((struct btrfs_ioctl_space_info *)b)->flags); ++} ++ ++/* ++ * This function load all the information about the space usage ++ */ ++static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) ++{ ++ struct btrfs_ioctl_space_args *sargs = 0, *sargs_orig = 0; ++ int e, ret, count; ++ ++ sargs_orig = sargs = malloc(sizeof(struct btrfs_ioctl_space_args)); ++ if (!sargs) { ++ fprintf(stderr, "ERROR: not enough memory\n"); ++ return NULL; ++ } ++ ++ sargs->space_slots = 0; ++ sargs->total_spaces = 0; ++ ++ ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs); ++ e = errno; ++ if (ret) { ++ fprintf(stderr, ++ "ERROR: couldn't get space info on '%s' - %s\n", ++ path, strerror(e)); ++ free(sargs); ++ return NULL; ++ } ++ if (!sargs->total_spaces) { ++ free(sargs); ++ printf("No chunks found\n"); ++ return NULL; ++ } ++ ++ count = sargs->total_spaces; ++ ++ sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) + ++ (count * sizeof(struct btrfs_ioctl_space_info))); ++ if (!sargs) { ++ free(sargs_orig); ++ fprintf(stderr, "ERROR: not enough memory\n"); ++ return NULL; ++ } ++ ++ sargs->space_slots = count; ++ sargs->total_spaces = 0; ++ ++ ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs); ++ e = errno; ++ ++ if (ret) { ++ fprintf(stderr, ++ "ERROR: couldn't get space info on '%s' - %s\n", ++ path, strerror(e)); ++ free(sargs); ++ return NULL; ++ } ++ ++ qsort(&(sargs->spaces), count, sizeof(struct btrfs_ioctl_space_info), ++ cmp_btrfs_ioctl_space_info); ++ ++ return sargs; ++} ++ ++/* ++ * This function computes the space occuped by a *single* RAID5/RAID6 chunk. ++ * The computation is performed on the basis of the number of stripes ++ * which compose the chunk, which could be different from the number of disks ++ * if a disk is added later. ++ */ ++static int get_raid56_used(int fd, u64 *raid5_used, u64 *raid6_used) ++{ ++ struct chunk_info *info_ptr=0, *p; ++ int info_count=0; ++ int ret; ++ ++ *raid5_used = *raid6_used =0; ++ ++ ret = load_chunk_info(fd, &info_ptr, &info_count); ++ if( ret < 0) ++ return ret; ++ ++ for ( p = info_ptr; info_count ; info_count--, p++ ) { ++ if (p->type & BTRFS_BLOCK_GROUP_RAID5) ++ (*raid5_used) += p->size / (p->num_stripes -1); ++ if (p->type & BTRFS_BLOCK_GROUP_RAID6) ++ (*raid6_used) += p->size / (p->num_stripes -2); ++ } ++ ++ return 0; ++ ++} ++ ++static int _cmd_disk_free(int fd, char *path, int mode) ++{ ++ struct btrfs_ioctl_space_args *sargs = 0; ++ int i; ++ int ret = 0; ++ int e, width; ++ u64 total_disk; /* filesystem size == sum of ++ disks sizes */ ++ u64 total_chunks; /* sum of chunks sizes on disk(s) */ ++ u64 total_used; /* logical space used */ ++ u64 total_free; /* logical space un-used */ ++ double K; ++ u64 raid5_used, raid6_used; ++ ++ if ((sargs = load_space_info(fd, path)) == NULL) { ++ ret = -1; ++ goto exit; ++ } ++ ++ total_disk = disk_size(path); ++ e = errno; ++ if (total_disk == 0) { ++ fprintf(stderr, ++ "ERROR: couldn't get space info on '%s' - %s\n", ++ path, strerror(e)); ++ ++ ret = 19; ++ goto exit; ++ } ++ if (get_raid56_used(fd, &raid5_used, &raid6_used) < 0) { ++ fprintf(stderr, ++ "ERROR: couldn't get space info on '%s'\n", ++ path ); ++ ret = 20; ++ goto exit; ++ } ++ ++ total_chunks = total_used = total_free = 0; ++ ++ for (i = 0; i < sargs->total_spaces; i++) { ++ float ratio = 1; ++ u64 allocated; ++ u64 flags = sargs->spaces[i].flags; ++ ++ /* ++ * The raid5/raid6 ratio depends by the stripes number ++ * used by every chunk. It is computed separately ++ */ ++ if (flags & BTRFS_BLOCK_GROUP_RAID0) ++ ratio = 1; ++ else if (flags & BTRFS_BLOCK_GROUP_RAID1) ++ ratio = 2; ++ else if (flags & BTRFS_BLOCK_GROUP_RAID5) ++ ratio = 0; ++ else if (flags & BTRFS_BLOCK_GROUP_RAID6) ++ ratio = 0; ++ else if (flags & BTRFS_BLOCK_GROUP_DUP) ++ ratio = 2; ++ else if (flags & BTRFS_BLOCK_GROUP_RAID10) ++ ratio = 2; ++ else ++ ratio = 1; ++ ++ allocated = sargs->spaces[i].total_bytes * ratio; ++ ++ total_chunks += allocated; ++ total_used += sargs->spaces[i].used_bytes; ++ total_free += (sargs->spaces[i].total_bytes - ++ sargs->spaces[i].used_bytes); ++ ++ } ++ ++ /* add the raid5/6 allocated space */ ++ total_chunks += raid5_used + raid6_used; ++ ++ K = ((double)total_used + (double)total_free) / (double)total_chunks; ++ ++ if (mode & DF_HUMAN_UNIT) ++ width = 10; ++ else ++ width = 18; ++ ++ printf("Disk size:\t\t%*s\n", width, ++ df_pretty_sizes(total_disk, mode)); ++ printf("Disk allocated:\t\t%*s\n", width, ++ df_pretty_sizes(total_chunks, mode)); ++ printf("Disk unallocated:\t%*s\n", width, ++ df_pretty_sizes(total_disk-total_chunks, mode)); ++ printf("Used:\t\t\t%*s\n", width, ++ df_pretty_sizes(total_used, mode)); ++ printf("Free (Estimated):\t%*s\t(", ++ width, ++ df_pretty_sizes((u64)(K*total_disk-total_used), mode)); ++ printf("Max: %s, ", ++ df_pretty_sizes(total_disk-total_chunks+total_free, mode)); ++ printf("min: %s)\n", ++ df_pretty_sizes((total_disk-total_chunks)/2+total_free, mode)); ++ printf("Data to disk ratio:\t%*.0f %%\n", ++ width-2, K*100); ++ ++exit: ++ ++ if (sargs) ++ free(sargs); ++ ++ return ret; ++} ++ ++const char * const cmd_filesystem_df_usage[] = { ++ "btrfs filesystem df [-b] [..]", ++ "Show space usage information for a mount point(s).", ++ "", ++ "-b\tSet byte as unit", ++ NULL ++}; ++ ++int cmd_filesystem_df(int argc, char **argv) ++{ ++ ++ int flags = DF_HUMAN_UNIT; ++ int i, more_than_one = 0; ++ ++ optind = 1; ++ while (1) { ++ char c = getopt(argc, argv, "b"); ++ if (c < 0) ++ break; ++ ++ switch (c) { ++ case 'b': ++ flags &= ~DF_HUMAN_UNIT; ++ break; ++ default: ++ usage(cmd_filesystem_df_usage); ++ } ++ } ++ ++ if (check_argc_min(argc - optind, 1)) { ++ usage(cmd_filesystem_df_usage); ++ return 21; ++ } ++ ++ for (i = optind; i < argc ; i++) { ++ int r, fd; ++ DIR *dirstream = NULL; ++ if (more_than_one) ++ printf("\n"); ++ ++ fd = open_file_or_dir(argv[i], &dirstream); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: can't access to '%s'\n", ++ argv[1]); ++ return 12; ++ } ++ r = _cmd_disk_free(fd, argv[i], flags); ++ close_file_or_dir(fd, dirstream); ++ ++ if (r) ++ return r; ++ more_than_one = 1; ++ ++ } ++ ++ return 0; ++} ++ +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +new file mode 100644 +index 000000000000..9f68bb342d52 +--- /dev/null ++++ b/cmds-fi-disk_usage.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 2007 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 __CMDS_FI_DISK_USAGE__ ++#define __CMDS_FI_DISK_USAGE__ ++ ++extern const char * const cmd_filesystem_df_usage[]; ++int cmd_filesystem_df(int argc, char **argv); ++ ++#endif +diff --git a/cmds-filesystem.c b/cmds-filesystem.c +index 306f715475ac..0edfb50daca2 100644 +--- a/cmds-filesystem.c ++++ b/cmds-filesystem.c +@@ -36,6 +36,7 @@ + #include "volumes.h" + #include "version.h" + #include "commands.h" ++#include "cmds-fi-disk_usage.h" + #include "list_sort.h" + #include "disk-io.h" + +@@ -112,50 +113,6 @@ static const char * const filesystem_cmd_group_usage[] = { + NULL + }; + +-static const char * const cmd_df_usage[] = { +- "btrfs filesystem df ", +- "Show space usage information for a mount point", +- NULL +-}; +- +-static char *group_type_str(u64 flag) +-{ +- switch (flag & BTRFS_BLOCK_GROUP_TYPE_MASK) { +- case BTRFS_BLOCK_GROUP_DATA: +- return "Data"; +- case BTRFS_BLOCK_GROUP_SYSTEM: +- return "System"; +- case BTRFS_BLOCK_GROUP_METADATA: +- return "Metadata"; +- case BTRFS_BLOCK_GROUP_DATA|BTRFS_BLOCK_GROUP_METADATA: +- return "Data+Metadata"; +- default: +- return "unknown"; +- } +-} +- +-static char *group_profile_str(u64 flag) +-{ +- switch (flag & BTRFS_BLOCK_GROUP_PROFILE_MASK) { +- case 0: +- return "single"; +- case BTRFS_BLOCK_GROUP_RAID0: +- return "RAID0"; +- case BTRFS_BLOCK_GROUP_RAID1: +- return "RAID1"; +- case BTRFS_BLOCK_GROUP_RAID5: +- return "RAID5"; +- case BTRFS_BLOCK_GROUP_RAID6: +- return "RAID6"; +- case BTRFS_BLOCK_GROUP_DUP: +- return "DUP"; +- case BTRFS_BLOCK_GROUP_RAID10: +- return "RAID10"; +- default: +- return "unknown"; +- } +-} +- + static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret) + { + u64 count = 0; +@@ -204,51 +161,6 @@ static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret) + return 0; + } + +-static void print_df(struct btrfs_ioctl_space_args *sargs) +-{ +- u64 i; +- struct btrfs_ioctl_space_info *sp = sargs->spaces; +- +- for (i = 0; i < sargs->total_spaces; i++, sp++) { +- printf("%s, %s: total=%s, used=%s\n", +- group_type_str(sp->flags), +- group_profile_str(sp->flags), +- pretty_size(sp->total_bytes), +- pretty_size(sp->used_bytes)); +- } +-} +- +-static int cmd_df(int argc, char **argv) +-{ +- struct btrfs_ioctl_space_args *sargs = NULL; +- int ret; +- int fd; +- char *path; +- DIR *dirstream = NULL; +- +- if (check_argc_exact(argc, 2)) +- usage(cmd_df_usage); +- +- path = argv[1]; +- +- fd = open_file_or_dir(path, &dirstream); +- if (fd < 0) { +- fprintf(stderr, "ERROR: can't access '%s'\n", path); +- return 1; +- } +- ret = get_df(fd, &sargs); +- +- if (!ret && sargs) { +- print_df(sargs); +- free(sargs); +- } else { +- fprintf(stderr, "ERROR: get_df failed %s\n", strerror(-ret)); +- } +- +- close_file_or_dir(fd, dirstream); +- return !!ret; +-} +- + static int match_search_item_kernel(__u8 *fsid, char *mnt, char *label, + char *search) + { +@@ -999,7 +911,7 @@ static int cmd_label(int argc, char **argv) + + const struct cmd_group filesystem_cmd_group = { + filesystem_cmd_group_usage, NULL, { +- { "df", cmd_df, cmd_df_usage, NULL, 0 }, ++ { "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 }, + { "show", cmd_show, cmd_show_usage, NULL, 0 }, + { "sync", cmd_sync, cmd_sync_usage, NULL, 0 }, + { "defragment", cmd_defrag, cmd_defrag_usage, NULL, 0 }, +diff --git a/ctree.h b/ctree.h +index a4d2cd114614..8ac17619b9dc 100644 +--- a/ctree.h ++++ b/ctree.h +@@ -843,9 +843,10 @@ struct btrfs_csum_item { + #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_RAID5 (1ULL << 7) +-#define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) ++#define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7) ++#define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) + #define BTRFS_BLOCK_GROUP_RESERVED BTRFS_AVAIL_ALLOC_BIT_SINGLE ++#define BTRFS_NR_RAID_TYPES 7 + + #define BTRFS_BLOCK_GROUP_TYPE_MASK (BTRFS_BLOCK_GROUP_DATA | \ + BTRFS_BLOCK_GROUP_SYSTEM | \ +diff --git a/utils.c b/utils.c +index e130849c7bb5..7731b071f353 100644 +--- a/utils.c ++++ b/utils.c +@@ -38,6 +38,8 @@ + #include + #include + #include ++#include ++ + #include "kerncompat.h" + #include "radix-tree.h" + #include "ctree.h" +@@ -2206,3 +2208,13 @@ int find_mount_root(const char *path, char **mount_root) + free(longest_match); + return ret; + } ++ ++u64 disk_size(char *path) ++{ ++ struct statfs sfs; ++ ++ if (statfs(path, &sfs) < 0) ++ return 0; ++ else ++ return sfs.f_bsize * sfs.f_blocks; ++} +diff --git a/utils.h b/utils.h +index db8d63c396d5..581faa9f6972 100644 +--- a/utils.h ++++ b/utils.h +@@ -101,5 +101,6 @@ int get_btrfs_mount(const char *dev, char *mp, size_t mp_size); + int find_mount_root(const char *path, char **mount_root); + int get_device_info(int fd, u64 devid, + struct btrfs_ioctl_dev_info_args *di_args); ++u64 disk_size(char *path); + + #endif +-- +1.9.0 + diff --git a/0012-btrfs-progs-Add-helpers-functions-to-handle-the-prin.patch b/0012-btrfs-progs-Add-helpers-functions-to-handle-the-prin.patch new file mode 100644 index 0000000..a617bf4 --- /dev/null +++ b/0012-btrfs-progs-Add-helpers-functions-to-handle-the-prin.patch @@ -0,0 +1,261 @@ +From a79f61440afaa0b77dc67c896fa3367a171c2306 Mon Sep 17 00:00:00 2001 +From: Goffredo Baroncelli +Date: Thu, 13 Feb 2014 20:19:21 +0100 +Subject: [PATCH 23/42] btrfs-progs: Add helpers functions to handle the + printing of data in tabular format + +This patch adds some functions to manage the printing of the data in +tabular format. + +The function + struct string_table *table_create(int columns, int rows) +creates an (empty) table. + +The functions + char *table_printf(struct string_table *tab, int column, + int row, char *fmt, ...) + char *table_vprintf(struct string_table *tab, int column, + int row, char *fmt, va_list ap) +populate the table with text. To align the text to the left, the text +shall be prefixed with '<', otherwise the text shall be prefixed by a +'>'. If the first character is a '=', the the text is replace by a +sequence of '=' to fill the column width. + +The function + void table_free(struct string_table *) +frees all the data associated to the table. + +The function + void table_dump(struct string_table *tab) +prints the table on stdout. + +Signed-off-by: Goffredo Baroncelli +Signed-off-by: David Sterba +--- + Makefile | 2 +- + string_table.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + string_table.h | 36 +++++++++++++ + 3 files changed, 193 insertions(+), 1 deletion(-) + create mode 100644 string_table.c + create mode 100644 string_table.h + +diff --git a/Makefile b/Makefile +index 50fb9b0ff2e3..bf6dc1c67d2c 100644 +--- a/Makefile ++++ b/Makefile +@@ -10,7 +10,7 @@ objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ + root-tree.o dir-item.o file-item.o inode-item.o inode-map.o \ + extent-cache.o extent_io.o volumes.o utils.o repair.o \ + qgroup.o raid6.o free-space-cache.o list_sort.o props.o \ +- utils-lib.o ++ utils-lib.o string_table.o + cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ + cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \ + cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \ +diff --git a/string_table.c b/string_table.c +new file mode 100644 +index 000000000000..016356c50392 +--- /dev/null ++++ b/string_table.c +@@ -0,0 +1,156 @@ ++/* ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "string_table.h" ++ ++/* ++ * This function create an array of char * which will represent a table ++ */ ++struct string_table *table_create(int columns, int rows) ++{ ++ struct string_table *p; ++ int size; ++ ++ size = sizeof( struct string_table ) + ++ rows * columns* sizeof(char *); ++ p = calloc(1, size); ++ ++ if (!p) return NULL; ++ ++ p->ncols = columns; ++ p->nrows = rows; ++ ++ return p; ++} ++ ++/* ++ * This function is like a vprintf, but store the results in a cell of ++ * the table. ++ * If fmt starts with '<', the text is left aligned; if fmt starts with ++ * '>' the text is right aligned. If fmt is equal to '=' the text will ++ * be replaced by a '=====' dimensioned on the basis of the column width ++ */ ++char *table_vprintf(struct string_table *tab, int column, int row, ++ char *fmt, va_list ap) ++{ ++ int idx = tab->ncols*row+column; ++ char *msg = calloc(100, sizeof(char)); ++ ++ if (!msg) ++ return NULL; ++ ++ if (tab->cells[idx]) ++ free(tab->cells[idx]); ++ tab->cells[idx] = msg; ++ vsnprintf(msg, 99, fmt, ap); ++ ++ return msg; ++} ++ ++ ++/* ++ * This function is like a printf, but store the results in a cell of ++ * the table. ++ */ ++char *table_printf(struct string_table *tab, int column, int row, ++ char *fmt, ...) ++{ ++ va_list ap; ++ char *ret; ++ ++ va_start(ap, fmt); ++ ret = table_vprintf(tab, column, row, fmt, ap); ++ va_end(ap); ++ ++ return ret; ++} ++ ++/* ++ * This function dumps the table. Every "=" string will be replaced by ++ * a "=======" length as the column ++ */ ++void table_dump(struct string_table *tab) ++{ ++ int sizes[tab->ncols]; ++ int i, j; ++ ++ for (i = 0 ; i < tab->ncols ; i++) { ++ sizes[i] = 0; ++ for (j = 0 ; j < tab->nrows ; j++) { ++ int idx = i + j*tab->ncols; ++ int s; ++ ++ if (!tab->cells[idx]) ++ continue; ++ ++ s = strlen(tab->cells[idx]) - 1; ++ if (s < 1 || tab->cells[idx][0] == '=') ++ continue; ++ ++ if (s > sizes[i]) ++ sizes[i] = s; ++ } ++ } ++ ++ ++ for (j = 0 ; j < tab->nrows ; j++) { ++ for (i = 0 ; i < tab->ncols ; i++) { ++ ++ int idx = i + j*tab->ncols; ++ char *s = tab->cells[idx]; ++ ++ if (!s|| !strlen(s)) { ++ printf("%*s", sizes[i], ""); ++ } else if (s && s[0] == '=') { ++ int k = sizes[i]; ++ while(k--) ++ putchar('='); ++ } else { ++ printf("%*s", ++ s[0] == '<' ? -sizes[i] : sizes[i], ++ s+1); ++ } ++ if (i != (tab->ncols - 1)) ++ putchar(' '); ++ } ++ putchar('\n'); ++ } ++ ++} ++ ++/* ++ * Deallocate a tabular and all its content ++ */ ++ ++void table_free(struct string_table *tab) ++{ ++ ++ int i, count; ++ ++ count = tab->ncols * tab->nrows; ++ ++ for (i=0 ; i < count ; i++) ++ if (tab->cells[i]) ++ free(tab->cells[i]); ++ ++ free(tab); ++ ++} +diff --git a/string_table.h b/string_table.h +new file mode 100644 +index 000000000000..83c4425d5f76 +--- /dev/null ++++ b/string_table.h +@@ -0,0 +1,36 @@ ++/* ++ * 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 STRING_TABLE_H ++#define STRING_TABLE_H ++ ++struct string_table { ++ ++ int ncols, nrows; ++ char *cells[]; ++ ++}; ++ ++ ++struct string_table *table_create(int columns, int rows); ++char *table_printf(struct string_table *tab, int column, int row, ++ char *fmt, ...); ++char *table_vprintf(struct string_table *tab, int column, int row, ++ char *fmt, va_list ap); ++void table_dump(struct string_table *tab); ++void table_free(struct string_table *); ++ ++#endif +-- +1.9.0 + diff --git a/0013-btrfs-progs-Add-command-btrfs-filesystem-disk-usage.patch b/0013-btrfs-progs-Add-command-btrfs-filesystem-disk-usage.patch new file mode 100644 index 0000000..30bbdd2 --- /dev/null +++ b/0013-btrfs-progs-Add-command-btrfs-filesystem-disk-usage.patch @@ -0,0 +1,581 @@ +From bb2b9f64b992f166533cc0d06aeec9518795d24a Mon Sep 17 00:00:00 2001 +From: Goffredo Baroncelli +Date: Thu, 13 Feb 2014 20:19:50 +0100 +Subject: [PATCH 24/42] btrfs-progs: Add command btrfs filesystem disk-usage + +Signed-off-by: Goffredo Baroncelli +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++ + cmds-fi-disk_usage.h | 3 + + cmds-filesystem.c | 3 + + utils.c | 60 ++++++++ + utils.h | 5 + + 5 files changed, 499 insertions(+) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 4012c781f20d..16b3ab250956 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -20,10 +20,12 @@ + #include + #include + #include ++#include + + #include "utils.h" + #include "kerncompat.h" + #include "ctree.h" ++#include "string_table.h" + + #include "commands.h" + +@@ -44,6 +46,13 @@ struct chunk_info { + u64 num_stripes; + }; + ++/* to store information about the disks */ ++struct disk_info { ++ u64 devid; ++ char path[BTRFS_DEVICE_PATH_NAME_MAX]; ++ u64 size; ++}; ++ + /* + * Pretty print the size + * PAY ATTENTION: it return a statically buffer +@@ -514,3 +523,422 @@ int cmd_filesystem_df(int argc, char **argv) + return 0; + } + ++/* ++ * Helper to sort the disk_info structure ++ */ ++static int cmp_disk_info(const void *a, const void *b) ++{ ++ return strcmp(((struct disk_info *)a)->path, ++ ((struct disk_info *)b)->path); ++} ++ ++/* ++ * This function load the disk_info structure and put them in an array ++ */ ++static int load_disks_info(int fd, ++ struct disk_info **disks_info_ptr, ++ int *disks_info_count) ++{ ++ ++ int ret, i, ndevs; ++ struct btrfs_ioctl_fs_info_args fi_args; ++ struct btrfs_ioctl_dev_info_args dev_info; ++ struct disk_info *info; ++ ++ *disks_info_count = 0; ++ *disks_info_ptr = 0; ++ ++ ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); ++ if (ret < 0) { ++ fprintf(stderr, "ERROR: cannot get filesystem info\n"); ++ return -1; ++ } ++ ++ info = malloc(sizeof(struct disk_info) * fi_args.num_devices); ++ if (!info) { ++ fprintf(stderr, "ERROR: not enough memory\n"); ++ return -1; ++ } ++ ++ for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) { ++ ++ BUG_ON(ndevs >= fi_args.num_devices); ++ ret = get_device_info(fd, i, &dev_info); ++ ++ if (ret == -ENODEV) ++ continue; ++ if (ret) { ++ fprintf(stderr, ++ "ERROR: cannot get info about device devid=%d\n", ++ i); ++ free(info); ++ return -1; ++ } ++ ++ info[ndevs].devid = dev_info.devid; ++ strcpy(info[ndevs].path, (char *)dev_info.path); ++ info[ndevs].size = get_partition_size((char *)dev_info.path); ++ ++ndevs; ++ } ++ ++ BUG_ON(ndevs != fi_args.num_devices); ++ qsort(info, fi_args.num_devices, ++ sizeof(struct disk_info), cmp_disk_info); ++ ++ *disks_info_count = fi_args.num_devices; ++ *disks_info_ptr = info; ++ ++ return 0; ++ ++} ++ ++/* ++ * This function computes the size of a chunk in a disk ++ */ ++static u64 calc_chunk_size(struct chunk_info *ci) ++{ ++ if (ci->type & BTRFS_BLOCK_GROUP_RAID0) ++ return ci->size / ci->num_stripes; ++ else if (ci->type & BTRFS_BLOCK_GROUP_RAID1) ++ return ci->size ; ++ else if (ci->type & BTRFS_BLOCK_GROUP_DUP) ++ return ci->size ; ++ else if (ci->type & BTRFS_BLOCK_GROUP_RAID5) ++ return ci->size / (ci->num_stripes -1); ++ else if (ci->type & BTRFS_BLOCK_GROUP_RAID6) ++ return ci->size / (ci->num_stripes -2); ++ else if (ci->type & BTRFS_BLOCK_GROUP_RAID10) ++ return ci->size / ci->num_stripes; ++ return ci->size; ++} ++ ++/* ++ * This function print the results of the command btrfs fi disk-usage ++ * in tabular format ++ */ ++static void _cmd_filesystem_disk_usage_tabular(int mode, ++ struct btrfs_ioctl_space_args *sargs, ++ struct chunk_info *chunks_info_ptr, ++ int chunks_info_count, ++ struct disk_info *disks_info_ptr, ++ int disks_info_count) ++{ ++ int i; ++ u64 total_unused = 0; ++ struct string_table *matrix = 0; ++ int ncols, nrows; ++ ++ ncols = sargs->total_spaces + 2; ++ nrows = 2 + 1 + disks_info_count + 1 + 2; ++ ++ matrix = table_create(ncols, nrows); ++ if (!matrix) { ++ fprintf(stderr, "ERROR: not enough memory\n"); ++ return; ++ } ++ ++ /* header */ ++ for (i = 0; i < sargs->total_spaces; i++) { ++ const char *description; ++ ++ u64 flags = sargs->spaces[i].flags; ++ description = group_type_str(flags); ++ ++ table_printf(matrix, 1+i, 0, "<%s", description); ++ } ++ ++ for (i = 0; i < sargs->total_spaces; i++) { ++ const char *r_mode; ++ ++ u64 flags = sargs->spaces[i].flags; ++ r_mode = group_profile_str(flags); ++ ++ table_printf(matrix, 1+i, 1, "<%s", r_mode); ++ } ++ ++ table_printf(matrix, 1+sargs->total_spaces, 1, "total_spaces ; k++) { ++ u64 flags = sargs->spaces[k].flags; ++ u64 devid = disks_info_ptr[i].devid; ++ int j; ++ u64 size = 0; ++ ++ for (j = 0 ; j < chunks_info_count ; j++) { ++ if (chunks_info_ptr[j].type != flags ) ++ continue; ++ if (chunks_info_ptr[j].devid != devid) ++ continue; ++ ++ size += calc_chunk_size(chunks_info_ptr+j); ++ } ++ ++ if (size) ++ table_printf(matrix, col, i+3, ++ ">%s", df_pretty_sizes(size, mode)); ++ else ++ table_printf(matrix, col, i+3, ">-"); ++ ++ total_allocated += size; ++ col++; ++ } ++ ++ unused = get_partition_size(disks_info_ptr[i].path) - ++ total_allocated; ++ ++ table_printf(matrix, sargs->total_spaces + 1, i + 3, ++ ">%s", df_pretty_sizes(unused, mode)); ++ total_unused += unused; ++ ++ } ++ ++ for (i = 0; i <= sargs->total_spaces; i++) ++ table_printf(matrix, i + 1, disks_info_count + 3, "="); ++ ++ ++ /* footer */ ++ table_printf(matrix, 0, disks_info_count + 4, "total_spaces; i++) ++ table_printf(matrix, 1 + i, disks_info_count + 4, ++ ">%s", ++ df_pretty_sizes(sargs->spaces[i].total_bytes, mode)); ++ ++ table_printf(matrix, sargs->total_spaces+1, disks_info_count+4, ++ ">%s", df_pretty_sizes(total_unused, mode)); ++ ++ table_printf(matrix, 0, disks_info_count+5, "total_spaces; i++) ++ table_printf(matrix, 1+i, disks_info_count+5, ">%s", ++ df_pretty_sizes(sargs->spaces[i].used_bytes, mode)); ++ ++ ++ table_dump(matrix); ++ table_free(matrix); ++ ++} ++ ++/* ++ * This function prints the unused space per every disk ++ */ ++static void print_unused(struct chunk_info *info_ptr, ++ int info_count, ++ struct disk_info *disks_info_ptr, ++ int disks_info_count, ++ int mode) ++{ ++ int i; ++ for (i = 0 ; i < disks_info_count ; i++) { ++ ++ int j; ++ u64 total = 0; ++ ++ for (j = 0 ; j < info_count ; j++) ++ if (info_ptr[j].devid == disks_info_ptr[i].devid) ++ total += calc_chunk_size(info_ptr+j); ++ ++ printf(" %s\t%10s\n", ++ disks_info_ptr[i].path, ++ df_pretty_sizes(disks_info_ptr[i].size - total, mode)); ++ ++ } ++ ++} ++ ++/* ++ * This function prints the allocated chunk per every disk ++ */ ++static void print_chunk_disks(u64 chunk_type, ++ struct chunk_info *chunks_info_ptr, ++ int chunks_info_count, ++ struct disk_info *disks_info_ptr, ++ int disks_info_count, ++ int mode) ++{ ++ int i; ++ ++ for (i = 0 ; i < disks_info_count ; i++) { ++ ++ int j; ++ u64 total = 0; ++ ++ for (j = 0 ; j < chunks_info_count ; j++) { ++ ++ if (chunks_info_ptr[j].type != chunk_type) ++ continue; ++ if (chunks_info_ptr[j].devid != disks_info_ptr[i].devid) ++ continue; ++ ++ total += calc_chunk_size(&(chunks_info_ptr[j])); ++ //total += chunks_info_ptr[j].size; ++ } ++ ++ if (total > 0) ++ printf(" %s\t%10s\n", ++ disks_info_ptr[i].path, ++ df_pretty_sizes(total, mode)); ++ } ++} ++ ++/* ++ * This function print the results of the command btrfs fi disk-usage ++ * in linear format ++ */ ++static void _cmd_filesystem_disk_usage_linear(int mode, ++ struct btrfs_ioctl_space_args *sargs, ++ struct chunk_info *info_ptr, ++ int info_count, ++ struct disk_info *disks_info_ptr, ++ int disks_info_count) ++{ ++ int i; ++ ++ for (i = 0; i < sargs->total_spaces; i++) { ++ const char *description; ++ const char *r_mode; ++ ++ u64 flags = sargs->spaces[i].flags; ++ description= group_type_str(flags); ++ r_mode = group_profile_str(flags); ++ ++ printf("%s,%s: Size:%s, ", ++ description, ++ r_mode, ++ df_pretty_sizes(sargs->spaces[i].total_bytes , ++ mode)); ++ printf("Used:%s\n", ++ df_pretty_sizes(sargs->spaces[i].used_bytes, ++ mode)); ++ print_chunk_disks(flags, info_ptr, info_count, ++ disks_info_ptr, disks_info_count, ++ mode); ++ printf("\n"); ++ ++ } ++ ++ printf("Unallocated:\n"); ++ print_unused(info_ptr, info_count, ++ disks_info_ptr, disks_info_count, ++ mode); ++ ++ ++ ++} ++ ++static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular) ++{ ++ struct btrfs_ioctl_space_args *sargs = 0; ++ int info_count = 0; ++ struct chunk_info *info_ptr = 0; ++ struct disk_info *disks_info_ptr = 0; ++ int disks_info_count = 0; ++ int ret = 0; ++ ++ if (load_chunk_info(fd, &info_ptr, &info_count) || ++ load_disks_info(fd, &disks_info_ptr, &disks_info_count)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if ((sargs = load_space_info(fd, path)) == NULL) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (tabular) ++ _cmd_filesystem_disk_usage_tabular(mode, sargs, ++ info_ptr, info_count, ++ disks_info_ptr, disks_info_count); ++ else ++ _cmd_filesystem_disk_usage_linear(mode, sargs, ++ info_ptr, info_count, ++ disks_info_ptr, disks_info_count); ++ ++exit: ++ ++ if (sargs) ++ free(sargs); ++ if (disks_info_ptr) ++ free(disks_info_ptr); ++ if (info_ptr) ++ free(info_ptr); ++ ++ return ret; ++} ++ ++const char * const cmd_filesystem_disk_usage_usage[] = { ++ "btrfs filesystem disk-usage [-b][-t] [..]", ++ "Show in which disk the chunks are allocated.", ++ "", ++ "-b\tSet byte as unit", ++ "-t\tShow data in tabular format", ++ NULL ++}; ++ ++int cmd_filesystem_disk_usage(int argc, char **argv) ++{ ++ ++ int flags = DF_HUMAN_UNIT; ++ int i, more_than_one = 0; ++ int tabular = 0; ++ ++ optind = 1; ++ while (1) { ++ char c = getopt(argc, argv, "bt"); ++ if (c < 0) ++ break; ++ switch (c) { ++ case 'b': ++ flags &= ~DF_HUMAN_UNIT; ++ break; ++ case 't': ++ tabular = 1; ++ break; ++ default: ++ usage(cmd_filesystem_disk_usage_usage); ++ } ++ } ++ ++ if (check_argc_min(argc - optind, 1)) { ++ usage(cmd_filesystem_disk_usage_usage); ++ return 21; ++ } ++ ++ for (i = optind; i < argc ; i++) { ++ int r, fd; ++ DIR *dirstream = NULL; ++ if (more_than_one) ++ printf("\n"); ++ ++ fd = open_file_or_dir(argv[i], &dirstream); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: can't access to '%s'\n", ++ argv[1]); ++ return 12; ++ } ++ r = _cmd_filesystem_disk_usage(fd, argv[i], flags, tabular); ++ close_file_or_dir(fd, dirstream); ++ ++ if (r) ++ return r; ++ more_than_one = 1; ++ ++ } ++ ++ return 0; ++} +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +index 9f68bb342d52..c7459b1521e4 100644 +--- a/cmds-fi-disk_usage.h ++++ b/cmds-fi-disk_usage.h +@@ -22,4 +22,7 @@ + extern const char * const cmd_filesystem_df_usage[]; + int cmd_filesystem_df(int argc, char **argv); + ++extern const char * const cmd_filesystem_disk_usage_usage[]; ++int cmd_filesystem_disk_usage(int argc, char **argv); ++ + #endif +diff --git a/cmds-filesystem.c b/cmds-filesystem.c +index 0edfb50daca2..214a0cda518c 100644 +--- a/cmds-filesystem.c ++++ b/cmds-filesystem.c +@@ -918,6 +918,9 @@ const struct cmd_group filesystem_cmd_group = { + { "balance", cmd_balance, NULL, &balance_cmd_group, 1 }, + { "resize", cmd_resize, cmd_resize_usage, NULL, 0 }, + { "label", cmd_label, cmd_label_usage, NULL, 0 }, ++ { "disk-usage", cmd_filesystem_disk_usage, ++ cmd_filesystem_disk_usage_usage, NULL, 0 }, ++ + NULL_CMD_STRUCT + } + }; +diff --git a/utils.c b/utils.c +index 7731b071f353..f2ab416c28b2 100644 +--- a/utils.c ++++ b/utils.c +@@ -2218,3 +2218,63 @@ u64 disk_size(char *path) + else + return sfs.f_bsize * sfs.f_blocks; + } ++ ++u64 get_partition_size(char *dev) ++{ ++ u64 result; ++ int fd = open(dev, O_RDONLY); ++ ++ if (fd < 0) ++ return 0; ++ if (ioctl(fd, BLKGETSIZE64, &result) < 0) { ++ close(fd); ++ return 0; ++ } ++ close(fd); ++ ++ return result; ++} ++ ++/* ++ * Convert a chunk type to a chunk description ++ */ ++const char *group_type_str(u64 flag) ++{ ++ switch (flag & BTRFS_BLOCK_GROUP_TYPE_MASK) { ++ case BTRFS_BLOCK_GROUP_DATA: ++ return "Data"; ++ case BTRFS_BLOCK_GROUP_SYSTEM: ++ return "System"; ++ case BTRFS_BLOCK_GROUP_METADATA: ++ return "Metadata"; ++ case BTRFS_BLOCK_GROUP_DATA|BTRFS_BLOCK_GROUP_METADATA: ++ return "Data+Metadata"; ++ default: ++ return "unknown"; ++ } ++} ++ ++/* ++ * Convert a chunk type to a chunk profile description ++ */ ++const char *group_profile_str(u64 flag) ++{ ++ switch (flag & BTRFS_BLOCK_GROUP_PROFILE_MASK) { ++ case 0: ++ return "single"; ++ case BTRFS_BLOCK_GROUP_RAID0: ++ return "RAID0"; ++ case BTRFS_BLOCK_GROUP_RAID1: ++ return "RAID1"; ++ case BTRFS_BLOCK_GROUP_RAID5: ++ return "RAID5"; ++ case BTRFS_BLOCK_GROUP_RAID6: ++ return "RAID6"; ++ case BTRFS_BLOCK_GROUP_DUP: ++ return "DUP"; ++ case BTRFS_BLOCK_GROUP_RAID10: ++ return "RAID10"; ++ default: ++ return "unknown"; ++ } ++} +diff --git a/utils.h b/utils.h +index 581faa9f6972..2d08e0b2a3a4 100644 +--- a/utils.h ++++ b/utils.h +@@ -102,5 +102,10 @@ int find_mount_root(const char *path, char **mount_root); + int get_device_info(int fd, u64 devid, + struct btrfs_ioctl_dev_info_args *di_args); + u64 disk_size(char *path); ++int get_device_info(int fd, u64 devid, ++ struct btrfs_ioctl_dev_info_args *di_args); ++u64 get_partition_size(char *dev); ++const char* group_type_str(u64 flags); ++const char* group_profile_str(u64 flags); + + #endif +-- +1.9.0 + diff --git a/0014-btrfs-progs-Add-btrfs-device-disk-usage-command.patch b/0014-btrfs-progs-Add-btrfs-device-disk-usage-command.patch new file mode 100644 index 0000000..dad81a1 --- /dev/null +++ b/0014-btrfs-progs-Add-btrfs-device-disk-usage-command.patch @@ -0,0 +1,193 @@ +From b8eb50e005cc92d870faf6bfe285950c4ac66e09 Mon Sep 17 00:00:00 2001 +From: Goffredo Baroncelli +Date: Thu, 13 Feb 2014 20:20:12 +0100 +Subject: [PATCH 25/42] btrfs-progs: Add btrfs device disk-usage command + +Signed-off-by: Goffredo Baroncelli +Signed-off-by: David Sterba +--- + cmds-device.c | 3 ++ + cmds-fi-disk_usage.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++ + cmds-fi-disk_usage.h | 3 ++ + 3 files changed, 142 insertions(+) + +diff --git a/cmds-device.c b/cmds-device.c +index 29da661e2a0d..f2e08ba55ba6 100644 +--- a/cmds-device.c ++++ b/cmds-device.c +@@ -28,6 +28,7 @@ + #include "ctree.h" + #include "ioctl.h" + #include "utils.h" ++#include "cmds-fi-disk_usage.h" + + #include "commands.h" + +@@ -435,6 +436,8 @@ const struct cmd_group device_cmd_group = { + { "scan", cmd_scan_dev, cmd_scan_dev_usage, NULL, 0 }, + { "ready", cmd_ready_dev, cmd_ready_dev_usage, NULL, 0 }, + { "stats", cmd_dev_stats, cmd_dev_stats_usage, NULL, 0 }, ++ { "disk-usage", cmd_device_disk_usage, ++ cmd_device_disk_usage_usage, NULL, 0 }, + NULL_CMD_STRUCT + } + }; +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 16b3ab250956..e4eb72be0a88 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -942,3 +942,139 @@ int cmd_filesystem_disk_usage(int argc, char **argv) + + return 0; + } ++ ++static void print_disk_chunks(int fd, ++ u64 devid, ++ u64 total_size, ++ struct chunk_info *chunks_info_ptr, ++ int chunks_info_count, ++ int mode) ++{ ++ int i; ++ u64 allocated = 0; ++ ++ for (i = 0 ; i < chunks_info_count ; i++) { ++ const char *description; ++ const char *r_mode; ++ u64 flags; ++ u64 size; ++ ++ if (chunks_info_ptr[i].devid != devid) ++ continue; ++ ++ flags = chunks_info_ptr[i].type; ++ ++ description = group_type_str(flags); ++ r_mode = group_profile_str(flags); ++ size = calc_chunk_size(chunks_info_ptr+i); ++ printf(" %s,%s:%*s%10s\n", ++ description, ++ r_mode, ++ (int)(20 - strlen(description) - strlen(r_mode)), "", ++ df_pretty_sizes(size, mode)); ++ ++ allocated += size; ++ ++ } ++ printf(" Unallocated: %*s%10s\n", ++ (int)(20 - strlen("Unallocated")), "", ++ df_pretty_sizes(total_size - allocated, mode)); ++ ++} ++ ++static int _cmd_device_disk_usage(int fd, char *path, int mode) ++{ ++ int i; ++ int ret = 0; ++ int info_count = 0; ++ struct chunk_info *info_ptr = 0; ++ struct disk_info *disks_info_ptr = 0; ++ int disks_info_count = 0; ++ ++ if (load_chunk_info(fd, &info_ptr, &info_count) || ++ load_disks_info(fd, &disks_info_ptr, &disks_info_count)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ for (i = 0 ; i < disks_info_count ; i++) { ++ printf("%s\t%10s\n", disks_info_ptr[i].path, ++ df_pretty_sizes(disks_info_ptr[i].size, mode)); ++ ++ print_disk_chunks(fd, disks_info_ptr[i].devid, ++ disks_info_ptr[i].size, ++ info_ptr, info_count, ++ mode); ++ printf("\n"); ++ ++ } ++ ++ ++exit: ++ ++ if (disks_info_ptr) ++ free(disks_info_ptr); ++ if (info_ptr) ++ free(info_ptr); ++ ++ return ret; ++} ++ ++const char * const cmd_device_disk_usage_usage[] = { ++ "btrfs device disk-usage [-b] [..]", ++ "Show which chunks are in a device.", ++ "", ++ "-b\tSet byte as unit", ++ NULL ++}; ++ ++int cmd_device_disk_usage(int argc, char **argv) ++{ ++ ++ int flags = DF_HUMAN_UNIT; ++ int i, more_than_one = 0; ++ ++ optind = 1; ++ while (1) { ++ char c = getopt(argc, argv, "b"); ++ ++ if (c < 0) ++ break; ++ ++ switch (c) { ++ case 'b': ++ flags &= ~DF_HUMAN_UNIT; ++ break; ++ default: ++ usage(cmd_device_disk_usage_usage); ++ } ++ } ++ ++ if (check_argc_min(argc - optind, 1)) { ++ usage(cmd_device_disk_usage_usage); ++ return 21; ++ } ++ ++ for (i = optind; i < argc ; i++) { ++ int r, fd; ++ DIR *dirstream = NULL; ++ if (more_than_one) ++ printf("\n"); ++ ++ fd = open_file_or_dir(argv[i], &dirstream); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: can't access to '%s'\n", ++ argv[1]); ++ return 12; ++ } ++ r = _cmd_device_disk_usage(fd, argv[i], flags); ++ close_file_or_dir(fd, dirstream); ++ ++ if (r) ++ return r; ++ more_than_one = 1; ++ ++ } ++ ++ return 0; ++} +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +index c7459b1521e4..c315004cd806 100644 +--- a/cmds-fi-disk_usage.h ++++ b/cmds-fi-disk_usage.h +@@ -25,4 +25,7 @@ int cmd_filesystem_df(int argc, char **argv); + extern const char * const cmd_filesystem_disk_usage_usage[]; + int cmd_filesystem_disk_usage(int argc, char **argv); + ++extern const char * const cmd_device_disk_usage_usage[]; ++int cmd_device_disk_usage(int argc, char **argv); ++ + #endif +-- +1.9.0 + diff --git a/0015-btrfs-progs-cleanup-dead-return-after-usage-for-fi-d.patch b/0015-btrfs-progs-cleanup-dead-return-after-usage-for-fi-d.patch new file mode 100644 index 0000000..caa7c52 --- /dev/null +++ b/0015-btrfs-progs-cleanup-dead-return-after-usage-for-fi-d.patch @@ -0,0 +1,57 @@ +From a604369c26e4e816579c59d7a595279b1b720cbc Mon Sep 17 00:00:00 2001 +From: Gui Hecheng +Date: Thu, 6 Mar 2014 11:36:46 +0800 +Subject: [PATCH 26/42] btrfs-progs: cleanup dead return after usage() for + fi-disk_usage + +The usage() calls exit() internally, so remove the return after it. + +Signed-off-by: Gui Hecheng +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index e4eb72be0a88..a3b06bebba72 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -494,10 +494,8 @@ int cmd_filesystem_df(int argc, char **argv) + } + } + +- if (check_argc_min(argc - optind, 1)) { ++ if (check_argc_min(argc - optind, 1)) + usage(cmd_filesystem_df_usage); +- return 21; +- } + + for (i = optind; i < argc ; i++) { + int r, fd; +@@ -914,10 +912,8 @@ int cmd_filesystem_disk_usage(int argc, char **argv) + } + } + +- if (check_argc_min(argc - optind, 1)) { ++ if (check_argc_min(argc - optind, 1)) + usage(cmd_filesystem_disk_usage_usage); +- return 21; +- } + + for (i = optind; i < argc ; i++) { + int r, fd; +@@ -1050,10 +1046,8 @@ int cmd_device_disk_usage(int argc, char **argv) + } + } + +- if (check_argc_min(argc - optind, 1)) { ++ if (check_argc_min(argc - optind, 1)) + usage(cmd_device_disk_usage_usage); +- return 21; +- } + + for (i = optind; i < argc ; i++) { + int r, fd; +-- +1.9.0 + diff --git a/0016-btrfs-progs-Fix-memleak-in-get_raid56_used.patch b/0016-btrfs-progs-Fix-memleak-in-get_raid56_used.patch new file mode 100644 index 0000000..cc8aebe --- /dev/null +++ b/0016-btrfs-progs-Fix-memleak-in-get_raid56_used.patch @@ -0,0 +1,28 @@ +From ef568dad3da6887e656be617a178cbb69b36cdf3 Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Wed, 19 Mar 2014 06:10:02 +0000 +Subject: [PATCH 27/42] btrfs-progs: Fix memleak in get_raid56_used() + +Fix memleak in get_raid56_used(). + +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index a3b06bebba72..2bd591db0f8a 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -352,6 +352,7 @@ static int get_raid56_used(int fd, u64 *raid5_used, u64 *raid6_used) + if (p->type & BTRFS_BLOCK_GROUP_RAID6) + (*raid6_used) += p->size / (p->num_stripes -2); + } ++ free(info_ptr); + + return 0; + +-- +1.9.0 + diff --git a/0017-Btrfs-progs-fi-usage-free-memory-if-realloc-fails.patch b/0017-Btrfs-progs-fi-usage-free-memory-if-realloc-fails.patch new file mode 100644 index 0000000..4dd9a9e --- /dev/null +++ b/0017-Btrfs-progs-fi-usage-free-memory-if-realloc-fails.patch @@ -0,0 +1,38 @@ +From b43d0660526d1a3e81f34fd499eb1dd038b00e08 Mon Sep 17 00:00:00 2001 +From: Rakesh Pandit +Date: Sat, 19 Apr 2014 14:12:03 +0300 +Subject: [PATCH 28/42] Btrfs-progs: fi usage: free memory if realloc fails + +Lets not assign *info_ptr to 0 before calling free on it and lose +track of already allocated memory if realloc fails in +add_info_to_list. Lets call free first. + +Signed-off-by: Rakesh Pandit +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 2bd591db0f8a..cd71c8da3cf4 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -104,6 +104,7 @@ static int add_info_to_list(struct chunk_info **info_ptr, + struct chunk_info *res = realloc(*info_ptr, size); + + if (!res) { ++ free(*info_ptr); + fprintf(stderr, "ERROR: not enough memory\n"); + return -1; + } +@@ -224,7 +225,6 @@ static int load_chunk_info(int fd, + + if (add_info_to_list(info_ptr, info_count, item)) { + *info_ptr = 0; +- free(*info_ptr); + return -100; + } + +-- +1.9.0 + diff --git a/0018-btrfs-progs-read-global-reserve-size-from-space-info.patch b/0018-btrfs-progs-read-global-reserve-size-from-space-info.patch new file mode 100644 index 0000000..67ddf9d --- /dev/null +++ b/0018-btrfs-progs-read-global-reserve-size-from-space-info.patch @@ -0,0 +1,60 @@ +From 28c2061817b8cb266458249cc7bdd770eb2b407b Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Thu, 16 Jan 2014 14:18:37 +0100 +Subject: [PATCH 29/42] btrfs-progs: read global reserve size from space infos + +Kernels >= 3.15 export the global block reserve as a space info presented +by 'btrfs fi df' but would display 'unknown' instead of some meaningful +string. + +Signed-off-by: David Sterba +--- + ctree.h | 6 ++++++ + utils.c | 7 ++++++- + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/ctree.h b/ctree.h +index 8ac17619b9dc..5c43fc5f5f6e 100644 +--- a/ctree.h ++++ b/ctree.h +@@ -862,6 +862,12 @@ struct btrfs_csum_item { + /* used in struct btrfs_balance_args fields */ + #define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) + ++/* ++ * GLOBAL_RSV does not exist as a on-disk block group type and is used ++ * internally for exporting info about global block reserve from space infos ++ */ ++#define BTRFS_SPACE_INFO_GLOBAL_RSV (1ULL << 49) ++ + #define BTRFS_QGROUP_STATUS_OFF 0 + #define BTRFS_QGROUP_STATUS_ON 1 + #define BTRFS_QGROUP_STATUS_SCANNING 2 +diff --git a/utils.c b/utils.c +index f2ab416c28b2..ca150404ea6f 100644 +--- a/utils.c ++++ b/utils.c +@@ -2240,7 +2240,10 @@ u64 get_partition_size(char *dev) + */ + const char *group_type_str(u64 flag) + { +- switch (flag & BTRFS_BLOCK_GROUP_TYPE_MASK) { ++ u64 mask = BTRFS_BLOCK_GROUP_TYPE_MASK | ++ BTRFS_SPACE_INFO_GLOBAL_RSV; ++ ++ switch (flag & mask) { + case BTRFS_BLOCK_GROUP_DATA: + return "Data"; + case BTRFS_BLOCK_GROUP_SYSTEM: +@@ -2249,6 +2252,8 @@ const char *group_type_str(u64 flag) + return "Metadata"; + case BTRFS_BLOCK_GROUP_DATA|BTRFS_BLOCK_GROUP_METADATA: + return "Data+Metadata"; ++ case BTRFS_SPACE_INFO_GLOBAL_RSV: ++ return "GlobalReserve"; + default: + return "unknown"; + } +-- +1.9.0 + diff --git a/0019-btrfs-progs-add-original-df-and-rename-disk_usage-to.patch b/0019-btrfs-progs-add-original-df-and-rename-disk_usage-to.patch new file mode 100644 index 0000000..18f2470 --- /dev/null +++ b/0019-btrfs-progs-add-original-df-and-rename-disk_usage-to.patch @@ -0,0 +1,289 @@ +From 90cbd00127631b5f8964d5518d6b22bfe994a686 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Wed, 23 Apr 2014 18:47:52 +0200 +Subject: [PATCH 30/42] btrfs-progs: add original 'df' and rename 'disk_usage' + to 'usage' + +Add back the original output of the 'btrfs fi df' command for backward +compatibility. The rich output is moved from 'disk_usage' to 'usage'. + +Agreed in http://www.spinics.net/lists/linux-btrfs/msg31698.html + +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 85 ++++++++++------------------------------------------ + cmds-fi-disk_usage.h | 7 ++--- + cmds-filesystem.c | 55 ++++++++++++++++++++++++++++++++-- + 3 files changed, 71 insertions(+), 76 deletions(-) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index cd71c8da3cf4..efc640d13148 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -328,6 +328,8 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) + return sargs; + } + ++/* Not used, keep for later */ ++#if 0 + /* + * This function computes the space occuped by a *single* RAID5/RAID6 chunk. + * The computation is performed on the basis of the number of stripes +@@ -465,62 +467,7 @@ exit: + + return ret; + } +- +-const char * const cmd_filesystem_df_usage[] = { +- "btrfs filesystem df [-b] [..]", +- "Show space usage information for a mount point(s).", +- "", +- "-b\tSet byte as unit", +- NULL +-}; +- +-int cmd_filesystem_df(int argc, char **argv) +-{ +- +- int flags = DF_HUMAN_UNIT; +- int i, more_than_one = 0; +- +- optind = 1; +- while (1) { +- char c = getopt(argc, argv, "b"); +- if (c < 0) +- break; +- +- switch (c) { +- case 'b': +- flags &= ~DF_HUMAN_UNIT; +- break; +- default: +- usage(cmd_filesystem_df_usage); +- } +- } +- +- if (check_argc_min(argc - optind, 1)) +- usage(cmd_filesystem_df_usage); +- +- for (i = optind; i < argc ; i++) { +- int r, fd; +- DIR *dirstream = NULL; +- if (more_than_one) +- printf("\n"); +- +- fd = open_file_or_dir(argv[i], &dirstream); +- if (fd < 0) { +- fprintf(stderr, "ERROR: can't access to '%s'\n", +- argv[1]); +- return 12; +- } +- r = _cmd_disk_free(fd, argv[i], flags); +- close_file_or_dir(fd, dirstream); +- +- if (r) +- return r; +- more_than_one = 1; +- +- } +- +- return 0; +-} ++#endif + + /* + * Helper to sort the disk_info structure +@@ -612,10 +559,10 @@ static u64 calc_chunk_size(struct chunk_info *ci) + } + + /* +- * This function print the results of the command btrfs fi disk-usage ++ * This function print the results of the command "btrfs fi usage" + * in tabular format + */ +-static void _cmd_filesystem_disk_usage_tabular(int mode, ++static void _cmd_filesystem_usage_tabular(int mode, + struct btrfs_ioctl_space_args *sargs, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, +@@ -795,10 +742,10 @@ static void print_chunk_disks(u64 chunk_type, + } + + /* +- * This function print the results of the command btrfs fi disk-usage ++ * This function print the results of the command "btrfs fi usage" + * in linear format + */ +-static void _cmd_filesystem_disk_usage_linear(int mode, ++static void _cmd_filesystem_usage_linear(int mode, + struct btrfs_ioctl_space_args *sargs, + struct chunk_info *info_ptr, + int info_count, +@@ -839,7 +786,7 @@ static void _cmd_filesystem_disk_usage_linear(int mode, + + } + +-static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular) ++static int _cmd_filesystem_usage(int fd, char *path, int mode, int tabular) + { + struct btrfs_ioctl_space_args *sargs = 0; + int info_count = 0; +@@ -860,11 +807,11 @@ static int _cmd_filesystem_disk_usage(int fd, char *path, int mode, int tabular) + } + + if (tabular) +- _cmd_filesystem_disk_usage_tabular(mode, sargs, ++ _cmd_filesystem_usage_tabular(mode, sargs, + info_ptr, info_count, + disks_info_ptr, disks_info_count); + else +- _cmd_filesystem_disk_usage_linear(mode, sargs, ++ _cmd_filesystem_usage_linear(mode, sargs, + info_ptr, info_count, + disks_info_ptr, disks_info_count); + +@@ -880,8 +827,8 @@ exit: + return ret; + } + +-const char * const cmd_filesystem_disk_usage_usage[] = { +- "btrfs filesystem disk-usage [-b][-t] [..]", ++const char * const cmd_filesystem_usage_usage[] = { ++ "btrfs filesystem usage [-b][-t] [..]", + "Show in which disk the chunks are allocated.", + "", + "-b\tSet byte as unit", +@@ -889,7 +836,7 @@ const char * const cmd_filesystem_disk_usage_usage[] = { + NULL + }; + +-int cmd_filesystem_disk_usage(int argc, char **argv) ++int cmd_filesystem_usage(int argc, char **argv) + { + + int flags = DF_HUMAN_UNIT; +@@ -909,12 +856,12 @@ int cmd_filesystem_disk_usage(int argc, char **argv) + tabular = 1; + break; + default: +- usage(cmd_filesystem_disk_usage_usage); ++ usage(cmd_filesystem_usage_usage); + } + } + + if (check_argc_min(argc - optind, 1)) +- usage(cmd_filesystem_disk_usage_usage); ++ usage(cmd_filesystem_usage_usage); + + for (i = optind; i < argc ; i++) { + int r, fd; +@@ -928,7 +875,7 @@ int cmd_filesystem_disk_usage(int argc, char **argv) + argv[1]); + return 12; + } +- r = _cmd_filesystem_disk_usage(fd, argv[i], flags, tabular); ++ r = _cmd_filesystem_usage(fd, argv[i], flags, tabular); + close_file_or_dir(fd, dirstream); + + if (r) +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +index c315004cd806..95cf4aabefb4 100644 +--- a/cmds-fi-disk_usage.h ++++ b/cmds-fi-disk_usage.h +@@ -19,11 +19,8 @@ + #ifndef __CMDS_FI_DISK_USAGE__ + #define __CMDS_FI_DISK_USAGE__ + +-extern const char * const cmd_filesystem_df_usage[]; +-int cmd_filesystem_df(int argc, char **argv); +- +-extern const char * const cmd_filesystem_disk_usage_usage[]; +-int cmd_filesystem_disk_usage(int argc, char **argv); ++extern const char * const cmd_filesystem_usage_usage[]; ++int cmd_filesystem_usage(int argc, char **argv); + + extern const char * const cmd_device_disk_usage_usage[]; + int cmd_device_disk_usage(int argc, char **argv); +diff --git a/cmds-filesystem.c b/cmds-filesystem.c +index 214a0cda518c..9340cb61cabe 100644 +--- a/cmds-filesystem.c ++++ b/cmds-filesystem.c +@@ -113,6 +113,26 @@ static const char * const filesystem_cmd_group_usage[] = { + NULL + }; + ++static const char * const cmd_filesystem_df_usage[] = { ++ "btrfs filesystem df ", ++ "Show space usage information for a mount point", ++ NULL ++}; ++ ++static void print_df(struct btrfs_ioctl_space_args *sargs) ++{ ++ u64 i; ++ struct btrfs_ioctl_space_info *sp = sargs->spaces; ++ ++ for (i = 0; i < sargs->total_spaces; i++, sp++) { ++ printf("%s, %s: total=%s, used=%s\n", ++ group_type_str(sp->flags), ++ group_profile_str(sp->flags), ++ pretty_size(sp->total_bytes), ++ pretty_size(sp->used_bytes)); ++ } ++} ++ + static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret) + { + u64 count = 0; +@@ -161,6 +181,37 @@ static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret) + return 0; + } + ++static int cmd_filesystem_df(int argc, char **argv) ++{ ++ struct btrfs_ioctl_space_args *sargs = NULL; ++ int ret; ++ int fd; ++ char *path; ++ DIR *dirstream = NULL; ++ ++ if (check_argc_exact(argc, 2)) ++ usage(cmd_filesystem_df_usage); ++ ++ path = argv[1]; ++ ++ fd = open_file_or_dir(path, &dirstream); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: can't access '%s'\n", path); ++ return 1; ++ } ++ ret = get_df(fd, &sargs); ++ ++ if (!ret && sargs) { ++ print_df(sargs); ++ free(sargs); ++ } else { ++ fprintf(stderr, "ERROR: get_df failed %s\n", strerror(-ret)); ++ } ++ ++ close_file_or_dir(fd, dirstream); ++ return !!ret; ++} ++ + static int match_search_item_kernel(__u8 *fsid, char *mnt, char *label, + char *search) + { +@@ -918,8 +969,8 @@ const struct cmd_group filesystem_cmd_group = { + { "balance", cmd_balance, NULL, &balance_cmd_group, 1 }, + { "resize", cmd_resize, cmd_resize_usage, NULL, 0 }, + { "label", cmd_label, cmd_label_usage, NULL, 0 }, +- { "disk-usage", cmd_filesystem_disk_usage, +- cmd_filesystem_disk_usage_usage, NULL, 0 }, ++ { "usage", cmd_filesystem_usage, ++ cmd_filesystem_usage_usage, NULL, 0 }, + + NULL_CMD_STRUCT + } +-- +1.9.0 + diff --git a/0020-btrfs-progs-move-device-usage-to-cmds-device-more-cl.patch b/0020-btrfs-progs-move-device-usage-to-cmds-device-more-cl.patch new file mode 100644 index 0000000..f693cc0 --- /dev/null +++ b/0020-btrfs-progs-move-device-usage-to-cmds-device-more-cl.patch @@ -0,0 +1,712 @@ +From 14462c746c40b97dd8efe0bea18cbc6372431a39 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Wed, 23 Apr 2014 19:00:22 +0200 +Subject: [PATCH 31/42] btrfs-progs: move device usage to cmds-device, more + cleanups + +Move the command definitions where they belong, keep common 'usage' +functions in cmds-fi-disk_usage.c and add exports. + +Rename structures containing 'disk' to 'device'. + +Fix whitespace in the modified code. + +Signed-off-by: David Sterba +--- + cmds-device.c | 96 +++++++++++++++++- + cmds-fi-disk_usage.c | 281 ++++++++++++--------------------------------------- + cmds-fi-disk_usage.h | 30 +++++- + 3 files changed, 188 insertions(+), 219 deletions(-) + +diff --git a/cmds-device.c b/cmds-device.c +index f2e08ba55ba6..c20b26e9be90 100644 +--- a/cmds-device.c ++++ b/cmds-device.c +@@ -429,6 +429,98 @@ out: + return err; + } + ++const char * const cmd_device_usage_usage[] = { ++ "btrfs device usage [-b] [..]", ++ "Show which chunks are in a device.", ++ "", ++ "-b\tSet byte as unit", ++ NULL ++}; ++ ++static int _cmd_device_usage(int fd, char *path, int mode) ++{ ++ int i; ++ int ret = 0; ++ int info_count = 0; ++ struct chunk_info *info_ptr = 0; ++ struct device_info *device_info_ptr = 0; ++ int device_info_count = 0; ++ ++ if (load_chunk_info(fd, &info_ptr, &info_count) || ++ load_device_info(fd, &device_info_ptr, &device_info_count)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ for (i = 0; i < device_info_count; i++) { ++ printf("%s\t%10s\n", device_info_ptr[i].path, ++ df_pretty_sizes(device_info_ptr[i].size, mode)); ++ ++ print_device_chunks(fd, device_info_ptr[i].devid, ++ device_info_ptr[i].size, ++ info_ptr, info_count, ++ mode); ++ printf("\n"); ++ } ++ ++exit: ++ if (device_info_ptr) ++ free(device_info_ptr); ++ if (info_ptr) ++ free(info_ptr); ++ ++ return ret; ++} ++ ++int cmd_device_usage(int argc, char **argv) ++{ ++ ++ int flags = DF_HUMAN_UNIT; ++ int i, more_than_one = 0; ++ ++ optind = 1; ++ while (1) { ++ char c = getopt(argc, argv, "b"); ++ ++ if (c < 0) ++ break; ++ ++ switch (c) { ++ case 'b': ++ flags &= ~DF_HUMAN_UNIT; ++ break; ++ default: ++ usage(cmd_device_usage_usage); ++ } ++ } ++ ++ if (check_argc_min(argc - optind, 1)) ++ usage(cmd_device_usage_usage); ++ ++ for (i = optind; i < argc ; i++) { ++ int r, fd; ++ DIR *dirstream = NULL; ++ if (more_than_one) ++ printf("\n"); ++ ++ fd = open_file_or_dir(argv[i], &dirstream); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: can't access to '%s'\n", ++ argv[1]); ++ return 12; ++ } ++ r = _cmd_device_usage(fd, argv[i], flags); ++ close_file_or_dir(fd, dirstream); ++ ++ if (r) ++ return r; ++ more_than_one = 1; ++ ++ } ++ ++ return 0; ++} ++ + const struct cmd_group device_cmd_group = { + device_cmd_group_usage, NULL, { + { "add", cmd_add_dev, cmd_add_dev_usage, NULL, 0 }, +@@ -436,8 +528,8 @@ const struct cmd_group device_cmd_group = { + { "scan", cmd_scan_dev, cmd_scan_dev_usage, NULL, 0 }, + { "ready", cmd_ready_dev, cmd_ready_dev_usage, NULL, 0 }, + { "stats", cmd_dev_stats, cmd_dev_stats_usage, NULL, 0 }, +- { "disk-usage", cmd_device_disk_usage, +- cmd_device_disk_usage_usage, NULL, 0 }, ++ { "usage", cmd_device_usage, ++ cmd_device_usage_usage, NULL, 0 }, + NULL_CMD_STRUCT + } + }; +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index efc640d13148..023659daac0e 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -26,38 +26,16 @@ + #include "kerncompat.h" + #include "ctree.h" + #include "string_table.h" +- ++#include "cmds-fi-disk_usage.h" + #include "commands.h" + + #include "version.h" + +-#define DF_HUMAN_UNIT (1<<0) +- +-/* +- * To store the size information about the chunks: +- * the chunks info are grouped by the tuple (type, devid, num_stripes), +- * i.e. if two chunks are of the same type (RAID1, DUP...), are on the +- * same disk, have the same stripes then their sizes are grouped +- */ +-struct chunk_info { +- u64 type; +- u64 size; +- u64 devid; +- u64 num_stripes; +-}; +- +-/* to store information about the disks */ +-struct disk_info { +- u64 devid; +- char path[BTRFS_DEVICE_PATH_NAME_MAX]; +- u64 size; +-}; +- + /* + * Pretty print the size + * PAY ATTENTION: it return a statically buffer + */ +-static char *df_pretty_sizes(u64 size, int mode) ++char *df_pretty_sizes(u64 size, int mode) + { + static char buf[30]; + +@@ -163,14 +141,8 @@ static int cmp_chunk_info(const void *a, const void *b) + ((struct chunk_info *)b)->type); + } + +-/* +- * This function load all the chunk info from the 'fd' filesystem +- */ +-static int load_chunk_info(int fd, +- struct chunk_info **info_ptr, +- int *info_count) ++int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count) + { +- + int ret; + struct btrfs_ioctl_search_args args; + struct btrfs_ioctl_search_key *sk = &args.key; +@@ -178,7 +150,6 @@ static int load_chunk_info(int fd, + unsigned long off = 0; + int i, e; + +- + memset(&args, 0, sizeof(args)); + + /* +@@ -186,8 +157,6 @@ static int load_chunk_info(int fd, + * snapshots pending deletion, we have to loop through + * them. + */ +- +- + sk->tree_id = BTRFS_CHUNK_TREE_OBJECTID; + + sk->min_objectid = 0; +@@ -253,7 +222,6 @@ static int load_chunk_info(int fd, + cmp_chunk_info); + + return 0; +- + } + + /* +@@ -333,7 +301,7 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) + /* + * This function computes the space occuped by a *single* RAID5/RAID6 chunk. + * The computation is performed on the basis of the number of stripes +- * which compose the chunk, which could be different from the number of disks ++ * which compose the chunk, which could be different from the number of devices + * if a disk is added later. + */ + static int get_raid56_used(int fd, u64 *raid5_used, u64 *raid6_used) +@@ -367,7 +335,7 @@ static int _cmd_disk_free(int fd, char *path, int mode) + int ret = 0; + int e, width; + u64 total_disk; /* filesystem size == sum of +- disks sizes */ ++ device sizes */ + u64 total_chunks; /* sum of chunks sizes on disk(s) */ + u64 total_used; /* logical space used */ + u64 total_free; /* logical space un-used */ +@@ -470,29 +438,27 @@ exit: + #endif + + /* +- * Helper to sort the disk_info structure ++ * Helper to sort the device_info structure + */ +-static int cmp_disk_info(const void *a, const void *b) ++static int cmp_device_info(const void *a, const void *b) + { +- return strcmp(((struct disk_info *)a)->path, +- ((struct disk_info *)b)->path); ++ return strcmp(((struct device_info *)a)->path, ++ ((struct device_info *)b)->path); + } + + /* +- * This function load the disk_info structure and put them in an array ++ * This function loads the device_info structure and put them in an array + */ +-static int load_disks_info(int fd, +- struct disk_info **disks_info_ptr, +- int *disks_info_count) ++int load_device_info(int fd, struct device_info **device_info_ptr, ++ int *device_info_count) + { +- + int ret, i, ndevs; + struct btrfs_ioctl_fs_info_args fi_args; + struct btrfs_ioctl_dev_info_args dev_info; +- struct disk_info *info; ++ struct device_info *info; + +- *disks_info_count = 0; +- *disks_info_ptr = 0; ++ *device_info_count = 0; ++ *device_info_ptr = 0; + + ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); + if (ret < 0) { +@@ -500,7 +466,7 @@ static int load_disks_info(int fd, + return -1; + } + +- info = malloc(sizeof(struct disk_info) * fi_args.num_devices); ++ info = malloc(sizeof(struct device_info) * fi_args.num_devices); + if (!info) { + fprintf(stderr, "ERROR: not enough memory\n"); + return -1; +@@ -529,13 +495,12 @@ static int load_disks_info(int fd, + + BUG_ON(ndevs != fi_args.num_devices); + qsort(info, fi_args.num_devices, +- sizeof(struct disk_info), cmp_disk_info); ++ sizeof(struct device_info), cmp_device_info); + +- *disks_info_count = fi_args.num_devices; +- *disks_info_ptr = info; ++ *device_info_count = fi_args.num_devices; ++ *device_info_ptr = info; + + return 0; +- + } + + /* +@@ -566,8 +531,8 @@ static void _cmd_filesystem_usage_tabular(int mode, + struct btrfs_ioctl_space_args *sargs, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, +- struct disk_info *disks_info_ptr, +- int disks_info_count) ++ struct device_info *device_info_ptr, ++ int device_info_count) + { + int i; + u64 total_unused = 0; +@@ -575,7 +540,7 @@ static void _cmd_filesystem_usage_tabular(int mode, + int ncols, nrows; + + ncols = sargs->total_spaces + 2; +- nrows = 2 + 1 + disks_info_count + 1 + 2; ++ nrows = 2 + 1 + device_info_count + 1 + 2; + + matrix = table_create(ncols, nrows); + if (!matrix) { +@@ -605,24 +570,23 @@ static void _cmd_filesystem_usage_tabular(int mode, + table_printf(matrix, 1+sargs->total_spaces, 1, "total_spaces ; k++) { + u64 flags = sargs->spaces[k].flags; +- u64 devid = disks_info_ptr[i].devid; ++ u64 devid = device_info_ptr[i].devid; + int j; + u64 size = 0; + +@@ -645,8 +609,8 @@ static void _cmd_filesystem_usage_tabular(int mode, + col++; + } + +- unused = get_partition_size(disks_info_ptr[i].path) - +- total_allocated; ++ unused = get_partition_size(device_info_ptr[i].path) ++ - total_allocated; + + table_printf(matrix, sargs->total_spaces + 1, i + 3, + ">%s", df_pretty_sizes(unused, mode)); +@@ -655,28 +619,24 @@ static void _cmd_filesystem_usage_tabular(int mode, + } + + for (i = 0; i <= sargs->total_spaces; i++) +- table_printf(matrix, i + 1, disks_info_count + 3, "="); +- ++ table_printf(matrix, i + 1, device_info_count + 3, "="); + + /* footer */ +- table_printf(matrix, 0, disks_info_count + 4, "total_spaces; i++) +- table_printf(matrix, 1 + i, disks_info_count + 4, +- ">%s", ++ table_printf(matrix, 1 + i, device_info_count + 4, ">%s", + df_pretty_sizes(sargs->spaces[i].total_bytes, mode)); + +- table_printf(matrix, sargs->total_spaces+1, disks_info_count+4, +- ">%s", df_pretty_sizes(total_unused, mode)); ++ table_printf(matrix, sargs->total_spaces + 1, device_info_count + 4, ++ ">%s", df_pretty_sizes(total_unused, mode)); + +- table_printf(matrix, 0, disks_info_count+5, "total_spaces; i++) +- table_printf(matrix, 1+i, disks_info_count+5, ">%s", ++ table_printf(matrix, 1 + i, device_info_count+5, ">%s", + df_pretty_sizes(sargs->spaces[i].used_bytes, mode)); + +- + table_dump(matrix); + table_free(matrix); +- + } + + /* +@@ -684,50 +644,46 @@ static void _cmd_filesystem_usage_tabular(int mode, + */ + static void print_unused(struct chunk_info *info_ptr, + int info_count, +- struct disk_info *disks_info_ptr, +- int disks_info_count, ++ struct device_info *device_info_ptr, ++ int device_info_count, + int mode) + { + int i; +- for (i = 0 ; i < disks_info_count ; i++) { +- ++ for (i = 0; i < device_info_count; i++) { + int j; + u64 total = 0; + +- for (j = 0 ; j < info_count ; j++) +- if (info_ptr[j].devid == disks_info_ptr[i].devid) ++ for (j = 0; j < info_count; j++) ++ if (info_ptr[j].devid == device_info_ptr[i].devid) + total += calc_chunk_size(info_ptr+j); + + printf(" %s\t%10s\n", +- disks_info_ptr[i].path, +- df_pretty_sizes(disks_info_ptr[i].size - total, mode)); +- ++ device_info_ptr[i].path, ++ df_pretty_sizes(device_info_ptr[i].size - total, mode)); + } +- + } + + /* + * This function prints the allocated chunk per every disk + */ +-static void print_chunk_disks(u64 chunk_type, ++static void print_chunk_device(u64 chunk_type, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, +- struct disk_info *disks_info_ptr, +- int disks_info_count, ++ struct device_info *device_info_ptr, ++ int device_info_count, + int mode) + { + int i; + +- for (i = 0 ; i < disks_info_count ; i++) { +- ++ for (i = 0; i < device_info_count; i++) { + int j; + u64 total = 0; + +- for (j = 0 ; j < chunks_info_count ; j++) { ++ for (j = 0; j < chunks_info_count; j++) { + + if (chunks_info_ptr[j].type != chunk_type) + continue; +- if (chunks_info_ptr[j].devid != disks_info_ptr[i].devid) ++ if (chunks_info_ptr[j].devid != device_info_ptr[i].devid) + continue; + + total += calc_chunk_size(&(chunks_info_ptr[j])); +@@ -736,7 +692,7 @@ static void print_chunk_disks(u64 chunk_type, + + if (total > 0) + printf(" %s\t%10s\n", +- disks_info_ptr[i].path, ++ device_info_ptr[i].path, + df_pretty_sizes(total, mode)); + } + } +@@ -749,8 +705,8 @@ static void _cmd_filesystem_usage_linear(int mode, + struct btrfs_ioctl_space_args *sargs, + struct chunk_info *info_ptr, + int info_count, +- struct disk_info *disks_info_ptr, +- int disks_info_count) ++ struct device_info *device_info_ptr, ++ int device_info_count) + { + int i; + +@@ -768,22 +724,15 @@ static void _cmd_filesystem_usage_linear(int mode, + df_pretty_sizes(sargs->spaces[i].total_bytes , + mode)); + printf("Used:%s\n", +- df_pretty_sizes(sargs->spaces[i].used_bytes, +- mode)); +- print_chunk_disks(flags, info_ptr, info_count, +- disks_info_ptr, disks_info_count, +- mode); ++ df_pretty_sizes(sargs->spaces[i].used_bytes, mode)); ++ print_chunk_device(flags, info_ptr, info_count, ++ device_info_ptr, device_info_count, mode); + printf("\n"); +- + } + + printf("Unallocated:\n"); +- print_unused(info_ptr, info_count, +- disks_info_ptr, disks_info_count, ++ print_unused(info_ptr, info_count, device_info_ptr, device_info_count, + mode); +- +- +- + } + + static int _cmd_filesystem_usage(int fd, char *path, int mode, int tabular) +@@ -791,12 +740,12 @@ static int _cmd_filesystem_usage(int fd, char *path, int mode, int tabular) + struct btrfs_ioctl_space_args *sargs = 0; + int info_count = 0; + struct chunk_info *info_ptr = 0; +- struct disk_info *disks_info_ptr = 0; +- int disks_info_count = 0; ++ struct device_info *device_info_ptr = 0; ++ int device_info_count = 0; + int ret = 0; + + if (load_chunk_info(fd, &info_ptr, &info_count) || +- load_disks_info(fd, &disks_info_ptr, &disks_info_count)) { ++ load_device_info(fd, &device_info_ptr, &device_info_count)) { + ret = -1; + goto exit; + } +@@ -809,18 +758,18 @@ static int _cmd_filesystem_usage(int fd, char *path, int mode, int tabular) + if (tabular) + _cmd_filesystem_usage_tabular(mode, sargs, + info_ptr, info_count, +- disks_info_ptr, disks_info_count); ++ device_info_ptr, device_info_count); + else + _cmd_filesystem_usage_linear(mode, sargs, + info_ptr, info_count, +- disks_info_ptr, disks_info_count); ++ device_info_ptr, device_info_count); + + exit: + + if (sargs) + free(sargs); +- if (disks_info_ptr) +- free(disks_info_ptr); ++ if (device_info_ptr) ++ free(device_info_ptr); + if (info_ptr) + free(info_ptr); + +@@ -887,12 +836,9 @@ int cmd_filesystem_usage(int argc, char **argv) + return 0; + } + +-static void print_disk_chunks(int fd, +- u64 devid, +- u64 total_size, +- struct chunk_info *chunks_info_ptr, +- int chunks_info_count, +- int mode) ++void print_device_chunks(int fd, u64 devid, u64 total_size, ++ struct chunk_info *chunks_info_ptr, ++ int chunks_info_count, int mode) + { + int i; + u64 allocated = 0; +@@ -925,98 +871,3 @@ static void print_disk_chunks(int fd, + df_pretty_sizes(total_size - allocated, mode)); + + } +- +-static int _cmd_device_disk_usage(int fd, char *path, int mode) +-{ +- int i; +- int ret = 0; +- int info_count = 0; +- struct chunk_info *info_ptr = 0; +- struct disk_info *disks_info_ptr = 0; +- int disks_info_count = 0; +- +- if (load_chunk_info(fd, &info_ptr, &info_count) || +- load_disks_info(fd, &disks_info_ptr, &disks_info_count)) { +- ret = -1; +- goto exit; +- } +- +- for (i = 0 ; i < disks_info_count ; i++) { +- printf("%s\t%10s\n", disks_info_ptr[i].path, +- df_pretty_sizes(disks_info_ptr[i].size, mode)); +- +- print_disk_chunks(fd, disks_info_ptr[i].devid, +- disks_info_ptr[i].size, +- info_ptr, info_count, +- mode); +- printf("\n"); +- +- } +- +- +-exit: +- +- if (disks_info_ptr) +- free(disks_info_ptr); +- if (info_ptr) +- free(info_ptr); +- +- return ret; +-} +- +-const char * const cmd_device_disk_usage_usage[] = { +- "btrfs device disk-usage [-b] [..]", +- "Show which chunks are in a device.", +- "", +- "-b\tSet byte as unit", +- NULL +-}; +- +-int cmd_device_disk_usage(int argc, char **argv) +-{ +- +- int flags = DF_HUMAN_UNIT; +- int i, more_than_one = 0; +- +- optind = 1; +- while (1) { +- char c = getopt(argc, argv, "b"); +- +- if (c < 0) +- break; +- +- switch (c) { +- case 'b': +- flags &= ~DF_HUMAN_UNIT; +- break; +- default: +- usage(cmd_device_disk_usage_usage); +- } +- } +- +- if (check_argc_min(argc - optind, 1)) +- usage(cmd_device_disk_usage_usage); +- +- for (i = optind; i < argc ; i++) { +- int r, fd; +- DIR *dirstream = NULL; +- if (more_than_one) +- printf("\n"); +- +- fd = open_file_or_dir(argv[i], &dirstream); +- if (fd < 0) { +- fprintf(stderr, "ERROR: can't access to '%s'\n", +- argv[1]); +- return 12; +- } +- r = _cmd_device_disk_usage(fd, argv[i], flags); +- close_file_or_dir(fd, dirstream); +- +- if (r) +- return r; +- more_than_one = 1; +- +- } +- +- return 0; +-} +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +index 95cf4aabefb4..787b4eb56acf 100644 +--- a/cmds-fi-disk_usage.h ++++ b/cmds-fi-disk_usage.h +@@ -19,10 +19,36 @@ + #ifndef __CMDS_FI_DISK_USAGE__ + #define __CMDS_FI_DISK_USAGE__ + ++#define DF_HUMAN_UNIT (1<<0) ++ + extern const char * const cmd_filesystem_usage_usage[]; + int cmd_filesystem_usage(int argc, char **argv); + +-extern const char * const cmd_device_disk_usage_usage[]; +-int cmd_device_disk_usage(int argc, char **argv); ++struct device_info { ++ u64 devid; ++ char path[BTRFS_DEVICE_PATH_NAME_MAX]; ++ u64 size; ++}; ++ ++/* ++ * To store the size information about the chunks: ++ * the chunks info are grouped by the tuple (type, devid, num_stripes), ++ * i.e. if two chunks are of the same type (RAID1, DUP...), are on the ++ * same disk, have the same stripes then their sizes are grouped ++ */ ++struct chunk_info { ++ u64 type; ++ u64 size; ++ u64 devid; ++ u64 num_stripes; ++}; ++ ++int load_device_info(int fd, struct device_info **device_info_ptr, ++ int *device_info_count); ++int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count); ++char *df_pretty_sizes(u64 size, int mode); ++void print_device_chunks(int fd, u64 devid, u64 total_size, ++ struct chunk_info *chunks_info_ptr, ++ int chunks_info_count, int mode); + + #endif +-- +1.9.0 + diff --git a/0021-btrfs-progs-check-if-we-can-t-get-info-from-ioctls-d.patch b/0021-btrfs-progs-check-if-we-can-t-get-info-from-ioctls-d.patch new file mode 100644 index 0000000..873b42c --- /dev/null +++ b/0021-btrfs-progs-check-if-we-can-t-get-info-from-ioctls-d.patch @@ -0,0 +1,45 @@ +From a6979c52fbff0e0961a0a0546c45bca11f6a0658 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Thu, 24 Apr 2014 15:21:16 +0200 +Subject: [PATCH 32/42] btrfs-progs: check if we can't get info from ioctls due + to permissions + +The TREE_SEARCH ioctl is root-only, FS_INFO will be available for +non-root users with an updated kernel, let the user know. + +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 023659daac0e..3fa2af004dc4 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -172,6 +172,12 @@ int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count) + while (1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); + e = errno; ++ if (ret == -EPERM) { ++ fprintf(stderr, ++ "ERROR: can't read detailed chunk info from ioctl(TREE_SEARCH), run as root\n"); ++ return 0; ++ } ++ + if (ret < 0) { + fprintf(stderr, + "ERROR: can't perform the search - %s\n", +@@ -461,6 +467,10 @@ int load_device_info(int fd, struct device_info **device_info_ptr, + *device_info_ptr = 0; + + ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); ++ if (ret == -EPERM) { ++ fprintf(stderr, "ERROR: can't get filesystem info from ioctl(FS_INFO), run as root\n"); ++ return -1; ++ } + if (ret < 0) { + fprintf(stderr, "ERROR: cannot get filesystem info\n"); + return -1; +-- +1.9.0 + diff --git a/0022-btrfs-progs-zero-out-structures-before-calling-ioctl.patch b/0022-btrfs-progs-zero-out-structures-before-calling-ioctl.patch new file mode 100644 index 0000000..b64fba3 --- /dev/null +++ b/0022-btrfs-progs-zero-out-structures-before-calling-ioctl.patch @@ -0,0 +1,44 @@ +From 70b51a393b7d9ee6d20b16be0c925c58ea88f3c5 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Thu, 24 Apr 2014 18:37:50 +0200 +Subject: [PATCH 33/42] btrfs-progs: zero out structures before calling ioctl + +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 3fa2af004dc4..8c0462230510 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -248,7 +248,7 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) + struct btrfs_ioctl_space_args *sargs = 0, *sargs_orig = 0; + int e, ret, count; + +- sargs_orig = sargs = malloc(sizeof(struct btrfs_ioctl_space_args)); ++ sargs_orig = sargs = calloc(1, sizeof(struct btrfs_ioctl_space_args)); + if (!sargs) { + fprintf(stderr, "ERROR: not enough memory\n"); + return NULL; +@@ -476,15 +476,15 @@ int load_device_info(int fd, struct device_info **device_info_ptr, + return -1; + } + +- info = malloc(sizeof(struct device_info) * fi_args.num_devices); ++ info = calloc(fi_args.num_devices, sizeof(struct device_info)); + if (!info) { + fprintf(stderr, "ERROR: not enough memory\n"); + return -1; + } + + for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) { +- + BUG_ON(ndevs >= fi_args.num_devices); ++ memset(&dev_info, 0, sizeof(dev_info)); + ret = get_device_info(fd, i, &dev_info); + + if (ret == -ENODEV) +-- +1.9.0 + diff --git a/0023-btrfs-progs-print-B-for-bytes.patch b/0023-btrfs-progs-print-B-for-bytes.patch new file mode 100644 index 0000000..ee495f1 --- /dev/null +++ b/0023-btrfs-progs-print-B-for-bytes.patch @@ -0,0 +1,28 @@ +From 86b1a432b74285db0096fdd4894626cb26773eeb Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Thu, 24 Apr 2014 18:31:28 +0200 +Subject: [PATCH 34/42] btrfs-progs: print B for bytes + +This arguably helps parsers. + +Signed-off-by: David Sterba +--- + utils.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/utils.c b/utils.c +index ca150404ea6f..159abf8bd0e4 100644 +--- a/utils.c ++++ b/utils.c +@@ -1252,7 +1252,7 @@ out: + return ret; + } + +-static char *size_strs[] = { "", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; ++static char *size_strs[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; + int pretty_size_snprintf(u64 size, char *str, size_t str_bytes) + { + int num_divs = 0; +-- +1.9.0 + diff --git a/0024-btrfs-progs-Print-more-info-about-device-sizes.patch b/0024-btrfs-progs-Print-more-info-about-device-sizes.patch new file mode 100644 index 0000000..a89176d --- /dev/null +++ b/0024-btrfs-progs-Print-more-info-about-device-sizes.patch @@ -0,0 +1,101 @@ +From c856f30b979c71ab5cda62753993e725dae922e6 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Thu, 24 Apr 2014 18:32:27 +0200 +Subject: [PATCH 35/42] btrfs-progs: Print more info about device sizes + +The entire device size may not be available to the filesystem, eg. if +it's modified via resize. Print this information if it can be obtained +from the DEV_INFO ioctl. + +Print the device ID on the same line as the device name and move size to +the next line. + +Sample: +/dev/sda7, ID: 3 + Device size: 10.00GiB + FS occuppied: 5.00GiB + Data,RAID10: 512.00MiB + Metadata,RAID10: 512.00MiB + System,RAID10: 4.00MiB + Unallocated: 9.00GiB + +Signed-off-by: David Sterba +--- + cmds-device.c | 6 +++--- + cmds-fi-disk_usage.c | 13 ++++++++++++- + cmds-fi-disk_usage.h | 6 +++++- + 3 files changed, 20 insertions(+), 5 deletions(-) + +diff --git a/cmds-device.c b/cmds-device.c +index c20b26e9be90..154188643c8f 100644 +--- a/cmds-device.c ++++ b/cmds-device.c +@@ -453,9 +453,9 @@ static int _cmd_device_usage(int fd, char *path, int mode) + } + + for (i = 0; i < device_info_count; i++) { +- printf("%s\t%10s\n", device_info_ptr[i].path, +- df_pretty_sizes(device_info_ptr[i].size, mode)); +- ++ printf("%s, ID: %llu\n", device_info_ptr[i].path, ++ device_info_ptr[i].devid); ++ print_device_sizes(fd, &device_info_ptr[i], mode); + print_device_chunks(fd, device_info_ptr[i].devid, + device_info_ptr[i].size, + info_ptr, info_count, +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 8c0462230510..63ed9ba089d5 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -499,7 +499,8 @@ int load_device_info(int fd, struct device_info **device_info_ptr, + + info[ndevs].devid = dev_info.devid; + strcpy(info[ndevs].path, (char *)dev_info.path); +- info[ndevs].size = get_partition_size((char *)dev_info.path); ++ info[ndevs].device_size = get_partition_size((char *)dev_info.path); ++ info[ndevs].size = dev_info.total_size; + ++ndevs; + } + +@@ -879,5 +880,15 @@ void print_device_chunks(int fd, u64 devid, u64 total_size, + printf(" Unallocated: %*s%10s\n", + (int)(20 - strlen("Unallocated")), "", + df_pretty_sizes(total_size - allocated, mode)); ++} + ++void print_device_sizes(int fd, struct device_info *devinfo, int mode) ++{ ++ printf(" Device size: %*s%10s\n", ++ (int)(20 - strlen("Device size")), "", ++ df_pretty_sizes(devinfo->device_size, mode)); ++ printf(" FS occuppied:%*s%10s\n", ++ (int)(20 - strlen("FS occupied")), "", ++ df_pretty_sizes(devinfo->size, mode)); ++ } + } +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +index 787b4eb56acf..79cc2a115bc5 100644 +--- a/cmds-fi-disk_usage.h ++++ b/cmds-fi-disk_usage.h +@@ -27,7 +27,10 @@ int cmd_filesystem_usage(int argc, char **argv); + struct device_info { + u64 devid; + char path[BTRFS_DEVICE_PATH_NAME_MAX]; +- u64 size; ++ /* Size of the block device */ ++ u64 device_size; ++ /* Size that's occupied by the filesystem, can be changed via resize */ ++ u64 size; + }; + + /* +@@ -50,5 +53,6 @@ char *df_pretty_sizes(u64 size, int mode); + void print_device_chunks(int fd, u64 devid, u64 total_size, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, int mode); ++void print_device_sizes(int fd, struct device_info *devinfo, int mode); + + #endif +-- +1.9.0 + diff --git a/0025-btrfs-progs-compare-unallocated-space-against-the-co.patch b/0025-btrfs-progs-compare-unallocated-space-against-the-co.patch new file mode 100644 index 0000000..1c00655 --- /dev/null +++ b/0025-btrfs-progs-compare-unallocated-space-against-the-co.patch @@ -0,0 +1,96 @@ +From a2b5656ac87bd741153b97ac1e7bcf40ecc4f16c Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Thu, 24 Apr 2014 18:57:12 +0200 +Subject: [PATCH 36/42] btrfs-progs: compare unallocated space against the + correct value + +The device may not be fully occupied by the filesystem, the value of +Unallocated should not be calculated against the device size but the +size provided by DEV_INFO. + +Signed-off-by: David Sterba +--- + cmds-device.c | 6 ++---- + cmds-fi-disk_usage.c | 9 ++++----- + cmds-fi-disk_usage.h | 2 +- + 3 files changed, 7 insertions(+), 10 deletions(-) + +diff --git a/cmds-device.c b/cmds-device.c +index 154188643c8f..3e851badc116 100644 +--- a/cmds-device.c ++++ b/cmds-device.c +@@ -456,10 +456,8 @@ static int _cmd_device_usage(int fd, char *path, int mode) + printf("%s, ID: %llu\n", device_info_ptr[i].path, + device_info_ptr[i].devid); + print_device_sizes(fd, &device_info_ptr[i], mode); +- print_device_chunks(fd, device_info_ptr[i].devid, +- device_info_ptr[i].size, +- info_ptr, info_count, +- mode); ++ print_device_chunks(fd, &device_info_ptr[i], ++ info_ptr, info_count, mode); + printf("\n"); + } + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 63ed9ba089d5..0e93dc836f16 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -500,7 +500,7 @@ int load_device_info(int fd, struct device_info **device_info_ptr, + info[ndevs].devid = dev_info.devid; + strcpy(info[ndevs].path, (char *)dev_info.path); + info[ndevs].device_size = get_partition_size((char *)dev_info.path); +- info[ndevs].size = dev_info.total_size; ++ info[ndevs].size = dev_info.total_bytes; + ++ndevs; + } + +@@ -847,7 +847,7 @@ int cmd_filesystem_usage(int argc, char **argv) + return 0; + } + +-void print_device_chunks(int fd, u64 devid, u64 total_size, ++void print_device_chunks(int fd, struct device_info *devinfo, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, int mode) + { +@@ -860,7 +860,7 @@ void print_device_chunks(int fd, u64 devid, u64 total_size, + u64 flags; + u64 size; + +- if (chunks_info_ptr[i].devid != devid) ++ if (chunks_info_ptr[i].devid != devinfo->devid) + continue; + + flags = chunks_info_ptr[i].type; +@@ -879,7 +879,7 @@ void print_device_chunks(int fd, u64 devid, u64 total_size, + } + printf(" Unallocated: %*s%10s\n", + (int)(20 - strlen("Unallocated")), "", +- df_pretty_sizes(total_size - allocated, mode)); ++ df_pretty_sizes(devinfo->size - allocated, mode)); + } + + void print_device_sizes(int fd, struct device_info *devinfo, int mode) +@@ -890,5 +890,4 @@ void print_device_sizes(int fd, struct device_info *devinfo, int mode) + printf(" FS occuppied:%*s%10s\n", + (int)(20 - strlen("FS occupied")), "", + df_pretty_sizes(devinfo->size, mode)); +- } + } +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +index 79cc2a115bc5..dbc2a10f31eb 100644 +--- a/cmds-fi-disk_usage.h ++++ b/cmds-fi-disk_usage.h +@@ -50,7 +50,7 @@ int load_device_info(int fd, struct device_info **device_info_ptr, + int *device_info_count); + int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count); + char *df_pretty_sizes(u64 size, int mode); +-void print_device_chunks(int fd, u64 devid, u64 total_size, ++void print_device_chunks(int fd, struct device_info *devinfo, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, int mode); + void print_device_sizes(int fd, struct device_info *devinfo, int mode); +-- +1.9.0 + diff --git a/0026-btrfs-progs-add-section-of-overall-filesystem-usage.patch b/0026-btrfs-progs-add-section-of-overall-filesystem-usage.patch new file mode 100644 index 0000000..64608d7 --- /dev/null +++ b/0026-btrfs-progs-add-section-of-overall-filesystem-usage.patch @@ -0,0 +1,107 @@ +From d8ca04ddc42461c462e3b52031e1134f01c71663 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Fri, 25 Apr 2014 17:24:40 +0200 +Subject: [PATCH 37/42] btrfs-progs: add section of overall filesystem usage + +The 'fi usage' lacks an overall report, this used to be in the enhanced +df command. Add it back. + +Sample: +Overall: + Device size: 35.00GiB + Device allocated: 8.07GiB + Device unallocated: 26.93GiB + Used: 1.12MiB + Free (Estimated): 17.57GiB (Max: 30.98GiB, min: 17.52GiB) + Data to device ratio: 50 % +... + +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 0e93dc836f16..e17f04e31d35 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -302,8 +302,6 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) + return sargs; + } + +-/* Not used, keep for later */ +-#if 0 + /* + * This function computes the space occuped by a *single* RAID5/RAID6 chunk. + * The computation is performed on the basis of the number of stripes +@@ -331,7 +329,6 @@ static int get_raid56_used(int fd, u64 *raid5_used, u64 *raid6_used) + free(info_ptr); + + return 0; +- + } + + static int _cmd_disk_free(int fd, char *path, int mode) +@@ -416,22 +413,24 @@ static int _cmd_disk_free(int fd, char *path, int mode) + else + width = 18; + +- printf("Disk size:\t\t%*s\n", width, ++ printf("Overall:\n"); ++ ++ printf(" Device size:\t\t%*s\n", width, + df_pretty_sizes(total_disk, mode)); +- printf("Disk allocated:\t\t%*s\n", width, ++ printf(" Device allocated:\t\t%*s\n", width, + df_pretty_sizes(total_chunks, mode)); +- printf("Disk unallocated:\t%*s\n", width, ++ printf(" Device unallocated:\t\t%*s\n", width, + df_pretty_sizes(total_disk-total_chunks, mode)); +- printf("Used:\t\t\t%*s\n", width, ++ printf(" Used:\t\t\t%*s\n", width, + df_pretty_sizes(total_used, mode)); +- printf("Free (Estimated):\t%*s\t(", ++ printf(" Free (Estimated):\t\t%*s\t(", + width, + df_pretty_sizes((u64)(K*total_disk-total_used), mode)); + printf("Max: %s, ", + df_pretty_sizes(total_disk-total_chunks+total_free, mode)); + printf("min: %s)\n", + df_pretty_sizes((total_disk-total_chunks)/2+total_free, mode)); +- printf("Data to disk ratio:\t%*.0f %%\n", ++ printf(" Data to device ratio:\t%*.0f %%\n", + width-2, K*100); + + exit: +@@ -441,7 +440,6 @@ exit: + + return ret; + } +-#endif + + /* + * Helper to sort the device_info structure +@@ -826,8 +824,6 @@ int cmd_filesystem_usage(int argc, char **argv) + for (i = optind; i < argc ; i++) { + int r, fd; + DIR *dirstream = NULL; +- if (more_than_one) +- printf("\n"); + + fd = open_file_or_dir(argv[i], &dirstream); + if (fd < 0) { +@@ -835,6 +831,11 @@ int cmd_filesystem_usage(int argc, char **argv) + argv[1]); + return 12; + } ++ if (more_than_one) ++ printf("\n"); ++ ++ r = _cmd_disk_free(fd, argv[i], flags); ++ printf("\n"); + r = _cmd_filesystem_usage(fd, argv[i], flags, tabular); + close_file_or_dir(fd, dirstream); + +-- +1.9.0 + diff --git a/0027-btrfs-progs-cleanup-filesystem-device-usage-code.patch b/0027-btrfs-progs-cleanup-filesystem-device-usage-code.patch new file mode 100644 index 0000000..f040682 --- /dev/null +++ b/0027-btrfs-progs-cleanup-filesystem-device-usage-code.patch @@ -0,0 +1,372 @@ +From e81d2614ff21e3e9e723cc645cc73646a42d06e8 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Fri, 25 Apr 2014 19:39:11 +0200 +Subject: [PATCH 38/42] btrfs-progs: cleanup filesystem/device usage code + +The main point of this is to load the device and chunk infos at one +place and pass down to the printers. The EPERM is handled separately, in +case kernel does not give us all the information about chunks or +devices, but we want to warn and print at least something. + +For non-root users, 'filesystem usage' prints only the overall stats and +warns about RAID5/6. + +The sole cleanup changes affect mostly the modified code and the related +functions, should be reasonably small. + +Signed-off-by: David Sterba +--- + cmds-device.c | 31 +++++----- + cmds-fi-disk_usage.c | 163 +++++++++++++++++++++++++++------------------------ + cmds-fi-disk_usage.h | 5 +- + 3 files changed, 105 insertions(+), 94 deletions(-) + +diff --git a/cmds-device.c b/cmds-device.c +index 3e851badc116..bf5898f6da68 100644 +--- a/cmds-device.c ++++ b/cmds-device.c +@@ -441,31 +441,29 @@ static int _cmd_device_usage(int fd, char *path, int mode) + { + int i; + int ret = 0; +- int info_count = 0; +- struct chunk_info *info_ptr = 0; +- struct device_info *device_info_ptr = 0; +- int device_info_count = 0; ++ struct chunk_info *chunkinfo = NULL; ++ struct device_info *devinfo = NULL; ++ int chunkcount = 0; ++ int devcount = 0; + +- if (load_chunk_info(fd, &info_ptr, &info_count) || +- load_device_info(fd, &device_info_ptr, &device_info_count)) { ++ ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo, ++ &devcount); ++ if (ret) { + ret = -1; + goto exit; + } + +- for (i = 0; i < device_info_count; i++) { +- printf("%s, ID: %llu\n", device_info_ptr[i].path, +- device_info_ptr[i].devid); +- print_device_sizes(fd, &device_info_ptr[i], mode); +- print_device_chunks(fd, &device_info_ptr[i], +- info_ptr, info_count, mode); ++ for (i = 0; i < devcount; i++) { ++ printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid); ++ print_device_sizes(fd, &devinfo[i], mode); ++ print_device_chunks(fd, &devinfo[i], chunkinfo, chunkcount, ++ mode); + printf("\n"); + } + + exit: +- if (device_info_ptr) +- free(device_info_ptr); +- if (info_ptr) +- free(info_ptr); ++ free(devinfo); ++ free(chunkinfo); + + return ret; + } +@@ -507,6 +505,7 @@ int cmd_device_usage(int argc, char **argv) + argv[1]); + return 12; + } ++ + r = _cmd_device_usage(fd, argv[i], flags); + close_file_or_dir(fd, dirstream); + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index e17f04e31d35..9d1c4085b4ea 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -141,7 +141,7 @@ static int cmp_chunk_info(const void *a, const void *b) + ((struct chunk_info *)b)->type); + } + +-int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count) ++static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count) + { + int ret; + struct btrfs_ioctl_search_args args; +@@ -172,11 +172,8 @@ int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count) + while (1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); + e = errno; +- if (ret == -EPERM) { +- fprintf(stderr, +- "ERROR: can't read detailed chunk info from ioctl(TREE_SEARCH), run as root\n"); +- return 0; +- } ++ if (ret == -EPERM) ++ return ret; + + if (ret < 0) { + fprintf(stderr, +@@ -308,30 +305,23 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) + * which compose the chunk, which could be different from the number of devices + * if a disk is added later. + */ +-static int get_raid56_used(int fd, u64 *raid5_used, u64 *raid6_used) ++static void get_raid56_used(int fd, struct chunk_info *chunks, int chunkcount, ++ u64 *raid5_used, u64 *raid6_used) + { +- struct chunk_info *info_ptr=0, *p; +- int info_count=0; +- int ret; +- +- *raid5_used = *raid6_used =0; +- +- ret = load_chunk_info(fd, &info_ptr, &info_count); +- if( ret < 0) +- return ret; +- +- for ( p = info_ptr; info_count ; info_count--, p++ ) { +- if (p->type & BTRFS_BLOCK_GROUP_RAID5) +- (*raid5_used) += p->size / (p->num_stripes -1); +- if (p->type & BTRFS_BLOCK_GROUP_RAID6) +- (*raid6_used) += p->size / (p->num_stripes -2); ++ *raid5_used = 0; ++ *raid6_used = 0; ++ ++ while (chunkcount-- > 0) { ++ if (chunks->type & BTRFS_BLOCK_GROUP_RAID5) ++ (*raid5_used) += chunks->size / (chunks->num_stripes - 1); ++ if (chunks->type & BTRFS_BLOCK_GROUP_RAID6) ++ (*raid6_used) += chunks->size / (chunks->num_stripes - 2); + } +- free(info_ptr); +- +- return 0; + } + +-static int _cmd_disk_free(int fd, char *path, int mode) ++static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, ++ int chunkcount, struct device_info *devinfo, int devcount, ++ char *path, int mode) + { + struct btrfs_ioctl_space_args *sargs = 0; + int i; +@@ -360,15 +350,11 @@ static int _cmd_disk_free(int fd, char *path, int mode) + ret = 19; + goto exit; + } +- if (get_raid56_used(fd, &raid5_used, &raid6_used) < 0) { +- fprintf(stderr, +- "ERROR: couldn't get space info on '%s'\n", +- path ); +- ret = 20; +- goto exit; +- } ++ get_raid56_used(fd, chunkinfo, chunkcount, &raid5_used, &raid6_used); + +- total_chunks = total_used = total_free = 0; ++ total_chunks = 0; ++ total_used = 0; ++ total_free = 0; + + for (i = 0; i < sargs->total_spaces; i++) { + float ratio = 1; +@@ -453,7 +439,7 @@ static int cmp_device_info(const void *a, const void *b) + /* + * This function loads the device_info structure and put them in an array + */ +-int load_device_info(int fd, struct device_info **device_info_ptr, ++static int load_device_info(int fd, struct device_info **device_info_ptr, + int *device_info_count) + { + int ret, i, ndevs; +@@ -465,10 +451,8 @@ int load_device_info(int fd, struct device_info **device_info_ptr, + *device_info_ptr = 0; + + ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); +- if (ret == -EPERM) { +- fprintf(stderr, "ERROR: can't get filesystem info from ioctl(FS_INFO), run as root\n"); +- return -1; +- } ++ if (ret == -EPERM) ++ return ret; + if (ret < 0) { + fprintf(stderr, "ERROR: cannot get filesystem info\n"); + return -1; +@@ -512,6 +496,29 @@ int load_device_info(int fd, struct device_info **device_info_ptr, + return 0; + } + ++int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo, ++ int *chunkcount, struct device_info **devinfo, int *devcount) ++{ ++ int ret; ++ ++ ret = load_chunk_info(fd, chunkinfo, chunkcount); ++ if (ret == -EPERM) { ++ fprintf(stderr, ++ "WARNING: can't read detailed chunk info, RAID5/6 numbers will be incorrect, run as root\n"); ++ } else if (ret) { ++ return ret; ++ } ++ ++ ret = load_device_info(fd, devinfo, devcount); ++ if (ret == -EPERM) { ++ fprintf(stderr, ++ "WARNING: can't get filesystem info from ioctl(FS_INFO), run as root\n"); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ + /* + * This function computes the size of a chunk in a disk + */ +@@ -744,43 +751,32 @@ static void _cmd_filesystem_usage_linear(int mode, + mode); + } + +-static int _cmd_filesystem_usage(int fd, char *path, int mode, int tabular) ++static int print_filesystem_usage_by_chunk(int fd, ++ struct chunk_info *chunkinfo, int chunkcount, ++ struct device_info *devinfo, int devcount, ++ char *path, int mode, int tabular) + { +- struct btrfs_ioctl_space_args *sargs = 0; +- int info_count = 0; +- struct chunk_info *info_ptr = 0; +- struct device_info *device_info_ptr = 0; +- int device_info_count = 0; ++ struct btrfs_ioctl_space_args *sargs; + int ret = 0; + +- if (load_chunk_info(fd, &info_ptr, &info_count) || +- load_device_info(fd, &device_info_ptr, &device_info_count)) { +- ret = -1; +- goto exit; +- } ++ if (!chunkinfo) ++ return 0; + +- if ((sargs = load_space_info(fd, path)) == NULL) { +- ret = -1; ++ sargs = load_space_info(fd, path); ++ if (!sargs) { ++ ret = 1; + goto exit; + } + + if (tabular) +- _cmd_filesystem_usage_tabular(mode, sargs, +- info_ptr, info_count, +- device_info_ptr, device_info_count); ++ _cmd_filesystem_usage_tabular(mode, sargs, chunkinfo, ++ chunkcount, devinfo, devcount); + else +- _cmd_filesystem_usage_linear(mode, sargs, +- info_ptr, info_count, +- device_info_ptr, device_info_count); ++ _cmd_filesystem_usage_linear(mode, sargs, chunkinfo, ++ chunkcount, devinfo, devcount); + + exit: +- +- if (sargs) +- free(sargs); +- if (device_info_ptr) +- free(device_info_ptr); +- if (info_ptr) +- free(info_ptr); ++ free(sargs); + + return ret; + } +@@ -796,16 +792,17 @@ const char * const cmd_filesystem_usage_usage[] = { + + int cmd_filesystem_usage(int argc, char **argv) + { +- + int flags = DF_HUMAN_UNIT; + int i, more_than_one = 0; + int tabular = 0; + + optind = 1; + while (1) { +- char c = getopt(argc, argv, "bt"); ++ int c = getopt(argc, argv, "bt"); ++ + if (c < 0) + break; ++ + switch (c) { + case 'b': + flags &= ~DF_HUMAN_UNIT; +@@ -821,9 +818,14 @@ int cmd_filesystem_usage(int argc, char **argv) + if (check_argc_min(argc - optind, 1)) + usage(cmd_filesystem_usage_usage); + +- for (i = optind; i < argc ; i++) { +- int r, fd; +- DIR *dirstream = NULL; ++ for (i = optind; i < argc; i++) { ++ int ret; ++ int fd; ++ DIR *dirstream = NULL; ++ struct chunk_info *chunkinfo = NULL; ++ struct device_info *devinfo = NULL; ++ int chunkcount = 0; ++ int devcount = 0; + + fd = open_file_or_dir(argv[i], &dirstream); + if (fd < 0) { +@@ -834,15 +836,26 @@ int cmd_filesystem_usage(int argc, char **argv) + if (more_than_one) + printf("\n"); + +- r = _cmd_disk_free(fd, argv[i], flags); ++ ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, ++ &devinfo, &devcount); ++ if (ret) ++ goto cleanup; ++ ++ ret = print_filesystem_usage_overall(fd, chunkinfo, chunkcount, ++ devinfo, devcount, argv[i], flags); ++ if (ret) ++ goto cleanup; + printf("\n"); +- r = _cmd_filesystem_usage(fd, argv[i], flags, tabular); ++ ret = print_filesystem_usage_by_chunk(fd, chunkinfo, chunkcount, ++ devinfo, devcount, argv[i], flags, tabular); ++cleanup: + close_file_or_dir(fd, dirstream); ++ free(chunkinfo); ++ free(devinfo); + +- if (r) +- return r; ++ if (ret) ++ return ret; + more_than_one = 1; +- + } + + return 0; +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +index dbc2a10f31eb..0779defc71db 100644 +--- a/cmds-fi-disk_usage.h ++++ b/cmds-fi-disk_usage.h +@@ -46,9 +46,8 @@ struct chunk_info { + u64 num_stripes; + }; + +-int load_device_info(int fd, struct device_info **device_info_ptr, +- int *device_info_count); +-int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count); ++int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo, ++ int *chunkcount, struct device_info **devinfo, int *devcount); + char *df_pretty_sizes(u64 size, int mode); + void print_device_chunks(int fd, struct device_info *devinfo, + struct chunk_info *chunks_info_ptr, +-- +1.9.0 + diff --git a/0028-btrfs-progs-extend-pretty-printers-with-unit-mode.patch b/0028-btrfs-progs-extend-pretty-printers-with-unit-mode.patch new file mode 100644 index 0000000..dd1bf53 --- /dev/null +++ b/0028-btrfs-progs-extend-pretty-printers-with-unit-mode.patch @@ -0,0 +1,172 @@ +From f54a92b54b57ea8be8d55ea012c9b69c9f0db5ff Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Mon, 28 Apr 2014 18:04:48 +0200 +Subject: [PATCH 39/42] btrfs-progs: extend pretty printers with unit mode + +The functionality of pretty unit printing was duplicated by +df_pretty_sizes, merge it with pretty_size and enhance the interface +with more suffix mode. Raw, binary or decimal. + +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 9 ++----- + utils.c | 71 ++++++++++++++++++++++++++++++++++++---------------- + utils.h | 21 +++++++++++----- + 3 files changed, 66 insertions(+), 35 deletions(-) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 9d1c4085b4ea..1e412c0b0e69 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -33,18 +33,13 @@ + + /* + * Pretty print the size +- * PAY ATTENTION: it return a statically buffer + */ + char *df_pretty_sizes(u64 size, int mode) + { +- static char buf[30]; +- + if (mode & DF_HUMAN_UNIT) +- (void)pretty_size_snprintf(size, buf, sizeof(buf)); ++ return pretty_size_mode(size, UNITS_HUMAN); + else +- sprintf(buf, "%llu", size); +- +- return buf; ++ return pretty_size_mode(size, UNITS_RAW); + } + + /* +diff --git a/utils.c b/utils.c +index 159abf8bd0e4..69112be51cb2 100644 +--- a/utils.c ++++ b/utils.c +@@ -1252,35 +1252,62 @@ out: + return ret; + } + +-static char *size_strs[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; +-int pretty_size_snprintf(u64 size, char *str, size_t str_bytes) ++static const char const *unit_suffix_binary[] = ++ { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; ++static const char const *unit_suffix_decimal[] = ++ { "B", "KB", "MB", "GB", "TB", "PB", "EB"}; ++ ++int pretty_size_snprintf(u64 size, char *str, size_t str_size, int unit_mode) + { +- int num_divs = 0; ++ int num_divs; + float fraction; ++ int base = 0; ++ const char const **suffix = NULL; ++ u64 last_size; + +- if (str_bytes == 0) ++ if (str_size == 0) + return 0; + +- if( size < 1024 ){ +- fraction = size; +- num_divs = 0; +- } else { +- u64 last_size = size; +- num_divs = 0; +- while(size >= 1024){ +- last_size = size; +- size /= 1024; +- num_divs ++; +- } ++ if (unit_mode == UNITS_RAW) { ++ snprintf(str, str_size, "%llu", size); ++ return 0; ++ } + +- if (num_divs >= ARRAY_SIZE(size_strs)) { +- str[0] = '\0'; +- return -1; +- } +- fraction = (float)last_size / 1024; ++ if (unit_mode == UNITS_BINARY) { ++ base = 1024; ++ suffix = unit_suffix_binary; ++ } else if (unit_mode == UNITS_DECIMAL) { ++ base = 1000; ++ suffix = unit_suffix_decimal; + } +- return snprintf(str, str_bytes, "%.2f%s", fraction, +- size_strs[num_divs]); ++ ++ /* Unknown mode */ ++ if (!base) { ++ fprintf(stderr, "INTERNAL ERROR: unknown unit base, mode %d", ++ unit_mode); ++ assert(0); ++ return -1; ++ } ++ ++ num_divs = 0; ++ last_size = size; ++ ++ while (size >= base) { ++ last_size = size; ++ size /= base; ++ num_divs++; ++ } ++ ++ if (num_divs >= ARRAY_SIZE(unit_suffix_binary)) { ++ str[0] = '\0'; ++ printf("INTERNAL ERROR: unsupported unit suffix, index %d\n", ++ num_divs); ++ assert(0); ++ return -1; ++ } ++ fraction = (float)last_size / base; ++ ++ return snprintf(str, str_size, "%.2f%s", fraction, suffix[num_divs]); + } + + /* +diff --git a/utils.h b/utils.h +index 2d08e0b2a3a4..3aea8b47d9e7 100644 +--- a/utils.h ++++ b/utils.h +@@ -39,6 +39,14 @@ + + #define BTRFS_UUID_UNPARSED_SIZE 37 + ++/* ++ * Output mode of byte units ++ */ ++#define UNITS_RAW (1) ++#define UNITS_BINARY (2) ++#define UNITS_DECIMAL (3) ++#define UNITS_HUMAN UNITS_BINARY ++ + int make_btrfs(int fd, const char *device, const char *label, + u64 blocks[6], u64 num_bytes, u32 nodesize, + u32 leafsize, u32 sectorsize, u32 stripesize, u64 features); +@@ -59,12 +67,13 @@ int check_mounted_where(int fd, const char *file, char *where, int size, + int btrfs_device_already_in_root(struct btrfs_root *root, int fd, + int super_offset); + +-int pretty_size_snprintf(u64 size, char *str, size_t str_bytes); +-#define pretty_size(size) \ +- ({ \ +- static __thread char _str[24]; \ +- (void)pretty_size_snprintf((size), _str, sizeof(_str)); \ +- _str; \ ++int pretty_size_snprintf(u64 size, char *str, size_t str_bytes, int unit_mode); ++#define pretty_size(size) pretty_size_mode(size, UNITS_BINARY) ++#define pretty_size_mode(size, mode) \ ++ ({ \ ++ static __thread char _str[32]; \ ++ (void)pretty_size_snprintf((size), _str, sizeof(_str), mode); \ ++ _str; \ + }) + + int get_mountpt(char *dev, char *mntpt, size_t size); +-- +1.9.0 + diff --git a/0029-btrfs-progs-replace-df_pretty_sizes-with-pretty_size.patch b/0029-btrfs-progs-replace-df_pretty_sizes-with-pretty_size.patch new file mode 100644 index 0000000..3524fcb --- /dev/null +++ b/0029-btrfs-progs-replace-df_pretty_sizes-with-pretty_size.patch @@ -0,0 +1,263 @@ +From a1764abe279f04a664d2745d6d2ce49db722bce3 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Mon, 28 Apr 2014 18:13:16 +0200 +Subject: [PATCH 40/42] btrfs-progs: replace df_pretty_sizes with + pretty_size_mode + +Signed-off-by: David Sterba +--- + cmds-device.c | 8 +++---- + cmds-fi-disk_usage.c | 63 ++++++++++++++++++++++------------------------------ + cmds-fi-disk_usage.h | 3 --- + 3 files changed, 30 insertions(+), 44 deletions(-) + +diff --git a/cmds-device.c b/cmds-device.c +index bf5898f6da68..eb6b79ca5127 100644 +--- a/cmds-device.c ++++ b/cmds-device.c +@@ -471,19 +471,19 @@ exit: + int cmd_device_usage(int argc, char **argv) + { + +- int flags = DF_HUMAN_UNIT; ++ int mode = UNITS_HUMAN; + int i, more_than_one = 0; + + optind = 1; + while (1) { +- char c = getopt(argc, argv, "b"); ++ int c = getopt(argc, argv, "b"); + + if (c < 0) + break; + + switch (c) { + case 'b': +- flags &= ~DF_HUMAN_UNIT; ++ mode = UNITS_RAW; + break; + default: + usage(cmd_device_usage_usage); +@@ -506,7 +506,7 @@ int cmd_device_usage(int argc, char **argv) + return 12; + } + +- r = _cmd_device_usage(fd, argv[i], flags); ++ r = _cmd_device_usage(fd, argv[i], mode); + close_file_or_dir(fd, dirstream); + + if (r) +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 1e412c0b0e69..d1b8bbddc4d5 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -32,17 +32,6 @@ + #include "version.h" + + /* +- * Pretty print the size +- */ +-char *df_pretty_sizes(u64 size, int mode) +-{ +- if (mode & DF_HUMAN_UNIT) +- return pretty_size_mode(size, UNITS_HUMAN); +- else +- return pretty_size_mode(size, UNITS_RAW); +-} +- +-/* + * Add the chunk info to the chunk_info list + */ + static int add_info_to_list(struct chunk_info **info_ptr, +@@ -389,7 +378,7 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + + K = ((double)total_used + (double)total_free) / (double)total_chunks; + +- if (mode & DF_HUMAN_UNIT) ++ if (mode == UNITS_HUMAN) + width = 10; + else + width = 18; +@@ -397,22 +386,22 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + printf("Overall:\n"); + + printf(" Device size:\t\t%*s\n", width, +- df_pretty_sizes(total_disk, mode)); ++ pretty_size_mode(total_disk, mode)); + printf(" Device allocated:\t\t%*s\n", width, +- df_pretty_sizes(total_chunks, mode)); ++ pretty_size_mode(total_chunks, mode)); + printf(" Device unallocated:\t\t%*s\n", width, +- df_pretty_sizes(total_disk-total_chunks, mode)); ++ pretty_size_mode(total_disk - total_chunks, mode)); + printf(" Used:\t\t\t%*s\n", width, +- df_pretty_sizes(total_used, mode)); ++ pretty_size_mode(total_used, mode)); + printf(" Free (Estimated):\t\t%*s\t(", + width, +- df_pretty_sizes((u64)(K*total_disk-total_used), mode)); ++ pretty_size_mode((u64)(K * total_disk - total_used), mode)); + printf("Max: %s, ", +- df_pretty_sizes(total_disk-total_chunks+total_free, mode)); ++ pretty_size_mode(total_disk - total_chunks + total_free, mode)); + printf("min: %s)\n", +- df_pretty_sizes((total_disk-total_chunks)/2+total_free, mode)); ++ pretty_size_mode((total_disk-total_chunks) / 2 + total_free, mode)); + printf(" Data to device ratio:\t%*.0f %%\n", +- width-2, K*100); ++ width - 2, K * 100); + + exit: + +@@ -612,7 +601,7 @@ static void _cmd_filesystem_usage_tabular(int mode, + + if (size) + table_printf(matrix, col, i+3, +- ">%s", df_pretty_sizes(size, mode)); ++ ">%s", pretty_size_mode(size, mode)); + else + table_printf(matrix, col, i+3, ">-"); + +@@ -624,7 +613,7 @@ static void _cmd_filesystem_usage_tabular(int mode, + - total_allocated; + + table_printf(matrix, sargs->total_spaces + 1, i + 3, +- ">%s", df_pretty_sizes(unused, mode)); ++ ">%s", pretty_size_mode(unused, mode)); + total_unused += unused; + + } +@@ -636,15 +625,15 @@ static void _cmd_filesystem_usage_tabular(int mode, + table_printf(matrix, 0, device_info_count + 4, "total_spaces; i++) + table_printf(matrix, 1 + i, device_info_count + 4, ">%s", +- df_pretty_sizes(sargs->spaces[i].total_bytes, mode)); ++ pretty_size_mode(sargs->spaces[i].total_bytes, mode)); + + table_printf(matrix, sargs->total_spaces + 1, device_info_count + 4, +- ">%s", df_pretty_sizes(total_unused, mode)); ++ ">%s", pretty_size_mode(total_unused, mode)); + + table_printf(matrix, 0, device_info_count + 5, "total_spaces; i++) + table_printf(matrix, 1 + i, device_info_count+5, ">%s", +- df_pretty_sizes(sargs->spaces[i].used_bytes, mode)); ++ pretty_size_mode(sargs->spaces[i].used_bytes, mode)); + + table_dump(matrix); + table_free(matrix); +@@ -670,7 +659,7 @@ static void print_unused(struct chunk_info *info_ptr, + + printf(" %s\t%10s\n", + device_info_ptr[i].path, +- df_pretty_sizes(device_info_ptr[i].size - total, mode)); ++ pretty_size_mode(device_info_ptr[i].size - total, mode)); + } + } + +@@ -704,7 +693,7 @@ static void print_chunk_device(u64 chunk_type, + if (total > 0) + printf(" %s\t%10s\n", + device_info_ptr[i].path, +- df_pretty_sizes(total, mode)); ++ pretty_size_mode(total, mode)); + } + } + +@@ -732,10 +721,10 @@ static void _cmd_filesystem_usage_linear(int mode, + printf("%s,%s: Size:%s, ", + description, + r_mode, +- df_pretty_sizes(sargs->spaces[i].total_bytes , ++ pretty_size_mode(sargs->spaces[i].total_bytes, + mode)); + printf("Used:%s\n", +- df_pretty_sizes(sargs->spaces[i].used_bytes, mode)); ++ pretty_size_mode(sargs->spaces[i].used_bytes, mode)); + print_chunk_device(flags, info_ptr, info_count, + device_info_ptr, device_info_count, mode); + printf("\n"); +@@ -787,7 +776,7 @@ const char * const cmd_filesystem_usage_usage[] = { + + int cmd_filesystem_usage(int argc, char **argv) + { +- int flags = DF_HUMAN_UNIT; ++ int mode = UNITS_HUMAN; + int i, more_than_one = 0; + int tabular = 0; + +@@ -800,7 +789,7 @@ int cmd_filesystem_usage(int argc, char **argv) + + switch (c) { + case 'b': +- flags &= ~DF_HUMAN_UNIT; ++ mode = UNITS_RAW; + break; + case 't': + tabular = 1; +@@ -837,12 +826,12 @@ int cmd_filesystem_usage(int argc, char **argv) + goto cleanup; + + ret = print_filesystem_usage_overall(fd, chunkinfo, chunkcount, +- devinfo, devcount, argv[i], flags); ++ devinfo, devcount, argv[i], mode); + if (ret) + goto cleanup; + printf("\n"); + ret = print_filesystem_usage_by_chunk(fd, chunkinfo, chunkcount, +- devinfo, devcount, argv[i], flags, tabular); ++ devinfo, devcount, argv[i], mode, tabular); + cleanup: + close_file_or_dir(fd, dirstream); + free(chunkinfo); +@@ -881,22 +870,22 @@ void print_device_chunks(int fd, struct device_info *devinfo, + description, + r_mode, + (int)(20 - strlen(description) - strlen(r_mode)), "", +- df_pretty_sizes(size, mode)); ++ pretty_size_mode(size, mode)); + + allocated += size; + + } + printf(" Unallocated: %*s%10s\n", + (int)(20 - strlen("Unallocated")), "", +- df_pretty_sizes(devinfo->size - allocated, mode)); ++ pretty_size_mode(devinfo->size - allocated, mode)); + } + + void print_device_sizes(int fd, struct device_info *devinfo, int mode) + { + printf(" Device size: %*s%10s\n", + (int)(20 - strlen("Device size")), "", +- df_pretty_sizes(devinfo->device_size, mode)); ++ pretty_size_mode(devinfo->device_size, mode)); + printf(" FS occuppied:%*s%10s\n", + (int)(20 - strlen("FS occupied")), "", +- df_pretty_sizes(devinfo->size, mode)); ++ pretty_size_mode(devinfo->size, mode)); + } +diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h +index 0779defc71db..8a0c60f011e4 100644 +--- a/cmds-fi-disk_usage.h ++++ b/cmds-fi-disk_usage.h +@@ -19,8 +19,6 @@ + #ifndef __CMDS_FI_DISK_USAGE__ + #define __CMDS_FI_DISK_USAGE__ + +-#define DF_HUMAN_UNIT (1<<0) +- + extern const char * const cmd_filesystem_usage_usage[]; + int cmd_filesystem_usage(int argc, char **argv); + +@@ -48,7 +46,6 @@ struct chunk_info { + + int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo, + int *chunkcount, struct device_info **devinfo, int *devcount); +-char *df_pretty_sizes(u64 size, int mode); + void print_device_chunks(int fd, struct device_info *devinfo, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, int mode); +-- +1.9.0 + diff --git a/0030-btrfs-progs-clean-up-return-codes-and-paths.patch b/0030-btrfs-progs-clean-up-return-codes-and-paths.patch new file mode 100644 index 0000000..f62ea24 --- /dev/null +++ b/0030-btrfs-progs-clean-up-return-codes-and-paths.patch @@ -0,0 +1,233 @@ +From 2c574dd5564fbe11a9e6e9c707fa907a7418c687 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Mon, 28 Apr 2014 18:55:05 +0200 +Subject: [PATCH 41/42] btrfs-progs: clean up return codes and paths + +Use the common patterns with one return statement at the end, pass down error + +Signed-off-by: David Sterba +--- + cmds-device.c | 27 +++++++++++++-------------- + cmds-fi-disk_usage.c | 39 +++++++++++++++++++++------------------ + 2 files changed, 34 insertions(+), 32 deletions(-) + +diff --git a/cmds-device.c b/cmds-device.c +index eb6b79ca5127..6dd5b05c7651 100644 +--- a/cmds-device.c ++++ b/cmds-device.c +@@ -448,10 +448,8 @@ static int _cmd_device_usage(int fd, char *path, int mode) + + ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo, + &devcount); +- if (ret) { +- ret = -1; +- goto exit; +- } ++ if (ret) ++ goto out; + + for (i = 0; i < devcount; i++) { + printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid); +@@ -461,7 +459,7 @@ static int _cmd_device_usage(int fd, char *path, int mode) + printf("\n"); + } + +-exit: ++out: + free(devinfo); + free(chunkinfo); + +@@ -472,6 +470,7 @@ int cmd_device_usage(int argc, char **argv) + { + + int mode = UNITS_HUMAN; ++ int ret = 0; + int i, more_than_one = 0; + + optind = 1; +@@ -494,28 +493,28 @@ int cmd_device_usage(int argc, char **argv) + usage(cmd_device_usage_usage); + + for (i = optind; i < argc ; i++) { +- int r, fd; ++ int fd; + DIR *dirstream = NULL; + if (more_than_one) + printf("\n"); + + fd = open_file_or_dir(argv[i], &dirstream); + if (fd < 0) { +- fprintf(stderr, "ERROR: can't access to '%s'\n", ++ fprintf(stderr, "ERROR: can't access '%s'\n", + argv[1]); +- return 12; ++ ret = 1; ++ goto out; + } + +- r = _cmd_device_usage(fd, argv[i], mode); ++ ret = _cmd_device_usage(fd, argv[i], mode); + close_file_or_dir(fd, dirstream); + +- if (r) +- return r; ++ if (ret) ++ goto out; + more_than_one = 1; +- + } +- +- return 0; ++out: ++ return !!ret; + } + + const struct cmd_group device_cmd_group = { +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index d1b8bbddc4d5..7c93247e4f54 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -68,7 +68,7 @@ static int add_info_to_list(struct chunk_info **info_ptr, + if (!res) { + free(*info_ptr); + fprintf(stderr, "ERROR: not enough memory\n"); +- return -1; ++ return -ENOMEM; + } + + *info_ptr = res; +@@ -163,7 +163,7 @@ static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count + fprintf(stderr, + "ERROR: can't perform the search - %s\n", + strerror(e)); +- return -99; ++ return ret; + } + /* the ioctl returns the number of item it found in nr_items */ + +@@ -179,9 +179,10 @@ static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count + off += sizeof(*sh); + item = (struct btrfs_chunk *)(args.buf + off); + +- if (add_info_to_list(info_ptr, info_count, item)) { ++ ret = add_info_to_list(info_ptr, info_count, item); ++ if (ret) { + *info_ptr = 0; +- return -100; ++ return ret; + } + + off += sh->len; +@@ -319,8 +320,9 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + double K; + u64 raid5_used, raid6_used; + +- if ((sargs = load_space_info(fd, path)) == NULL) { +- ret = -1; ++ sargs = load_space_info(fd, path); ++ if (!sargs) { ++ ret = 1; + goto exit; + } + +@@ -331,7 +333,7 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + "ERROR: couldn't get space info on '%s' - %s\n", + path, strerror(e)); + +- ret = 19; ++ ret = 1; + goto exit; + } + get_raid56_used(fd, chunkinfo, chunkcount, &raid5_used, &raid6_used); +@@ -439,13 +441,13 @@ static int load_device_info(int fd, struct device_info **device_info_ptr, + return ret; + if (ret < 0) { + fprintf(stderr, "ERROR: cannot get filesystem info\n"); +- return -1; ++ return ret; + } + + info = calloc(fi_args.num_devices, sizeof(struct device_info)); + if (!info) { + fprintf(stderr, "ERROR: not enough memory\n"); +- return -1; ++ return ret; + } + + for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) { +@@ -460,7 +462,7 @@ static int load_device_info(int fd, struct device_info **device_info_ptr, + "ERROR: cannot get info about device devid=%d\n", + i); + free(info); +- return -1; ++ return ret; + } + + info[ndevs].devid = dev_info.devid; +@@ -749,7 +751,7 @@ static int print_filesystem_usage_by_chunk(int fd, + sargs = load_space_info(fd, path); + if (!sargs) { + ret = 1; +- goto exit; ++ goto out; + } + + if (tabular) +@@ -759,9 +761,8 @@ static int print_filesystem_usage_by_chunk(int fd, + _cmd_filesystem_usage_linear(mode, sargs, chunkinfo, + chunkcount, devinfo, devcount); + +-exit: + free(sargs); +- ++out: + return ret; + } + +@@ -777,6 +778,7 @@ const char * const cmd_filesystem_usage_usage[] = { + int cmd_filesystem_usage(int argc, char **argv) + { + int mode = UNITS_HUMAN; ++ int ret = 0; + int i, more_than_one = 0; + int tabular = 0; + +@@ -803,7 +805,6 @@ int cmd_filesystem_usage(int argc, char **argv) + usage(cmd_filesystem_usage_usage); + + for (i = optind; i < argc; i++) { +- int ret; + int fd; + DIR *dirstream = NULL; + struct chunk_info *chunkinfo = NULL; +@@ -813,9 +814,10 @@ int cmd_filesystem_usage(int argc, char **argv) + + fd = open_file_or_dir(argv[i], &dirstream); + if (fd < 0) { +- fprintf(stderr, "ERROR: can't access to '%s'\n", ++ fprintf(stderr, "ERROR: can't access '%s'\n", + argv[1]); +- return 12; ++ ret = 1; ++ goto out; + } + if (more_than_one) + printf("\n"); +@@ -838,11 +840,12 @@ cleanup: + free(devinfo); + + if (ret) +- return ret; ++ goto out; + more_than_one = 1; + } + +- return 0; ++out: ++ return !!ret; + } + + void print_device_chunks(int fd, struct device_info *devinfo, +-- +1.9.0 + diff --git a/0031-btrfs-progs-move-global-reserve-to-overall-summary.patch b/0031-btrfs-progs-move-global-reserve-to-overall-summary.patch new file mode 100644 index 0000000..41c1bb6 --- /dev/null +++ b/0031-btrfs-progs-move-global-reserve-to-overall-summary.patch @@ -0,0 +1,96 @@ +From 552e2741a3b0ce344c73b3e1d80d385605d49e75 Mon Sep 17 00:00:00 2001 +From: David Sterba +Date: Tue, 29 Apr 2014 17:32:22 +0200 +Subject: [PATCH 42/42] btrfs-progs: move global reserve to overall summary + +It looks confusing among the chunks, it is not in fact a chunk type. + +Sample: +Overall: + Device size: 35.00GiB + Device allocated: 8.07GiB + Device unallocated: 26.93GiB + Used: 1.12MiB + Free (Estimated): 17.57GiB (Max: 30.98GiB, min: 17.52GiB) + Data to device ratio: 50 % + Global reserve: 16.00MiB (used: 0.00B) +... + +Signed-off-by: David Sterba +--- + cmds-fi-disk_usage.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c +index 7c93247e4f54..0caba159b974 100644 +--- a/cmds-fi-disk_usage.c ++++ b/cmds-fi-disk_usage.c +@@ -319,6 +319,8 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + u64 total_free; /* logical space un-used */ + double K; + u64 raid5_used, raid6_used; ++ u64 global_reserve; ++ u64 global_reserve_used; + + sargs = load_space_info(fd, path); + if (!sargs) { +@@ -341,6 +343,8 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + total_chunks = 0; + total_used = 0; + total_free = 0; ++ global_reserve = 0; ++ global_reserve_used = 0; + + for (i = 0; i < sargs->total_spaces; i++) { + float ratio = 1; +@@ -366,6 +370,11 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + else + ratio = 1; + ++ if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) { ++ global_reserve = sargs->spaces[i].total_bytes; ++ global_reserve_used = sargs->spaces[i].used_bytes; ++ } ++ + allocated = sargs->spaces[i].total_bytes * ratio; + + total_chunks += allocated; +@@ -404,6 +413,9 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + pretty_size_mode((total_disk-total_chunks) / 2 + total_free, mode)); + printf(" Data to device ratio:\t%*.0f %%\n", + width - 2, K * 100); ++ printf(" Global reserve:\t\t%*s\t(used: %s)\n", width, ++ pretty_size_mode(global_reserve, mode), ++ pretty_size_mode(global_reserve_used, mode)); + + exit: + +@@ -553,8 +565,11 @@ static void _cmd_filesystem_usage_tabular(int mode, + /* header */ + for (i = 0; i < sargs->total_spaces; i++) { + const char *description; +- + u64 flags = sargs->spaces[i].flags; ++ ++ if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) ++ continue; ++ + description = group_type_str(flags); + + table_printf(matrix, 1+i, 0, "<%s", description); +@@ -715,8 +730,11 @@ static void _cmd_filesystem_usage_linear(int mode, + for (i = 0; i < sargs->total_spaces; i++) { + const char *description; + const char *r_mode; +- + u64 flags = sargs->spaces[i].flags; ++ ++ if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) ++ continue; ++ + description= group_type_str(flags); + r_mode = group_profile_str(flags); + +-- +1.9.0 + diff --git a/btrfs-progs-v3.14.1.tar.bz2 b/btrfs-progs-v3.14.1.tar.bz2 new file mode 100644 index 0000000..ff9c620 --- /dev/null +++ b/btrfs-progs-v3.14.1.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91b731c9889cdad80d36e6f0345b9dc6fa0e7f98eda5730bfd88947ff4afedb1 +size 281329 diff --git a/btrfs-progs-v3.14.tar.bz2 b/btrfs-progs-v3.14.tar.bz2 deleted file mode 100644 index c95d2df..0000000 --- a/btrfs-progs-v3.14.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d5680d1ae0a88f6f07350e1dd8e81a1d6933bf7eccd4233c9d24f5a7b8f482bd -size 281254 diff --git a/btrfsprogs.changes b/btrfsprogs.changes index 4a0e984..4fface7 100644 --- a/btrfsprogs.changes +++ b/btrfsprogs.changes @@ -1,3 +1,53 @@ +------------------------------------------------------------------- +Fri May 2 13:37:04 UTC 2014 - dsterba@suse.cz + +- update to upstream 3.14.1 +- mkfs: + - fix TRIM detection + - do not zero-out end of device unconditionally + - no crash with --features option +- fsck: + - clear log tree in repair mode + - check reloc roots +- btrfs - reworked space reporting (bnc#873106) + - btrfs fi usage - new command + - btrfs dev usage - new command + - btrfs fi df - enhanced output with GlobalReserve +- Removed patches: + * 0001-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch +- Added patches: + * 0001-Btrfs-progs-fix-check-to-test-trim-support.patch + * 0002-Btrfs-progs-fsck-fix-double-free-memory-crash.patch + * 0003-Btrfs-progs-mkfs-Remove-zero_end-1-since-it-has-been.patch + * 0004-btrfs-progs-fix-wrong-max-system-array-size-check-in.patch + * 0005-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch + * 0006-Btrfs-progs-fsck-clear-out-log-tree-in-repair-mode.patch + * 0007-Btrfs-progs-fsck-avoid-pinning-same-block-several-ti.patch + * 0008-Btrfs-progs-fsck-add-ability-to-check-reloc-roots.patch + * 0009-btrfs-progs-prevent-close_root-if-the-root-to-close-.patch + * 0010-btrfs-progs-fix-mkfs.btrfs-segfault-with-features-op.patch + * 0011-btrfs-progs-Enhance-the-command-btrfs-filesystem-df.patch + * 0012-btrfs-progs-Add-helpers-functions-to-handle-the-prin.patch + * 0013-btrfs-progs-Add-command-btrfs-filesystem-disk-usage.patch + * 0014-btrfs-progs-Add-btrfs-device-disk-usage-command.patch + * 0015-btrfs-progs-cleanup-dead-return-after-usage-for-fi-d.patch + * 0016-btrfs-progs-Fix-memleak-in-get_raid56_used.patch + * 0017-Btrfs-progs-fi-usage-free-memory-if-realloc-fails.patch + * 0018-btrfs-progs-read-global-reserve-size-from-space-info.patch + * 0019-btrfs-progs-add-original-df-and-rename-disk_usage-to.patch + * 0020-btrfs-progs-move-device-usage-to-cmds-device-more-cl.patch + * 0021-btrfs-progs-check-if-we-can-t-get-info-from-ioctls-d.patch + * 0022-btrfs-progs-zero-out-structures-before-calling-ioctl.patch + * 0023-btrfs-progs-print-B-for-bytes.patch + * 0024-btrfs-progs-Print-more-info-about-device-sizes.patch + * 0025-btrfs-progs-compare-unallocated-space-against-the-co.patch + * 0026-btrfs-progs-add-section-of-overall-filesystem-usage.patch + * 0027-btrfs-progs-cleanup-filesystem-device-usage-code.patch + * 0028-btrfs-progs-extend-pretty-printers-with-unit-mode.patch + * 0029-btrfs-progs-replace-df_pretty_sizes-with-pretty_size.patch + * 0030-btrfs-progs-clean-up-return-codes-and-paths.patch + * 0031-btrfs-progs-move-global-reserve-to-overall-summary.patch + ------------------------------------------------------------------- Sat Apr 26 09:45:23 UTC 2014 - coolo@suse.com diff --git a/btrfsprogs.spec b/btrfsprogs.spec index 2aeffb5..968afaf 100644 --- a/btrfsprogs.spec +++ b/btrfsprogs.spec @@ -16,9 +16,9 @@ # -%define tar_version v3.14 +%define tar_version v3.14.1 Name: btrfsprogs -Version: 3.14 +Version: 3.14.1 Release: 0 Summary: Utilities for the Btrfs filesystem License: GPL-2.0 @@ -31,7 +31,37 @@ Source: btrfs-progs-%{tar_version}.tar.bz2 Source1: boot-btrfs.sh Source4: setup-btrfs.sh -Patch1: 0001-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch +Patch1: 0001-Btrfs-progs-fix-check-to-test-trim-support.patch +Patch2: 0002-Btrfs-progs-fsck-fix-double-free-memory-crash.patch +Patch3: 0003-Btrfs-progs-mkfs-Remove-zero_end-1-since-it-has-been.patch +Patch4: 0004-btrfs-progs-fix-wrong-max-system-array-size-check-in.patch +Patch5: 0005-btrfs-progs-move-arg_strtou64-to-a-separate-file-for.patch +Patch6: 0006-Btrfs-progs-fsck-clear-out-log-tree-in-repair-mode.patch +Patch7: 0007-Btrfs-progs-fsck-avoid-pinning-same-block-several-ti.patch +Patch8: 0008-Btrfs-progs-fsck-add-ability-to-check-reloc-roots.patch +Patch9: 0009-btrfs-progs-prevent-close_root-if-the-root-to-close-.patch +Patch10: 0010-btrfs-progs-fix-mkfs.btrfs-segfault-with-features-op.patch +Patch11: 0011-btrfs-progs-Enhance-the-command-btrfs-filesystem-df.patch +Patch12: 0012-btrfs-progs-Add-helpers-functions-to-handle-the-prin.patch +Patch13: 0013-btrfs-progs-Add-command-btrfs-filesystem-disk-usage.patch +Patch14: 0014-btrfs-progs-Add-btrfs-device-disk-usage-command.patch +Patch15: 0015-btrfs-progs-cleanup-dead-return-after-usage-for-fi-d.patch +Patch16: 0016-btrfs-progs-Fix-memleak-in-get_raid56_used.patch +Patch17: 0017-Btrfs-progs-fi-usage-free-memory-if-realloc-fails.patch +Patch18: 0018-btrfs-progs-read-global-reserve-size-from-space-info.patch +Patch19: 0019-btrfs-progs-add-original-df-and-rename-disk_usage-to.patch +Patch20: 0020-btrfs-progs-move-device-usage-to-cmds-device-more-cl.patch +Patch21: 0021-btrfs-progs-check-if-we-can-t-get-info-from-ioctls-d.patch +Patch22: 0022-btrfs-progs-zero-out-structures-before-calling-ioctl.patch +Patch23: 0023-btrfs-progs-print-B-for-bytes.patch +Patch24: 0024-btrfs-progs-Print-more-info-about-device-sizes.patch +Patch25: 0025-btrfs-progs-compare-unallocated-space-against-the-co.patch +Patch26: 0026-btrfs-progs-add-section-of-overall-filesystem-usage.patch +Patch27: 0027-btrfs-progs-cleanup-filesystem-device-usage-code.patch +Patch28: 0028-btrfs-progs-extend-pretty-printers-with-unit-mode.patch +Patch29: 0029-btrfs-progs-replace-df_pretty_sizes-with-pretty_size.patch +Patch30: 0030-btrfs-progs-clean-up-return-codes-and-paths.patch +Patch31: 0031-btrfs-progs-move-global-reserve-to-overall-summary.patch Patch163: 0163-btrfs-progs-fsck-fix-segfault.patch Patch164: 0164-btrfs-progs-convert-set-label-or-copy-from-origin.patch @@ -77,6 +107,36 @@ build applications to interface with btrfs. %prep %setup -q -n btrfs-progs-%{tar_version} %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 %patch163 -p1 %patch164 -p1 %patch167 -p1 diff --git a/local-version-override.patch b/local-version-override.patch index ac87eb2..c5ff23a 100644 --- a/local-version-override.patch +++ b/local-version-override.patch @@ -6,8 +6,8 @@ Index: btrfs-progs-v0.19-116-g13eced9/version.sh # Copyright 2008, Oracle # Released under the GNU GPLv2 --v="v3.14" -+v="v3.14+20140408" +-v="v3.14.1" ++v="v3.14.1+20140502" which git &> /dev/null if [ $? == 0 -a -d .git ]; then