From: Liu Bo <bo.li...@oracle.com> This aims to decide whether a balance can reduce the number of data block groups and if it can, this shows the '-dvrange' block group's objectid.
With this, you can run 'btrfs balance start -c mnt' or 'btrfs balance start --check-only mnt' -------------------------------------------------------------- $ btrfs balance start -c /mnt/btrfs Checking data block groups... block_group 12582912 (len 8388608 used 786432) block_group 1103101952 (len 1073741824 used 536870912) block_group 2176843776 (len 1073741824 used 1073741824) total bgs 3 total_free 544473088 min_used bg 12582912 has (min_used 786432 free 7602176) run 'btrfs balance start -dvrange=12582912..12582913 your_mnt' $ btrfs balance start -dvrange=12582912..12582913 /mnt/btrfs Done, had to relocate 1 out of 5 chunks $ btrfs balance start -c /mnt/btrfs Checking data block groups... block_group 1103101952 (len 1073741824 used 537395200) block_group 2176843776 (len 1073741824 used 1073741824) total bgs 2 total_free 536346624 min_used bg 1103101952 has (min_used 537395200 free 536346624) -------------------------------------------------------------- So you now know how to babysit your btrfs in a smart way. Signed-off-by: Liu Bo <bo.li....@oracle.com> Signed-off-by: Ashish Samant <ashish.sam...@oracle.com> --- cmds-balance.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 126 insertions(+), 1 deletions(-) diff --git a/cmds-balance.c b/cmds-balance.c index 8f3bf5b..e2aab6c 100644 --- a/cmds-balance.c +++ b/cmds-balance.c @@ -493,6 +493,116 @@ out: return ret; } +/* return 0 if balance can remove a data block group, otherwise return 1 */ +static int search_data_bgs(const char *path) +{ + struct btrfs_ioctl_search_args args; + struct btrfs_ioctl_search_key *sk; + struct btrfs_ioctl_search_header *header; + struct btrfs_block_group_item *bg; + unsigned long off = 0; + DIR *dirstream = NULL; + int e; + int fd; + int i; + u64 total_free = 0; + u64 min_used = (u64)-1; + u64 free_of_min_used = 0; + u64 bg_of_min_used = 0; + u64 flags; + u64 used; + int ret = 0; + int nr_data_bgs = 0; + + fd = btrfs_open_dir(path, &dirstream, 1); + if (fd < 0) + return 1; + + memset(&args, 0, sizeof(args)); + sk = &args.key; + + sk->tree_id = BTRFS_EXTENT_TREE_OBJECTID; + sk->min_objectid = sk->min_offset = sk->min_transid = 0; + sk->max_objectid = sk->max_offset = sk->max_transid = (u64)-1; + sk->max_type = sk->min_type = BTRFS_BLOCK_GROUP_ITEM_KEY; + sk->nr_items = 65536; + + while (1) { + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); + e = errno; + if (ret < 0) { + fprintf(stderr, "ret %d error '%s'\n", ret, + strerror(e)); + return ret; + } + /* + * it should not happen. + */ + if (sk->nr_items == 0) + break; + + off = 0; + for (i = 0; i < sk->nr_items; i++) { + header = (struct btrfs_ioctl_search_header *)(args.buf + + off); + + off += sizeof(*header); + if (header->type == BTRFS_BLOCK_GROUP_ITEM_KEY) { + bg = (struct btrfs_block_group_item *) + (args.buf + off); + flags = btrfs_block_group_flags(bg); + if (flags & BTRFS_BLOCK_GROUP_DATA) { + nr_data_bgs++; + used = btrfs_block_group_used(bg); + printf( + "block_group %15llu (len %11llu used %11llu)\n", + header->objectid, + header->offset, used); + total_free += header->offset - used; + if (min_used >= used) { + min_used = used; + free_of_min_used = + header->offset - used; + bg_of_min_used = + header->objectid; + } + } + } + + off += header->len; + sk->min_objectid = header->objectid; + sk->min_type = header->type; + sk->min_offset = header->offset; + } + sk->nr_items = 65536; + + if (sk->min_objectid < sk->max_objectid) + sk->min_objectid += 1; + else + break; + } + + if (nr_data_bgs <= 1) { + printf("Data block groups in fs = %d, no need to do balance.\n", + nr_data_bgs); + return 1; + } + + printf("total bgs %d total_free %llu min_used bg %llu has (min_used %llu free %llu)\n", + nr_data_bgs, total_free, bg_of_min_used, min_used, + free_of_min_used); + if (total_free - free_of_min_used > min_used) { + printf("run 'btrfs balance start -dvrange=%llu..%llu <mountpoint>'\n", + bg_of_min_used, bg_of_min_used + 1); + ret = 0; + } else { + printf("Please don't balance data block groups, it won't work.\n"); + ret = 1; + } + + return ret; +} + static const char * const cmd_balance_start_usage[] = { "btrfs balance start [options] <path>", "Balance chunks across the devices", @@ -508,6 +618,7 @@ static const char * const cmd_balance_start_usage[] = { "-m[filters] act on metadata chunks", "-s[filters] act on system chunks (only under -f)", "-v be verbose", + "-c only check if balance would make sense, not doing real job", "-f force reducing of metadata integrity", "--full-balance do not print warning and do not delay start", NULL @@ -521,6 +632,7 @@ static int cmd_balance_start(int argc, char **argv) int force = 0; int verbose = 0; unsigned start_flags = 0; + int check_data_bgs = 0; int i; memset(&args, 0, sizeof(args)); @@ -534,12 +646,14 @@ static int cmd_balance_start(int argc, char **argv) { "system", optional_argument, NULL, 's' }, { "force", no_argument, NULL, 'f' }, { "verbose", no_argument, NULL, 'v' }, + { "check-only", no_argument, NULL, 'c' }, { "full-balance", no_argument, NULL, GETOPT_VAL_FULL_BALANCE }, { NULL, 0, NULL, 0 } }; - int opt = getopt_long(argc, argv, "d::s::m::fv", longopts, NULL); + int opt = getopt_long(argc, argv, "d::s::m::fvc", longopts, + NULL); if (opt < 0) break; @@ -571,6 +685,9 @@ static int cmd_balance_start(int argc, char **argv) case 'v': verbose = 1; break; + case 'c': + check_data_bgs = 1; + break; case GETOPT_VAL_FULL_BALANCE: start_flags |= BALANCE_START_NOWARN; break; @@ -582,6 +699,14 @@ static int cmd_balance_start(int argc, char **argv) if (check_argc_exact(argc - optind, 1)) usage(cmd_balance_start_usage); + if (check_data_bgs) { + if (verbose) + dump_ioctl_balance_args(&args); + + printf("Checking data block groups...\n"); + return search_data_bgs(argv[optind]); + } + /* * allow -s only under --force, otherwise do with system chunks * the same thing we were ordered to do with meta chunks -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html