diff -Nru btrfs-tools-3.19.1/btrfs-calc-size.c btrfs-tools-4.0/btrfs-calc-size.c --- btrfs-tools-3.19.1/btrfs-calc-size.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/btrfs-calc-size.c 2015-04-29 14:56:22.000000000 +0000 @@ -218,9 +218,9 @@ struct rb_node *n = rb_first(&stat->seek_root); struct seek *seek; u64 tick_interval; - u64 group_start; + u64 group_start = 0; u64 group_count = 0; - u64 group_end; + u64 group_end = 0; u64 i; u64 max_seek = stat->max_seek_len; int digits = 1; diff -Nru btrfs-tools-3.19.1/btrfs-convert.c btrfs-tools-4.0/btrfs-convert.c --- btrfs-tools-3.19.1/btrfs-convert.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/btrfs-convert.c 2015-04-29 14:56:22.000000000 +0000 @@ -1161,7 +1161,7 @@ struct btrfs_root *root, u64 objectid, struct btrfs_inode_item *inode, u64 start_byte, u64 end_byte, - ext2_filsys ext2_fs) + ext2_filsys ext2_fs, int datacsum) { u32 blocksize = ext2_fs->blocksize; u32 block = start_byte / blocksize; @@ -1176,7 +1176,7 @@ .disk_block = 0, .num_blocks = 0, .boundary = (u64)-1, - .checksum = 0, + .checksum = datacsum, .errcode = 0, }; for (; start_byte < end_byte; block++, start_byte += blocksize) { @@ -1191,7 +1191,7 @@ if (data.num_blocks > 0) { ret = record_file_blocks(trans, root, objectid, inode, data.first_block, data.disk_block, - data.num_blocks, 0); + data.num_blocks, datacsum); if (ret) goto fail; data.first_block += data.num_blocks; @@ -1199,7 +1199,7 @@ if (last_block > data.first_block) { ret = record_file_blocks(trans, root, objectid, inode, data.first_block, 0, last_block - - data.first_block, 0); + data.first_block, datacsum); if (ret) goto fail; } @@ -1210,7 +1210,7 @@ * Create the ext2fs image file. */ static int create_ext2_image(struct btrfs_root *root, ext2_filsys ext2_fs, - const char *name) + const char *name, int datacsum) { int ret; struct btrfs_key key; @@ -1231,11 +1231,14 @@ u64 last_byte; u64 first_free; u64 total_bytes; + u64 flags = BTRFS_INODE_READONLY; u32 sectorsize = root->sectorsize; total_bytes = btrfs_super_total_bytes(fs_info->super_copy); first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize * 2 - 1; first_free &= ~((u64)sectorsize - 1); + if (!datacsum) + flags |= BTRFS_INODE_NODATASUM; memset(&btrfs_inode, 0, sizeof(btrfs_inode)); btrfs_set_stack_inode_generation(&btrfs_inode, 1); @@ -1243,8 +1246,7 @@ btrfs_set_stack_inode_nlink(&btrfs_inode, 1); btrfs_set_stack_inode_nbytes(&btrfs_inode, 0); btrfs_set_stack_inode_mode(&btrfs_inode, S_IFREG | 0400); - btrfs_set_stack_inode_flags(&btrfs_inode, BTRFS_INODE_NODATASUM | - BTRFS_INODE_READONLY); + btrfs_set_stack_inode_flags(&btrfs_inode, flags); btrfs_init_path(&path); trans = btrfs_start_transaction(root, 1); BUG_ON(!trans); @@ -1271,6 +1273,12 @@ key.objectid, sectorsize); if (ret) goto fail; + if (datacsum) { + ret = csum_disk_extent(trans, root, key.objectid, + sectorsize); + if (ret) + goto fail; + } } while(1) { @@ -1323,7 +1331,8 @@ if (bytenr > last_byte) { ret = create_image_file_range(trans, root, objectid, &btrfs_inode, last_byte, - bytenr, ext2_fs); + bytenr, ext2_fs, + datacsum); if (ret) goto fail; } @@ -1346,7 +1355,8 @@ if (total_bytes > last_byte) { ret = create_image_file_range(trans, root, objectid, &btrfs_inode, last_byte, - total_bytes, ext2_fs); + total_bytes, ext2_fs, + datacsum); if (ret) goto fail; } @@ -1789,20 +1799,20 @@ return 0; } -static int prepare_system_chunk(int fd, u64 sb_bytenr, u32 sectorsize) +static int prepare_system_chunk(int fd, u64 sb_bytenr) { int ret; struct extent_buffer *buf; struct btrfs_super_block *super; - BUG_ON(sectorsize < sizeof(*super)); - buf = malloc(sizeof(*buf) + sectorsize); + BUG_ON(BTRFS_SUPER_INFO_SIZE < sizeof(*super)); + buf = malloc(sizeof(*buf) + BTRFS_SUPER_INFO_SIZE); if (!buf) return -ENOMEM; - buf->len = sectorsize; - ret = pread(fd, buf->data, sectorsize, sb_bytenr); - if (ret != sectorsize) + buf->len = BTRFS_SUPER_INFO_SIZE; + ret = pread(fd, buf->data, BTRFS_SUPER_INFO_SIZE, sb_bytenr); + if (ret != BTRFS_SUPER_INFO_SIZE) goto fail; super = (struct btrfs_super_block *)buf->data; @@ -1814,8 +1824,8 @@ goto fail; csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); - ret = pwrite(fd, buf->data, sectorsize, sb_bytenr); - if (ret != sectorsize) + ret = pwrite(fd, buf->data, BTRFS_SUPER_INFO_SIZE, sb_bytenr); + if (ret != BTRFS_SUPER_INFO_SIZE) goto fail; ret = 0; @@ -2288,7 +2298,7 @@ fprintf(stderr, "filetype feature is missing\n"); goto fail; } - if (btrfs_check_node_or_leaf_size(nodesize, blocksize)) + if (btrfs_check_nodesize(nodesize, blocksize)) goto fail; blocks_per_node = nodesize / blocksize; ret = -blocks_per_node; @@ -2312,7 +2322,7 @@ goto fail; } ret = make_btrfs(fd, devname, ext2_fs->super->s_volume_name, - NULL, blocks, total_bytes, nodesize, nodesize, + NULL, blocks, total_bytes, nodesize, blocksize, blocksize, 0); if (ret) { fprintf(stderr, "unable to create initial ctree: %s\n", @@ -2320,7 +2330,7 @@ goto fail; } /* create a system chunk that maps the whole device */ - ret = prepare_system_chunk(fd, super_bytenr, blocksize); + ret = prepare_system_chunk(fd, super_bytenr); if (ret) { fprintf(stderr, "unable to update system chunk\n"); goto fail; @@ -2374,7 +2384,7 @@ fprintf(stderr, "unable to create subvol\n"); goto fail; } - ret = create_ext2_image(ext2_root, ext2_fs, "image"); + ret = create_ext2_image(ext2_root, ext2_fs, "image", datacsum); if (ret) { fprintf(stderr, "error during create_ext2_image %d\n", ret); goto fail; @@ -2828,7 +2838,6 @@ char *fslabel = NULL; while(1) { - int long_index; enum { GETOPT_VAL_NO_PROGRESS = 256 }; static const struct option long_options[] = { { "no-progress", no_argument, NULL, @@ -2843,8 +2852,7 @@ { "nodesize", required_argument, NULL, 'N' }, { NULL, 0, NULL, 0 } }; - int c = getopt_long(argc, argv, "dinN:rl:Lp", long_options, - &long_index); + int c = getopt_long(argc, argv, "dinN:rl:Lp", long_options, NULL); if (c < 0) break; diff -Nru btrfs-tools-3.19.1/btrfs-corrupt-block.c btrfs-tools-4.0/btrfs-corrupt-block.c --- btrfs-tools-3.19.1/btrfs-corrupt-block.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/btrfs-corrupt-block.c 2015-04-29 14:56:22.000000000 +0000 @@ -1017,31 +1017,30 @@ while(1) { int c; - int option_index = 0; static const struct option long_options[] = { /* { "byte-count", 1, NULL, 'b' }, */ - { "logical", 1, NULL, 'l' }, - { "copy", 1, NULL, 'c' }, - { "bytes", 1, NULL, 'b' }, - { "extent-record", 0, NULL, 'e' }, - { "extent-tree", 0, NULL, 'E' }, - { "keys", 0, NULL, 'k' }, - { "chunk-record", 0, NULL, 'u' }, - { "chunk-tree", 0, NULL, 'U' }, - { "inode", 1, NULL, 'i'}, - { "file-extent", 1, NULL, 'x'}, - { "metadata-block", 1, NULL, 'm'}, - { "field", 1, NULL, 'f'}, - { "key", 1, NULL, 'K'}, - { "item", 0, NULL, 'I'}, - { "dir-item", 0, NULL, 'D'}, - { "delete", 0, NULL, 'd'}, - { "root", 0, NULL, 'r'}, + { "logical", required_argument, NULL, 'l' }, + { "copy", required_argument, NULL, 'c' }, + { "bytes", required_argument, NULL, 'b' }, + { "extent-record", no_argument, NULL, 'e' }, + { "extent-tree", no_argument, NULL, 'E' }, + { "keys", no_argument, NULL, 'k' }, + { "chunk-record", no_argument, NULL, 'u' }, + { "chunk-tree", no_argument, NULL, 'U' }, + { "inode", required_argument, NULL, 'i'}, + { "file-extent", required_argument, NULL, 'x'}, + { "metadata-block", required_argument, NULL, 'm'}, + { "field", required_argument, NULL, 'f'}, + { "key", required_argument, NULL, 'K'}, + { "item", no_argument, NULL, 'I'}, + { "dir-item", no_argument, NULL, 'D'}, + { "delete", no_argument, NULL, 'd'}, + { "root", no_argument, NULL, 'r'}, { NULL, 0, NULL, 0 } }; c = getopt_long(ac, av, "l:c:b:eEkuUi:f:x:m:K:IDdr:", - long_options, &option_index); + long_options, NULL); if (c < 0) break; switch(c) { diff -Nru btrfs-tools-3.19.1/btrfs-map-logical.c btrfs-tools-4.0/btrfs-map-logical.c --- btrfs-tools-3.19.1/btrfs-map-logical.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/btrfs-map-logical.c 2015-04-29 14:56:22.000000000 +0000 @@ -124,18 +124,16 @@ while(1) { int c; - int option_index = 0; static const struct option long_options[] = { /* { "byte-count", 1, NULL, 'b' }, */ - { "logical", 1, NULL, 'l' }, - { "copy", 1, NULL, 'c' }, - { "output", 1, NULL, 'o' }, - { "bytes", 1, NULL, 'b' }, + { "logical", required_argument, NULL, 'l' }, + { "copy", required_argument, NULL, 'c' }, + { "output", required_argument, NULL, 'o' }, + { "bytes", required_argument, NULL, 'b' }, { NULL, 0, NULL, 0} }; - c = getopt_long(ac, av, "l:c:o:b:", long_options, - &option_index); + c = getopt_long(ac, av, "l:c:o:b:", long_options, NULL); if (c < 0) break; switch(c) { diff -Nru btrfs-tools-3.19.1/cmds-balance.c btrfs-tools-4.0/cmds-balance.c --- btrfs-tools-3.19.1/cmds-balance.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-balance.c 2015-04-29 14:56:22.000000000 +0000 @@ -389,7 +389,6 @@ optind = 1; while (1) { - int longindex; static const struct option longopts[] = { { "data", optional_argument, NULL, 'd'}, { "metadata", optional_argument, NULL, 'm' }, @@ -399,8 +398,7 @@ { NULL, 0, NULL, 0 } }; - int opt = getopt_long(argc, argv, "d::s::m::fv", longopts, - &longindex); + int opt = getopt_long(argc, argv, "d::s::m::fv", longopts, NULL); if (opt < 0) break; @@ -661,13 +659,13 @@ optind = 1; while (1) { - int longindex; + int opt; static const struct option longopts[] = { { "verbose", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; - int opt = getopt_long(argc, argv, "v", longopts, &longindex); + opt = getopt_long(argc, argv, "v", longopts, NULL); if (opt < 0) break; diff -Nru btrfs-tools-3.19.1/cmds-check.c btrfs-tools-4.0/cmds-check.c --- btrfs-tools-3.19.1/cmds-check.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-check.c 2015-04-29 14:56:22.000000000 +0000 @@ -286,8 +286,10 @@ { struct file_extent_hole *hole; struct file_extent_hole tmp; - struct file_extent_hole prev; - struct file_extent_hole next; + u64 prev_start = 0; + u64 prev_len = 0; + u64 next_start = 0; + u64 next_len = 0; struct rb_node *node; int have_prev = 0; int have_next = 0; @@ -307,24 +309,24 @@ * split(s) if they exists. */ if (start > hole->start) { - prev.start = hole->start; - prev.len = start - hole->start; + prev_start = hole->start; + prev_len = start - hole->start; have_prev = 1; } if (hole->start + hole->len > start + len) { - next.start = start + len; - next.len = hole->start + hole->len - start - len; + next_start = start + len; + next_len = hole->start + hole->len - start - len; have_next = 1; } rb_erase(node, holes); free(hole); if (have_prev) { - ret = add_file_extent_hole(holes, prev.start, prev.len); + ret = add_file_extent_hole(holes, prev_start, prev_len); if (ret < 0) return ret; } if (have_next) { - ret = add_file_extent_hole(holes, next.start, next.len); + ret = add_file_extent_hole(holes, next_start, next_len); if (ret < 0) return ret; } @@ -9221,25 +9223,23 @@ while(1) { int c; - int option_index = 0; enum { OPT_REPAIR = 257, OPT_INIT_CSUM, OPT_INIT_EXTENT, OPT_CHECK_CSUM, OPT_READONLY }; static const struct option long_options[] = { - { "super", 1, NULL, 's' }, - { "repair", 0, NULL, OPT_REPAIR }, - { "readonly", 0, NULL, OPT_READONLY }, - { "init-csum-tree", 0, NULL, OPT_INIT_CSUM }, - { "init-extent-tree", 0, NULL, OPT_INIT_EXTENT }, - { "check-data-csum", 0, NULL, OPT_CHECK_CSUM }, - { "backup", 0, NULL, 'b' }, - { "subvol-extents", 1, NULL, 'E' }, - { "qgroup-report", 0, NULL, 'Q' }, - { "tree-root", 1, NULL, 'r' }, + { "super", required_argument, NULL, 's' }, + { "repair", no_argument, NULL, OPT_REPAIR }, + { "readonly", no_argument, NULL, OPT_READONLY }, + { "init-csum-tree", no_argument, NULL, OPT_INIT_CSUM }, + { "init-extent-tree", no_argument, NULL, OPT_INIT_EXTENT }, + { "check-data-csum", no_argument, NULL, OPT_CHECK_CSUM }, + { "backup", no_argument, NULL, 'b' }, + { "subvol-extents", required_argument, NULL, 'E' }, + { "qgroup-report", no_argument, NULL, 'Q' }, + { "tree-root", required_argument, NULL, 'r' }, { NULL, 0, NULL, 0} }; - c = getopt_long(argc, argv, "as:br:", long_options, - &option_index); + c = getopt_long(argc, argv, "as:br:", long_options, NULL); if (c < 0) break; switch(c) { diff -Nru btrfs-tools-3.19.1/cmds-device.c btrfs-tools-4.0/cmds-device.c --- btrfs-tools-3.19.1/cmds-device.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-device.c 2015-04-29 14:56:22.000000000 +0000 @@ -28,7 +28,7 @@ #include "ctree.h" #include "ioctl.h" #include "utils.h" -#include "cmds-fi-disk_usage.h" +#include "cmds-fi-usage.h" #include "commands.h" @@ -55,14 +55,14 @@ char estr[100]; while (1) { - int long_index; + int c; static const struct option long_options[] = { { "nodiscard", optional_argument, NULL, 'K'}, { "force", no_argument, NULL, 'f'}, { NULL, 0, NULL, 0} }; - int c = getopt_long(argc, argv, "Kf", long_options, - &long_index); + + c = getopt_long(argc, argv, "Kf", long_options, NULL); if (c < 0) break; switch (c) { @@ -180,15 +180,16 @@ strncpy_null(arg.name, argv[i]); res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); e = errno; - if (res > 0) { - fprintf(stderr, - "ERROR: error removing the device '%s' - %s\n", - argv[i], btrfs_err_str(res)); - ret++; - } else if (res < 0) { + if (res) { + const char *msg; + + if (ret > 0) + msg = btrfs_err_str(res); + else + msg = strerror(e); fprintf(stderr, "ERROR: error removing the device '%s' - %s\n", - argv[i], strerror(e)); + argv[i], msg); ret++; } } @@ -213,13 +214,13 @@ optind = 1; while (1) { - int long_index; + int c; static const struct option long_options[] = { { "all-devices", no_argument, NULL, 'd'}, { NULL, 0, NULL, 0} }; - int c = getopt_long(argc, argv, "d", long_options, - &long_index); + + c = getopt_long(argc, argv, "d", long_options, NULL); if (c < 0) break; switch (c) { @@ -503,7 +504,7 @@ optind = 1; while (1) { - int long_index; + int c; static const struct option long_options[] = { { "raw", no_argument, NULL, 'b'}, { "kbytes", no_argument, NULL, 'k'}, @@ -516,9 +517,8 @@ GETOPT_VAL_HUMAN_READABLE}, { NULL, 0, NULL, 0 } }; - int c = getopt_long(argc, argv, "bhHkmgt", long_options, - &long_index); + c = getopt_long(argc, argv, "bhHkmgt", long_options, NULL); if (c < 0) break; switch (c) { diff -Nru btrfs-tools-3.19.1/cmds-fi-disk_usage.c btrfs-tools-4.0/cmds-fi-disk_usage.c --- btrfs-tools-3.19.1/cmds-fi-disk_usage.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-fi-disk_usage.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1036 +0,0 @@ -/* - * 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 -#include - -#include "utils.h" -#include "kerncompat.h" -#include "ctree.h" -#include "string-table.h" -#include "cmds-fi-disk_usage.h" -#include "commands.h" - -#include "version.h" - -/* - * 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) { - free(*info_ptr); - fprintf(stderr, "ERROR: not enough memory\n"); - return -ENOMEM; - } - - *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); -} - -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 (e == EPERM) - return -e; - - if (ret < 0) { - fprintf(stderr, - "ERROR: can't perform the search - %s\n", - strerror(e)); - return 1; - } - /* 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); - - ret = add_info_to_list(info_ptr, info_count, item); - if (ret) { - *info_ptr = 0; - return 1; - } - - 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 = calloc(1, 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 devices - * if a disk is added later. - */ -static void get_raid56_used(int fd, struct chunk_info *chunks, int chunkcount, - u64 *raid5_used, u64 *raid6_used) -{ - struct chunk_info *info_ptr = chunks; - *raid5_used = 0; - *raid6_used = 0; - - while (chunkcount-- > 0) { - if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID5) - (*raid5_used) += info_ptr->size / (info_ptr->num_stripes - 1); - if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID6) - (*raid6_used) += info_ptr->size / (info_ptr->num_stripes - 2); - info_ptr++; - } -} - -#define MIN_UNALOCATED_THRESH (16 * 1024 * 1024) -static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, - int chunkcount, struct device_info *devinfo, int devcount, - char *path, unsigned unit_mode) -{ - struct btrfs_ioctl_space_args *sargs = 0; - int i; - int ret = 0; - int width = 10; /* default 10 for human units */ - /* - * r_* prefix is for raw data - * l_* is for logical - */ - u64 r_total_size = 0; /* filesystem size, sum of device sizes */ - u64 r_total_chunks = 0; /* sum of chunks sizes on disk(s) */ - u64 r_total_used = 0; - u64 r_total_unused = 0; - u64 r_total_missing = 0; /* sum of missing devices size */ - u64 r_data_used = 0; - u64 r_data_chunks = 0; - u64 l_data_chunks = 0; - u64 r_metadata_used = 0; - u64 r_metadata_chunks = 0; - u64 l_metadata_chunks = 0; - u64 r_system_used = 0; - u64 r_system_chunks = 0; - double data_ratio; - double metadata_ratio; - /* logical */ - u64 raid5_used = 0; - u64 raid6_used = 0; - u64 l_global_reserve = 0; - u64 l_global_reserve_used = 0; - u64 free_estimated = 0; - u64 free_min = 0; - int max_data_ratio = 1; - - sargs = load_space_info(fd, path); - if (!sargs) { - ret = 1; - goto exit; - } - - r_total_size = 0; - for (i = 0; i < devcount; i++) { - r_total_size += devinfo[i].size; - if (!devinfo[i].device_size) - r_total_missing += devinfo[i].size; - } - - if (r_total_size == 0) { - fprintf(stderr, - "ERROR: couldn't get space info on '%s' - %s\n", - path, strerror(errno)); - - ret = 1; - goto exit; - } - get_raid56_used(fd, chunkinfo, chunkcount, &raid5_used, &raid6_used); - - for (i = 0; i < sargs->total_spaces; i++) { - int ratio; - 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; - - if (!ratio) - fprintf(stderr, "WARNING: RAID56 detected, not implemented\n"); - - if (ratio > max_data_ratio) - max_data_ratio = ratio; - - if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) { - l_global_reserve = sargs->spaces[i].total_bytes; - l_global_reserve_used = sargs->spaces[i].used_bytes; - } - if ((flags & (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA)) - == (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA)) { - fprintf(stderr, "WARNING: MIXED blockgroups not handled\n"); - } - - if (flags & BTRFS_BLOCK_GROUP_DATA) { - r_data_used += sargs->spaces[i].used_bytes * ratio; - r_data_chunks += sargs->spaces[i].total_bytes * ratio; - l_data_chunks += sargs->spaces[i].total_bytes; - } - if (flags & BTRFS_BLOCK_GROUP_METADATA) { - r_metadata_used += sargs->spaces[i].used_bytes * ratio; - r_metadata_chunks += sargs->spaces[i].total_bytes * ratio; - l_metadata_chunks += sargs->spaces[i].total_bytes; - } - if (flags & BTRFS_BLOCK_GROUP_SYSTEM) { - r_system_used += sargs->spaces[i].used_bytes * ratio; - r_system_chunks += sargs->spaces[i].total_bytes * ratio; - } - } - - r_total_chunks = r_data_chunks + r_metadata_chunks + r_system_chunks; - r_total_used = r_data_used + r_metadata_used + r_system_used; - r_total_unused = r_total_size - r_total_chunks; - - /* Raw / Logical = raid factor, >= 1 */ - data_ratio = (double)r_data_chunks / l_data_chunks; - metadata_ratio = (double)r_metadata_chunks / l_metadata_chunks; - -#if 0 - /* add the raid5/6 allocated space */ - total_chunks += raid5_used + raid6_used; -#endif - - /* - * We're able to fill at least DATA for the unused space - * - * With mixed raid levels, this gives a rough estimate but more - * accurate than just counting the logical free space - * (l_data_chunks - l_data_used) - * - * In non-mixed case there's no difference. - */ - free_estimated = (r_data_chunks - r_data_used) / data_ratio; - free_min = free_estimated; - - /* Chop unallocatable space */ - /* FIXME: must be applied per device */ - if (r_total_unused >= MIN_UNALOCATED_THRESH) { - free_estimated += r_total_unused / data_ratio; - /* Match the calculation of 'df', use the highest raid ratio */ - free_min += r_total_unused / max_data_ratio; - } - - if (unit_mode != UNITS_HUMAN) - width = 18; - - printf("Overall:\n"); - - printf(" Device size:\t\t%*s\n", width, - pretty_size_mode(r_total_size, unit_mode)); - printf(" Device allocated:\t\t%*s\n", width, - pretty_size_mode(r_total_chunks, unit_mode)); - printf(" Device unallocated:\t\t%*s\n", width, - pretty_size_mode(r_total_unused, unit_mode)); - printf(" Device missing:\t\t%*s\n", width, - pretty_size_mode(r_total_missing, unit_mode)); - printf(" Used:\t\t\t%*s\n", width, - pretty_size_mode(r_total_used, unit_mode)); - printf(" Free (estimated):\t\t%*s\t(", - width, - pretty_size_mode(free_estimated, unit_mode)); - printf("min: %s)\n", pretty_size_mode(free_min, unit_mode)); - printf(" Data ratio:\t\t\t%*.2f\n", - width, data_ratio); - printf(" Metadata ratio:\t\t%*.2f\n", - width, metadata_ratio); - printf(" Global reserve:\t\t%*s\t(used: %s)\n", width, - pretty_size_mode(l_global_reserve, unit_mode), - pretty_size_mode(l_global_reserve_used, unit_mode)); - -exit: - - if (sargs) - free(sargs); - - return ret; -} - -/* - * Helper to sort the device_info structure - */ -static int cmp_device_info(const void *a, const void *b) -{ - return strcmp(((struct device_info *)a)->path, - ((struct device_info *)b)->path); -} - -/* - * This function loads the device_info structure and put them in an array - */ -static int load_device_info(int fd, struct device_info **device_info_ptr, - int *device_info_count) -{ - int ret, i, ndevs, e; - struct btrfs_ioctl_fs_info_args fi_args; - struct btrfs_ioctl_dev_info_args dev_info; - struct device_info *info; - - *device_info_count = 0; - *device_info_ptr = 0; - - ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); - e = errno; - if (e == EPERM) - return -e; - if (ret < 0) { - fprintf(stderr, "ERROR: cannot get filesystem info - %s\n", - strerror(e)); - return 1; - } - - 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) - continue; - if (ret) { - fprintf(stderr, - "ERROR: cannot get info about device devid=%d\n", - i); - free(info); - return ret; - } - - info[ndevs].devid = dev_info.devid; - if (!dev_info.path[0]) { - strcpy(info[ndevs].path, "missing"); - } else { - 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_bytes; - ++ndevs; - } - - BUG_ON(ndevs != fi_args.num_devices); - qsort(info, fi_args.num_devices, - sizeof(struct device_info), cmp_device_info); - - *device_info_count = fi_args.num_devices; - *device_info_ptr = info; - - 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 - */ -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 usage" - * in tabular format - */ -static void _cmd_filesystem_usage_tabular(unsigned unit_mode, - struct btrfs_ioctl_space_args *sargs, - struct chunk_info *chunks_info_ptr, - int chunks_info_count, - struct device_info *device_info_ptr, - int device_info_count) -{ - int i; - u64 total_unused = 0; - struct string_table *matrix = 0; - int ncols, nrows; - - ncols = sargs->total_spaces + 2; - nrows = 2 + 1 + device_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; - - if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) - continue; - - description = btrfs_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 = btrfs_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 = device_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", pretty_size_mode(size, unit_mode)); - else - table_printf(matrix, col, i+3, ">-"); - - total_allocated += size; - col++; - } - - unused = get_partition_size(device_info_ptr[i].path) - - total_allocated; - - table_printf(matrix, sargs->total_spaces + 1, i + 3, - ">%s", pretty_size_mode(unused, unit_mode)); - total_unused += unused; - - } - - for (i = 0; i <= sargs->total_spaces; i++) - table_printf(matrix, i + 1, device_info_count + 3, "="); - - /* footer */ - table_printf(matrix, 0, device_info_count + 4, "total_spaces; i++) - table_printf(matrix, 1 + i, device_info_count + 4, ">%s", - pretty_size_mode(sargs->spaces[i].total_bytes, unit_mode)); - - table_printf(matrix, sargs->total_spaces + 1, device_info_count + 4, - ">%s", pretty_size_mode(total_unused, unit_mode)); - - table_printf(matrix, 0, device_info_count + 5, "total_spaces; i++) - table_printf(matrix, 1 + i, device_info_count+5, ">%s", - pretty_size_mode(sargs->spaces[i].used_bytes, unit_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 device_info *device_info_ptr, - int device_info_count, - unsigned unit_mode) -{ - int 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 == device_info_ptr[i].devid) - total += calc_chunk_size(info_ptr+j); - - printf(" %s\t%10s\n", - device_info_ptr[i].path, - pretty_size_mode(device_info_ptr[i].size - total, - unit_mode)); - } -} - -/* - * This function prints the allocated chunk per every disk - */ -static void print_chunk_device(u64 chunk_type, - struct chunk_info *chunks_info_ptr, - int chunks_info_count, - struct device_info *device_info_ptr, - int device_info_count, - unsigned unit_mode) -{ - int i; - - for (i = 0; i < device_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 != device_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", - device_info_ptr[i].path, - pretty_size_mode(total, unit_mode)); - } -} - -/* - * This function print the results of the command "btrfs fi usage" - * in linear format - */ -static void _cmd_filesystem_usage_linear(unsigned unit_mode, - struct btrfs_ioctl_space_args *sargs, - struct chunk_info *info_ptr, - int info_count, - struct device_info *device_info_ptr, - int device_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; - - if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) - continue; - - description = btrfs_group_type_str(flags); - r_mode = btrfs_group_profile_str(flags); - - printf("%s,%s: Size:%s, ", - description, - r_mode, - pretty_size_mode(sargs->spaces[i].total_bytes, - unit_mode)); - printf("Used:%s\n", - pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode)); - print_chunk_device(flags, info_ptr, info_count, - device_info_ptr, device_info_count, unit_mode); - printf("\n"); - } - - printf("Unallocated:\n"); - print_unused(info_ptr, info_count, device_info_ptr, device_info_count, - unit_mode); -} - -static int print_filesystem_usage_by_chunk(int fd, - struct chunk_info *chunkinfo, int chunkcount, - struct device_info *devinfo, int devcount, - char *path, unsigned unit_mode, int tabular) -{ - struct btrfs_ioctl_space_args *sargs; - int ret = 0; - - if (!chunkinfo) - return 0; - - sargs = load_space_info(fd, path); - if (!sargs) { - ret = 1; - goto out; - } - - if (tabular) - _cmd_filesystem_usage_tabular(unit_mode, sargs, chunkinfo, - chunkcount, devinfo, devcount); - else - _cmd_filesystem_usage_linear(unit_mode, sargs, chunkinfo, - chunkcount, devinfo, devcount); - - free(sargs); -out: - return ret; -} - -const char * const cmd_filesystem_usage_usage[] = { - "btrfs filesystem usage [options] [..]", - "Show detailed information about internal filesystem usage .", - "-b|--raw raw numbers in bytes", - "-h|--human-readable", - " human friendly numbers, base 1024 (default)", - "-H human friendly numbers, base 1000", - "--iec use 1024 as a base (KiB, MiB, GiB, TiB)", - "--si use 1000 as a base (kB, MB, GB, TB)", - "-k|--kbytes show sizes in KiB, or kB with --si", - "-m|--mbytes show sizes in MiB, or MB with --si", - "-g|--gbytes show sizes in GiB, or GB with --si", - "-t|--tbytes show sizes in TiB, or TB with --si", - "-T show data in tabular format", - NULL -}; - -int cmd_filesystem_usage(int argc, char **argv) -{ - unsigned unit_mode = UNITS_DEFAULT; - int ret = 0; - int i, more_than_one = 0; - int tabular = 0; - - optind = 1; - while (1) { - int long_index; - static const struct option long_options[] = { - { "raw", no_argument, NULL, 'b'}, - { "kbytes", no_argument, NULL, 'k'}, - { "mbytes", no_argument, NULL, 'm'}, - { "gbytes", no_argument, NULL, 'g'}, - { "tbytes", no_argument, NULL, 't'}, - { "si", no_argument, NULL, GETOPT_VAL_SI}, - { "iec", no_argument, NULL, GETOPT_VAL_IEC}, - { "human-readable", no_argument, NULL, - GETOPT_VAL_HUMAN_READABLE}, - { NULL, 0, NULL, 0 } - }; - int c = getopt_long(argc, argv, "bhHkmgtT", long_options, - &long_index); - - if (c < 0) - break; - switch (c) { - case 'b': - unit_mode = UNITS_RAW; - break; - case 'k': - units_set_base(&unit_mode, UNITS_KBYTES); - break; - case 'm': - units_set_base(&unit_mode, UNITS_MBYTES); - break; - case 'g': - units_set_base(&unit_mode, UNITS_GBYTES); - break; - case 't': - units_set_base(&unit_mode, UNITS_TBYTES); - break; - case GETOPT_VAL_HUMAN_READABLE: - case 'h': - unit_mode = UNITS_HUMAN_BINARY; - break; - case 'H': - unit_mode = UNITS_HUMAN_DECIMAL; - break; - case GETOPT_VAL_SI: - units_set_mode(&unit_mode, UNITS_DECIMAL); - break; - case GETOPT_VAL_IEC: - units_set_mode(&unit_mode, UNITS_BINARY); - break; - case 'T': - tabular = 1; - break; - default: - usage(cmd_filesystem_usage_usage); - } - } - - if (check_argc_min(argc - optind, 1)) - usage(cmd_filesystem_usage_usage); - - for (i = optind; i < argc; i++) { - 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) { - fprintf(stderr, "ERROR: can't access '%s'\n", - argv[i]); - ret = 1; - goto out; - } - if (more_than_one) - printf("\n"); - - 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], unit_mode); - if (ret) - goto cleanup; - printf("\n"); - ret = print_filesystem_usage_by_chunk(fd, chunkinfo, chunkcount, - devinfo, devcount, argv[i], unit_mode, tabular); -cleanup: - close_file_or_dir(fd, dirstream); - free(chunkinfo); - free(devinfo); - - if (ret) - goto out; - more_than_one = 1; - } - -out: - return !!ret; -} - -void print_device_chunks(int fd, struct device_info *devinfo, - struct chunk_info *chunks_info_ptr, - int chunks_info_count, unsigned unit_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 != devinfo->devid) - continue; - - flags = chunks_info_ptr[i].type; - - description = btrfs_group_type_str(flags); - r_mode = btrfs_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)), "", - pretty_size_mode(size, unit_mode)); - - allocated += size; - - } - printf(" Unallocated: %*s%10s\n", - (int)(20 - strlen("Unallocated")), "", - pretty_size_mode(devinfo->size - allocated, unit_mode)); -} - -void print_device_sizes(int fd, struct device_info *devinfo, unsigned unit_mode) -{ - printf(" Device size: %*s%10s\n", - (int)(20 - strlen("Device size")), "", - pretty_size_mode(devinfo->device_size, unit_mode)); -#if 0 - /* - * The term has not seen an agreement and we don't want to change it - * once it's in non-development branches or even released. - */ - printf(" FS occupied: %*s%10s\n", - (int)(20 - strlen("FS occupied")), "", - pretty_size_mode(devinfo->size, unit_mode)); -#endif -} diff -Nru btrfs-tools-3.19.1/cmds-fi-disk_usage.h btrfs-tools-4.0/cmds-fi-disk_usage.h --- btrfs-tools-3.19.1/cmds-fi-disk_usage.h 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-fi-disk_usage.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/* - * 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_H__ -#define __CMDS_FI_DISK_USAGE_H__ - -extern const char * const cmd_filesystem_usage_usage[]; -int cmd_filesystem_usage(int argc, char **argv); - -struct device_info { - u64 devid; - char path[BTRFS_DEVICE_PATH_NAME_MAX]; - /* Size of the block device */ - u64 device_size; - /* Size that's occupied by the filesystem, can be changed via resize */ - 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_chunk_and_device_info(int fd, struct chunk_info **chunkinfo, - int *chunkcount, struct device_info **devinfo, int *devcount); -void print_device_chunks(int fd, struct device_info *devinfo, - struct chunk_info *chunks_info_ptr, - int chunks_info_count, unsigned unit_mode); -void print_device_sizes(int fd, struct device_info *devinfo, unsigned unit_mode); - -#endif diff -Nru btrfs-tools-3.19.1/cmds-filesystem.c btrfs-tools-4.0/cmds-filesystem.c --- btrfs-tools-3.19.1/cmds-filesystem.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-filesystem.c 2015-04-29 14:56:22.000000000 +0000 @@ -34,7 +34,7 @@ #include "utils.h" #include "volumes.h" #include "commands.h" -#include "cmds-fi-disk_usage.h" +#include "cmds-fi-usage.h" #include "list_sort.h" #include "disk-io.h" @@ -208,7 +208,7 @@ unsigned unit_mode = UNITS_DEFAULT; while (1) { - int long_index; + int c; static const struct option long_options[] = { { "raw", no_argument, NULL, 'b'}, { "kbytes", no_argument, NULL, 'k'}, @@ -221,8 +221,8 @@ GETOPT_VAL_HUMAN_READABLE}, { NULL, 0, NULL, 0 } }; - int c = getopt_long(argc, argv, "bhHkmgt", long_options, - &long_index); + + c = getopt_long(argc, argv, "bhHkmgt", long_options, NULL); if (c < 0) break; switch (c) { @@ -836,14 +836,14 @@ int found = 0; while (1) { - int long_index; + int c; static const struct option long_options[] = { { "all-devices", no_argument, NULL, 'd'}, { "mounted", no_argument, NULL, 'm'}, { NULL, 0, NULL, 0 } }; - int c = getopt_long(argc, argv, "dm", long_options, - &long_index); + + c = getopt_long(argc, argv, "dm", long_options, NULL); if (c < 0) break; switch (c) { @@ -1234,6 +1234,7 @@ int fd, res, len, e; char *amount, *path; DIR *dirstream = NULL; + struct stat st; if (check_argc_exact(argc, 3)) usage(cmd_resize_usage); @@ -1248,6 +1249,20 @@ return 1; } + res = stat(path, &st); + if (res < 0) { + fprintf(stderr, "ERROR: resize: cannot stat %s: %s\n", + path, strerror(errno)); + return 1; + } + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, + "ERROR: resize works on mounted filesystems and accepts only\n" + "directories as argument. Passing file containing a btrfs image\n" + "would resize the underlying filesystem instead of the image.\n"); + return 1; + } + fd = open_file_or_dir(path, &dirstream); if (fd < 0) { fprintf(stderr, "ERROR: can't access '%s'\n", path); @@ -1263,6 +1278,18 @@ fprintf(stderr, "ERROR: unable to resize '%s' - %s\n", path, strerror(e)); return 1; + } else if (res > 0) { + const char *err_str = btrfs_err_str(res); + + if (err_str) { + fprintf(stderr, "ERROR: btrfs error resizing '%s' - %s\n", + path, err_str); + } else { + fprintf(stderr, + "ERROR: btrfs error resizing '%s' - unknown btrfs_err_code %d\n", + path, res); + } + return 1; } return 0; } diff -Nru btrfs-tools-3.19.1/cmds-fi-usage.c btrfs-tools-4.0/cmds-fi-usage.c --- btrfs-tools-3.19.1/cmds-fi-usage.c 1970-01-01 00:00:00.000000000 +0000 +++ btrfs-tools-4.0/cmds-fi-usage.c 2015-04-29 14:56:22.000000000 +0000 @@ -0,0 +1,1036 @@ +/* + * 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 +#include + +#include "utils.h" +#include "kerncompat.h" +#include "ctree.h" +#include "string-table.h" +#include "cmds-fi-usage.h" +#include "commands.h" + +#include "version.h" + +/* + * 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) { + free(*info_ptr); + fprintf(stderr, "ERROR: not enough memory\n"); + return -ENOMEM; + } + + *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); +} + +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 (e == EPERM) + return -e; + + if (ret < 0) { + fprintf(stderr, + "ERROR: can't perform the search - %s\n", + strerror(e)); + return 1; + } + /* 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); + + ret = add_info_to_list(info_ptr, info_count, item); + if (ret) { + *info_ptr = 0; + return 1; + } + + 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 = calloc(1, 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 devices + * if a disk is added later. + */ +static void get_raid56_used(int fd, struct chunk_info *chunks, int chunkcount, + u64 *raid5_used, u64 *raid6_used) +{ + struct chunk_info *info_ptr = chunks; + *raid5_used = 0; + *raid6_used = 0; + + while (chunkcount-- > 0) { + if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID5) + (*raid5_used) += info_ptr->size / (info_ptr->num_stripes - 1); + if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID6) + (*raid6_used) += info_ptr->size / (info_ptr->num_stripes - 2); + info_ptr++; + } +} + +#define MIN_UNALOCATED_THRESH (16 * 1024 * 1024) +static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, + int chunkcount, struct device_info *devinfo, int devcount, + char *path, unsigned unit_mode) +{ + struct btrfs_ioctl_space_args *sargs = 0; + int i; + int ret = 0; + int width = 10; /* default 10 for human units */ + /* + * r_* prefix is for raw data + * l_* is for logical + */ + u64 r_total_size = 0; /* filesystem size, sum of device sizes */ + u64 r_total_chunks = 0; /* sum of chunks sizes on disk(s) */ + u64 r_total_used = 0; + u64 r_total_unused = 0; + u64 r_total_missing = 0; /* sum of missing devices size */ + u64 r_data_used = 0; + u64 r_data_chunks = 0; + u64 l_data_chunks = 0; + u64 r_metadata_used = 0; + u64 r_metadata_chunks = 0; + u64 l_metadata_chunks = 0; + u64 r_system_used = 0; + u64 r_system_chunks = 0; + double data_ratio; + double metadata_ratio; + /* logical */ + u64 raid5_used = 0; + u64 raid6_used = 0; + u64 l_global_reserve = 0; + u64 l_global_reserve_used = 0; + u64 free_estimated = 0; + u64 free_min = 0; + int max_data_ratio = 1; + + sargs = load_space_info(fd, path); + if (!sargs) { + ret = 1; + goto exit; + } + + r_total_size = 0; + for (i = 0; i < devcount; i++) { + r_total_size += devinfo[i].size; + if (!devinfo[i].device_size) + r_total_missing += devinfo[i].size; + } + + if (r_total_size == 0) { + fprintf(stderr, + "ERROR: couldn't get space info on '%s' - %s\n", + path, strerror(errno)); + + ret = 1; + goto exit; + } + get_raid56_used(fd, chunkinfo, chunkcount, &raid5_used, &raid6_used); + + for (i = 0; i < sargs->total_spaces; i++) { + int ratio; + 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; + + if (!ratio) + fprintf(stderr, "WARNING: RAID56 detected, not implemented\n"); + + if (ratio > max_data_ratio) + max_data_ratio = ratio; + + if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) { + l_global_reserve = sargs->spaces[i].total_bytes; + l_global_reserve_used = sargs->spaces[i].used_bytes; + } + if ((flags & (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA)) + == (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA)) { + fprintf(stderr, "WARNING: MIXED blockgroups not handled\n"); + } + + if (flags & BTRFS_BLOCK_GROUP_DATA) { + r_data_used += sargs->spaces[i].used_bytes * ratio; + r_data_chunks += sargs->spaces[i].total_bytes * ratio; + l_data_chunks += sargs->spaces[i].total_bytes; + } + if (flags & BTRFS_BLOCK_GROUP_METADATA) { + r_metadata_used += sargs->spaces[i].used_bytes * ratio; + r_metadata_chunks += sargs->spaces[i].total_bytes * ratio; + l_metadata_chunks += sargs->spaces[i].total_bytes; + } + if (flags & BTRFS_BLOCK_GROUP_SYSTEM) { + r_system_used += sargs->spaces[i].used_bytes * ratio; + r_system_chunks += sargs->spaces[i].total_bytes * ratio; + } + } + + r_total_chunks = r_data_chunks + r_metadata_chunks + r_system_chunks; + r_total_used = r_data_used + r_metadata_used + r_system_used; + r_total_unused = r_total_size - r_total_chunks; + + /* Raw / Logical = raid factor, >= 1 */ + data_ratio = (double)r_data_chunks / l_data_chunks; + metadata_ratio = (double)r_metadata_chunks / l_metadata_chunks; + +#if 0 + /* add the raid5/6 allocated space */ + total_chunks += raid5_used + raid6_used; +#endif + + /* + * We're able to fill at least DATA for the unused space + * + * With mixed raid levels, this gives a rough estimate but more + * accurate than just counting the logical free space + * (l_data_chunks - l_data_used) + * + * In non-mixed case there's no difference. + */ + free_estimated = (r_data_chunks - r_data_used) / data_ratio; + free_min = free_estimated; + + /* Chop unallocatable space */ + /* FIXME: must be applied per device */ + if (r_total_unused >= MIN_UNALOCATED_THRESH) { + free_estimated += r_total_unused / data_ratio; + /* Match the calculation of 'df', use the highest raid ratio */ + free_min += r_total_unused / max_data_ratio; + } + + if (unit_mode != UNITS_HUMAN) + width = 18; + + printf("Overall:\n"); + + printf(" Device size:\t\t%*s\n", width, + pretty_size_mode(r_total_size, unit_mode)); + printf(" Device allocated:\t\t%*s\n", width, + pretty_size_mode(r_total_chunks, unit_mode)); + printf(" Device unallocated:\t\t%*s\n", width, + pretty_size_mode(r_total_unused, unit_mode)); + printf(" Device missing:\t\t%*s\n", width, + pretty_size_mode(r_total_missing, unit_mode)); + printf(" Used:\t\t\t%*s\n", width, + pretty_size_mode(r_total_used, unit_mode)); + printf(" Free (estimated):\t\t%*s\t(", + width, + pretty_size_mode(free_estimated, unit_mode)); + printf("min: %s)\n", pretty_size_mode(free_min, unit_mode)); + printf(" Data ratio:\t\t\t%*.2f\n", + width, data_ratio); + printf(" Metadata ratio:\t\t%*.2f\n", + width, metadata_ratio); + printf(" Global reserve:\t\t%*s\t(used: %s)\n", width, + pretty_size_mode(l_global_reserve, unit_mode), + pretty_size_mode(l_global_reserve_used, unit_mode)); + +exit: + + if (sargs) + free(sargs); + + return ret; +} + +/* + * Helper to sort the device_info structure + */ +static int cmp_device_info(const void *a, const void *b) +{ + return strcmp(((struct device_info *)a)->path, + ((struct device_info *)b)->path); +} + +/* + * This function loads the device_info structure and put them in an array + */ +static int load_device_info(int fd, struct device_info **device_info_ptr, + int *device_info_count) +{ + int ret, i, ndevs, e; + struct btrfs_ioctl_fs_info_args fi_args; + struct btrfs_ioctl_dev_info_args dev_info; + struct device_info *info; + + *device_info_count = 0; + *device_info_ptr = 0; + + ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); + e = errno; + if (e == EPERM) + return -e; + if (ret < 0) { + fprintf(stderr, "ERROR: cannot get filesystem info - %s\n", + strerror(e)); + return 1; + } + + 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) + continue; + if (ret) { + fprintf(stderr, + "ERROR: cannot get info about device devid=%d\n", + i); + free(info); + return ret; + } + + info[ndevs].devid = dev_info.devid; + if (!dev_info.path[0]) { + strcpy(info[ndevs].path, "missing"); + } else { + 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_bytes; + ++ndevs; + } + + BUG_ON(ndevs != fi_args.num_devices); + qsort(info, fi_args.num_devices, + sizeof(struct device_info), cmp_device_info); + + *device_info_count = fi_args.num_devices; + *device_info_ptr = info; + + 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 + */ +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 usage" + * in tabular format + */ +static void _cmd_filesystem_usage_tabular(unsigned unit_mode, + struct btrfs_ioctl_space_args *sargs, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, + struct device_info *device_info_ptr, + int device_info_count) +{ + int i; + u64 total_unused = 0; + struct string_table *matrix = 0; + int ncols, nrows; + + ncols = sargs->total_spaces + 2; + nrows = 2 + 1 + device_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; + + if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) + continue; + + description = btrfs_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 = btrfs_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 = device_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", pretty_size_mode(size, unit_mode)); + else + table_printf(matrix, col, i+3, ">-"); + + total_allocated += size; + col++; + } + + unused = get_partition_size(device_info_ptr[i].path) + - total_allocated; + + table_printf(matrix, sargs->total_spaces + 1, i + 3, + ">%s", pretty_size_mode(unused, unit_mode)); + total_unused += unused; + + } + + for (i = 0; i <= sargs->total_spaces; i++) + table_printf(matrix, i + 1, device_info_count + 3, "="); + + /* footer */ + table_printf(matrix, 0, device_info_count + 4, "total_spaces; i++) + table_printf(matrix, 1 + i, device_info_count + 4, ">%s", + pretty_size_mode(sargs->spaces[i].total_bytes, unit_mode)); + + table_printf(matrix, sargs->total_spaces + 1, device_info_count + 4, + ">%s", pretty_size_mode(total_unused, unit_mode)); + + table_printf(matrix, 0, device_info_count + 5, "total_spaces; i++) + table_printf(matrix, 1 + i, device_info_count+5, ">%s", + pretty_size_mode(sargs->spaces[i].used_bytes, unit_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 device_info *device_info_ptr, + int device_info_count, + unsigned unit_mode) +{ + int 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 == device_info_ptr[i].devid) + total += calc_chunk_size(info_ptr+j); + + printf(" %s\t%10s\n", + device_info_ptr[i].path, + pretty_size_mode(device_info_ptr[i].size - total, + unit_mode)); + } +} + +/* + * This function prints the allocated chunk per every disk + */ +static void print_chunk_device(u64 chunk_type, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, + struct device_info *device_info_ptr, + int device_info_count, + unsigned unit_mode) +{ + int i; + + for (i = 0; i < device_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 != device_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", + device_info_ptr[i].path, + pretty_size_mode(total, unit_mode)); + } +} + +/* + * This function print the results of the command "btrfs fi usage" + * in linear format + */ +static void _cmd_filesystem_usage_linear(unsigned unit_mode, + struct btrfs_ioctl_space_args *sargs, + struct chunk_info *info_ptr, + int info_count, + struct device_info *device_info_ptr, + int device_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; + + if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) + continue; + + description = btrfs_group_type_str(flags); + r_mode = btrfs_group_profile_str(flags); + + printf("%s,%s: Size:%s, ", + description, + r_mode, + pretty_size_mode(sargs->spaces[i].total_bytes, + unit_mode)); + printf("Used:%s\n", + pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode)); + print_chunk_device(flags, info_ptr, info_count, + device_info_ptr, device_info_count, unit_mode); + printf("\n"); + } + + printf("Unallocated:\n"); + print_unused(info_ptr, info_count, device_info_ptr, device_info_count, + unit_mode); +} + +static int print_filesystem_usage_by_chunk(int fd, + struct chunk_info *chunkinfo, int chunkcount, + struct device_info *devinfo, int devcount, + char *path, unsigned unit_mode, int tabular) +{ + struct btrfs_ioctl_space_args *sargs; + int ret = 0; + + if (!chunkinfo) + return 0; + + sargs = load_space_info(fd, path); + if (!sargs) { + ret = 1; + goto out; + } + + if (tabular) + _cmd_filesystem_usage_tabular(unit_mode, sargs, chunkinfo, + chunkcount, devinfo, devcount); + else + _cmd_filesystem_usage_linear(unit_mode, sargs, chunkinfo, + chunkcount, devinfo, devcount); + + free(sargs); +out: + return ret; +} + +const char * const cmd_filesystem_usage_usage[] = { + "btrfs filesystem usage [options] [..]", + "Show detailed information about internal filesystem usage .", + "-b|--raw raw numbers in bytes", + "-h|--human-readable", + " human friendly numbers, base 1024 (default)", + "-H human friendly numbers, base 1000", + "--iec use 1024 as a base (KiB, MiB, GiB, TiB)", + "--si use 1000 as a base (kB, MB, GB, TB)", + "-k|--kbytes show sizes in KiB, or kB with --si", + "-m|--mbytes show sizes in MiB, or MB with --si", + "-g|--gbytes show sizes in GiB, or GB with --si", + "-t|--tbytes show sizes in TiB, or TB with --si", + "-T show data in tabular format", + NULL +}; + +int cmd_filesystem_usage(int argc, char **argv) +{ + unsigned unit_mode = UNITS_DEFAULT; + int ret = 0; + int i, more_than_one = 0; + int tabular = 0; + + optind = 1; + while (1) { + int c; + static const struct option long_options[] = { + { "raw", no_argument, NULL, 'b'}, + { "kbytes", no_argument, NULL, 'k'}, + { "mbytes", no_argument, NULL, 'm'}, + { "gbytes", no_argument, NULL, 'g'}, + { "tbytes", no_argument, NULL, 't'}, + { "si", no_argument, NULL, GETOPT_VAL_SI}, + { "iec", no_argument, NULL, GETOPT_VAL_IEC}, + { "human-readable", no_argument, NULL, + GETOPT_VAL_HUMAN_READABLE}, + { NULL, 0, NULL, 0 } + }; + + c = getopt_long(argc, argv, "bhHkmgtT", long_options, NULL); + + if (c < 0) + break; + switch (c) { + case 'b': + unit_mode = UNITS_RAW; + break; + case 'k': + units_set_base(&unit_mode, UNITS_KBYTES); + break; + case 'm': + units_set_base(&unit_mode, UNITS_MBYTES); + break; + case 'g': + units_set_base(&unit_mode, UNITS_GBYTES); + break; + case 't': + units_set_base(&unit_mode, UNITS_TBYTES); + break; + case GETOPT_VAL_HUMAN_READABLE: + case 'h': + unit_mode = UNITS_HUMAN_BINARY; + break; + case 'H': + unit_mode = UNITS_HUMAN_DECIMAL; + break; + case GETOPT_VAL_SI: + units_set_mode(&unit_mode, UNITS_DECIMAL); + break; + case GETOPT_VAL_IEC: + units_set_mode(&unit_mode, UNITS_BINARY); + break; + case 'T': + tabular = 1; + break; + default: + usage(cmd_filesystem_usage_usage); + } + } + + if (check_argc_min(argc - optind, 1)) + usage(cmd_filesystem_usage_usage); + + for (i = optind; i < argc; i++) { + 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) { + fprintf(stderr, "ERROR: can't access '%s'\n", + argv[i]); + ret = 1; + goto out; + } + if (more_than_one) + printf("\n"); + + 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], unit_mode); + if (ret) + goto cleanup; + printf("\n"); + ret = print_filesystem_usage_by_chunk(fd, chunkinfo, chunkcount, + devinfo, devcount, argv[i], unit_mode, tabular); +cleanup: + close_file_or_dir(fd, dirstream); + free(chunkinfo); + free(devinfo); + + if (ret) + goto out; + more_than_one = 1; + } + +out: + return !!ret; +} + +void print_device_chunks(int fd, struct device_info *devinfo, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, unsigned unit_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 != devinfo->devid) + continue; + + flags = chunks_info_ptr[i].type; + + description = btrfs_group_type_str(flags); + r_mode = btrfs_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)), "", + pretty_size_mode(size, unit_mode)); + + allocated += size; + + } + printf(" Unallocated: %*s%10s\n", + (int)(20 - strlen("Unallocated")), "", + pretty_size_mode(devinfo->size - allocated, unit_mode)); +} + +void print_device_sizes(int fd, struct device_info *devinfo, unsigned unit_mode) +{ + printf(" Device size: %*s%10s\n", + (int)(20 - strlen("Device size")), "", + pretty_size_mode(devinfo->device_size, unit_mode)); +#if 0 + /* + * The term has not seen an agreement and we don't want to change it + * once it's in non-development branches or even released. + */ + printf(" FS occupied: %*s%10s\n", + (int)(20 - strlen("FS occupied")), "", + pretty_size_mode(devinfo->size, unit_mode)); +#endif +} diff -Nru btrfs-tools-3.19.1/cmds-fi-usage.h btrfs-tools-4.0/cmds-fi-usage.h --- btrfs-tools-3.19.1/cmds-fi-usage.h 1970-01-01 00:00:00.000000000 +0000 +++ btrfs-tools-4.0/cmds-fi-usage.h 2015-04-29 14:56:22.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * 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_USAGE_H__ +#define __CMDS_FI_USAGE_H__ + +extern const char * const cmd_filesystem_usage_usage[]; +int cmd_filesystem_usage(int argc, char **argv); + +struct device_info { + u64 devid; + char path[BTRFS_DEVICE_PATH_NAME_MAX]; + /* Size of the block device */ + u64 device_size; + /* Size that's occupied by the filesystem, can be changed via resize */ + 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_chunk_and_device_info(int fd, struct chunk_info **chunkinfo, + int *chunkcount, struct device_info **devinfo, int *devcount); +void print_device_chunks(int fd, struct device_info *devinfo, + struct chunk_info *chunks_info_ptr, + int chunks_info_count, unsigned unit_mode); +void print_device_sizes(int fd, struct device_info *devinfo, unsigned unit_mode); + +#endif diff -Nru btrfs-tools-3.19.1/cmds-qgroup.c btrfs-tools-4.0/cmds-qgroup.c --- btrfs-tools-3.19.1/cmds-qgroup.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-qgroup.c 2015-04-29 14:56:22.000000000 +0000 @@ -251,9 +251,8 @@ optind = 1; while (1) { int c; - int option_index = 0; static const struct option long_options[] = { - {"sort", 1, NULL, 'S'}, + {"sort", required_argument, NULL, 'S'}, {"raw", no_argument, NULL, GETOPT_VAL_RAW}, {"kbytes", no_argument, NULL, GETOPT_VAL_KBYTES}, {"mbytes", no_argument, NULL, GETOPT_VAL_MBYTES}, @@ -265,9 +264,8 @@ GETOPT_VAL_HUMAN_READABLE}, { NULL, 0, NULL, 0 } }; - c = getopt_long(argc, argv, "pcreFf", - long_options, &option_index); + c = getopt_long(argc, argv, "pcreFf", long_options, NULL); if (c < 0) break; switch (c) { diff -Nru btrfs-tools-3.19.1/cmds-quota.c btrfs-tools-4.0/cmds-quota.c --- btrfs-tools-3.19.1/cmds-quota.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-quota.c 2015-04-29 14:56:22.000000000 +0000 @@ -109,7 +109,7 @@ int e; char *path = NULL; struct btrfs_ioctl_quota_rescan_args args; - int ioctlnum = BTRFS_IOC_QUOTA_RESCAN; + unsigned long ioctlnum = BTRFS_IOC_QUOTA_RESCAN; DIR *dirstream = NULL; int wait_for_completion = 0; diff -Nru btrfs-tools-3.19.1/cmds-receive.c btrfs-tools-4.0/cmds-receive.c --- btrfs-tools-3.19.1/cmds-receive.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-receive.c 2015-04-29 14:56:22.000000000 +0000 @@ -61,6 +61,7 @@ char *root_path; char *dest_dir_path; /* relative to root_path */ char *full_subvol_path; + int dest_dir_chroot; struct subvol_info *cur_subvol; @@ -858,14 +859,35 @@ goto out; } - /* - * find_mount_root returns a root_path that is a subpath of - * dest_dir_full_path. Now get the other part of root_path, - * which is the destination dir relative to root_path. - */ - r->dest_dir_path = dest_dir_full_path + strlen(r->root_path); - while (r->dest_dir_path[0] == '/') - r->dest_dir_path++; + if (r->dest_dir_chroot) { + if (chroot(dest_dir_full_path)) { + ret = -errno; + fprintf(stderr, + "ERROR: failed to chroot to %s, %s\n", + dest_dir_full_path, + strerror(-ret)); + goto out; + } + if (chdir("/")) { + ret = -errno; + fprintf(stderr, + "ERROR: failed to chdir to /, %s\n", + strerror(-ret)); + goto out; + } + fprintf(stderr, "Chroot to %s\n", dest_dir_full_path); + r->root_path = strdup("/"); + r->dest_dir_path = r->root_path; + } else { + /* + * find_mount_root returns a root_path that is a subpath of + * dest_dir_full_path. Now get the other part of root_path, + * which is the destination dir relative to root_path. + */ + r->dest_dir_path = dest_dir_full_path + strlen(r->root_path); + while (r->dest_dir_path[0] == '/') + r->dest_dir_path++; + } ret = subvol_uuid_search_init(r->mnt_fd, &r->sus); if (ret < 0) @@ -930,15 +952,17 @@ r.mnt_fd = -1; r.write_fd = -1; r.dest_dir_fd = -1; + r.dest_dir_chroot = 0; while (1) { int c; static const struct option long_opts[] = { - { "max-errors", 1, NULL, 'E' }, + { "max-errors", required_argument, NULL, 'E' }, + { "chroot", no_argument, NULL, 'C' }, { NULL, 0, NULL, 0 } }; - c = getopt_long(argc, argv, "evf:", long_opts, NULL); + c = getopt_long(argc, argv, "Cevf:", long_opts, NULL); if (c < 0) break; @@ -952,6 +976,9 @@ case 'e': r.honor_end_cmd = 1; break; + case 'C': + r.dest_dir_chroot = 1; + break; case 'E': max_errors = arg_strtou64(optarg); break; @@ -1001,6 +1028,7 @@ " in the data stream. Without this option,", " the receiver terminates only if an error", " is recognized or on EOF.", + "-C|--chroot confine the process to using chroot", "--max-errors Terminate as soon as N errors happened while", " processing commands from the send stream.", " Default value is 1. A value of 0 means no limit.", diff -Nru btrfs-tools-3.19.1/cmds-rescue.c btrfs-tools-4.0/cmds-rescue.c --- btrfs-tools-3.19.1/cmds-rescue.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-rescue.c 2015-04-29 14:56:22.000000000 +0000 @@ -19,6 +19,9 @@ #include "kerncompat.h" #include +#include "ctree.h" +#include "transaction.h" +#include "disk-io.h" #include "commands.h" #include "utils.h" @@ -149,11 +152,61 @@ return ret; } +const char * const cmd_rescue_zero_log_usage[] = { + "btrfs rescue zero-log ", + "Clear the tree log. Usable if it's corrupted and prevents mount.", + "", + NULL +}; + +int cmd_rescue_zero_log(int argc, char **argv) +{ + struct btrfs_root *root; + struct btrfs_trans_handle *trans; + struct btrfs_super_block *sb; + char *devname; + int ret; + + if (check_argc_exact(argc, 2)) + usage(cmd_rescue_zero_log_usage); + + devname = argv[optind]; + ret = check_mounted(devname); + if (ret < 0) { + fprintf(stderr, "Could not check mount status: %s\n", strerror(-ret)); + goto out; + } else if (ret) { + fprintf(stderr, "%s is currently mounted. Aborting.\n", devname); + ret = -EBUSY; + } + + root = open_ctree(devname, 0, OPEN_CTREE_WRITES | OPEN_CTREE_PARTIAL); + if (!root) { + fprintf(stderr, "Could not open ctree\n"); + return 1; + } + + sb = root->fs_info->super_copy; + printf("Clearing log on %s, previous log_root %llu, level %u\n", + devname, + (unsigned long long)btrfs_super_log_root(sb), + (unsigned)btrfs_super_log_root_level(sb)); + trans = btrfs_start_transaction(root, 1); + btrfs_set_super_log_root(sb, 0); + btrfs_set_super_log_root_level(sb, 0); + btrfs_commit_transaction(trans, root); + close_ctree(root); + +out: + return !!ret; +} + const struct cmd_group rescue_cmd_group = { rescue_cmd_group_usage, NULL, { { "chunk-recover", cmd_chunk_recover, cmd_chunk_recover_usage, NULL, 0}, { "super-recover", cmd_super_recover, cmd_super_recover_usage, NULL, 0}, - { 0, 0, 0, 0, 0 } + { "zero-log", cmd_rescue_zero_log, cmd_rescue_zero_log_usage, NULL, 0}, + NULL_CMD_STRUCT } }; diff -Nru btrfs-tools-3.19.1/cmds-restore.c btrfs-tools-4.0/cmds-restore.c --- btrfs-tools-3.19.1/cmds-restore.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-restore.c 2015-04-29 14:56:22.000000000 +0000 @@ -43,10 +43,11 @@ #include "utils.h" #include "commands.h" -static char fs_name[4096]; -static char path_name[4096]; +static char fs_name[PATH_MAX]; +static char path_name[PATH_MAX]; static int get_snaps = 0; static int verbose = 0; +static int restore_metadata = 0; static int ignore_errors = 0; static int overwrite = 0; static int get_xattrs = 0; @@ -559,6 +560,61 @@ return ret; } +static int copy_metadata(struct btrfs_root *root, int fd, + struct btrfs_key *key) +{ + struct btrfs_path *path; + struct btrfs_inode_item *inode_item; + int ret; + + path = btrfs_alloc_path(); + if (!path) { + fprintf(stderr, "ERROR: Ran out of memory\n"); + return -ENOMEM; + } + + ret = btrfs_lookup_inode(NULL, root, path, key, 0); + if (ret == 0) { + struct btrfs_timespec *bts; + struct timespec times[2]; + + inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_inode_item); + + ret = fchown(fd, btrfs_inode_uid(path->nodes[0], inode_item), + btrfs_inode_gid(path->nodes[0], inode_item)); + if (ret) { + fprintf(stderr, "ERROR: Failed to change owner: %s\n", + strerror(errno)); + goto out; + } + + ret = fchmod(fd, btrfs_inode_mode(path->nodes[0], inode_item)); + if (ret) { + fprintf(stderr, "ERROR: Failed to change mode: %s\n", + strerror(errno)); + goto out; + } + + bts = btrfs_inode_atime(inode_item); + times[0].tv_sec = btrfs_timespec_sec(path->nodes[0], bts); + times[0].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts); + + bts = btrfs_inode_mtime(inode_item); + times[1].tv_sec = btrfs_timespec_sec(path->nodes[0], bts); + times[1].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts); + + ret = futimens(fd, times); + if (ret) { + fprintf(stderr, "ERROR: Failed to set times: %s\n", + strerror(errno)); + goto out; + } + } +out: + btrfs_free_path(path); + return ret; +} static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key, const char *file) @@ -567,12 +623,15 @@ struct btrfs_path *path; struct btrfs_file_extent_item *fi; struct btrfs_inode_item *inode_item; + struct btrfs_timespec *bts; struct btrfs_key found_key; int ret; int extent_type; int compression; int loops = 0; u64 found_size = 0; + struct timespec times[2]; + int times_ok = 0; path = btrfs_alloc_path(); if (!path) { @@ -585,6 +644,31 @@ inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); found_size = btrfs_inode_size(path->nodes[0], inode_item); + + if (restore_metadata) { + /* + * Change the ownership and mode now, set times when + * copyout is finished. + */ + + ret = fchown(fd, btrfs_inode_uid(path->nodes[0], inode_item), + btrfs_inode_gid(path->nodes[0], inode_item)); + if (ret && !ignore_errors) + goto out; + + ret = fchmod(fd, btrfs_inode_mode(path->nodes[0], inode_item)); + if (ret && !ignore_errors) + goto out; + + bts = btrfs_inode_atime(inode_item); + times[0].tv_sec = btrfs_timespec_sec(path->nodes[0], bts); + times[0].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts); + + bts = btrfs_inode_mtime(inode_item); + times[1].tv_sec = btrfs_timespec_sec(path->nodes[0], bts); + times[1].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts); + times_ok = 1; + } } btrfs_release_path(path); @@ -594,8 +678,7 @@ ret = btrfs_search_slot(NULL, root, key, path, 0, 0); if (ret < 0) { fprintf(stderr, "Error searching %d\n", ret); - btrfs_free_path(path); - return ret; + goto out; } leaf = path->nodes[0]; @@ -604,12 +687,11 @@ if (ret < 0) { fprintf(stderr, "Error getting next leaf %d\n", ret); - btrfs_free_path(path); - return ret; + goto out; } else if (ret > 0) { /* No more leaves to search */ - btrfs_free_path(path); - return 0; + ret = 0; + goto out; } leaf = path->nodes[0]; } @@ -631,8 +713,7 @@ ret = next_leaf(root, path); if (ret < 0) { fprintf(stderr, "Error searching %d\n", ret); - btrfs_free_path(path); - return ret; + goto out; } else if (ret) { /* No more leaves to search */ btrfs_free_path(path); @@ -654,25 +735,21 @@ if (compression >= BTRFS_COMPRESS_LAST) { fprintf(stderr, "Don't support compression yet %d\n", compression); - btrfs_free_path(path); - return -1; + ret = -1; + goto out; } if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) goto next; if (extent_type == BTRFS_FILE_EXTENT_INLINE) { ret = copy_one_inline(fd, path, found_key.offset); - if (ret) { - btrfs_free_path(path); - return -1; - } + if (ret) + goto out; } else if (extent_type == BTRFS_FILE_EXTENT_REG) { ret = copy_one_extent(root, fd, leaf, fi, found_key.offset); - if (ret) { - btrfs_free_path(path); - return ret; - } + if (ret) + goto out; } else { printf("Weird extent type %d\n", extent_type); } @@ -692,7 +769,16 @@ if (ret) return ret; } + if (restore_metadata && times_ok) { + ret = futimens(fd, times); + if (ret) + return ret; + } return 0; + +out: + btrfs_free_path(path); + return ret; } static int search_dir(struct btrfs_root *root, struct btrfs_key *key, @@ -706,7 +792,7 @@ char filename[BTRFS_NAME_LEN + 1]; unsigned long name_ptr; int name_len; - int ret; + int ret = 0; int fd; int loops = 0; u8 type; @@ -723,10 +809,11 @@ ret = btrfs_search_slot(NULL, root, key, path, 0, 0); if (ret < 0) { fprintf(stderr, "Error searching %d\n", ret); - btrfs_free_path(path); - return ret; + goto out; } + ret = 0; + leaf = path->nodes[0]; while (!leaf) { if (verbose > 1) @@ -736,15 +823,14 @@ if (ret < 0) { fprintf(stderr, "Error getting next leaf %d\n", ret); - btrfs_free_path(path); - return ret; + goto out; } else if (ret > 0) { /* No more leaves to search */ if (verbose) printf("Reached the end of the tree looking " "for the directory\n"); - btrfs_free_path(path); - return 0; + ret = 0; + goto out; } leaf = path->nodes[0]; } @@ -763,16 +849,15 @@ if (ret < 0) { fprintf(stderr, "Error searching %d\n", ret); - btrfs_free_path(path); - return ret; + goto out; } else if (ret > 0) { /* No more leaves to search */ if (verbose) printf("Reached the end of " "the tree searching the" " directory\n"); - btrfs_free_path(path); - return 0; + ret = 0; + goto out; } leaf = path->nodes[0]; } while (!leaf); @@ -801,13 +886,13 @@ btrfs_dir_item_key_to_cpu(leaf, dir_item, &location); /* full path from root of btrfs being restored */ - snprintf(fs_name, 4096, "%s/%s", in_dir, filename); + snprintf(fs_name, PATH_MAX, "%s/%s", in_dir, filename); if (mreg && REG_NOMATCH == regexec(mreg, fs_name, 0, NULL, 0)) goto next; /* full path from system root */ - snprintf(path_name, 4096, "%s%s", output_rootdir, fs_name); + snprintf(path_name, PATH_MAX, "%s%s", output_rootdir, fs_name); /* * At this point we're only going to restore directories and @@ -843,8 +928,8 @@ path_name, errno); if (ignore_errors) goto next; - btrfs_free_path(path); - return -1; + ret = -1; + goto out; } loops = 0; ret = copy_file(root, fd, &location, path_name); @@ -854,8 +939,7 @@ path_name); if (ignore_errors) goto next; - btrfs_free_path(path); - return ret; + goto out; } } else if (type == BTRFS_FT_DIR) { struct btrfs_root *search_root = root; @@ -863,8 +947,8 @@ if (!dir) { fprintf(stderr, "Ran out of memory\n"); - btrfs_free_path(path); - return -ENOMEM; + ret = -ENOMEM; + goto out; } if (location.type == BTRFS_ROOT_ITEM_KEY) { @@ -889,8 +973,8 @@ PTR_ERR(search_root)); if (ignore_errors) goto next; - btrfs_free_path(path); - return PTR_ERR(search_root); + ret = PTR_ERR(search_root); + goto out; } /* @@ -921,8 +1005,8 @@ path_name, errno); if (ignore_errors) goto next; - btrfs_free_path(path); - return -1; + ret = -1; + goto out; } loops = 0; ret = search_dir(search_root, &location, @@ -933,18 +1017,40 @@ path_name); if (ignore_errors) goto next; - btrfs_free_path(path); - return ret; + goto out; } } next: path->slots[0]++; } + if (restore_metadata) { + snprintf(path_name, PATH_MAX, "%s%s", output_rootdir, in_dir); + fd = open(path_name, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "ERROR: Failed to access %s to restore metadata\n", + path_name); + if (!ignore_errors) { + ret = -1; + goto out; + } + } else { + /* + * Set owner/mode/time on the directory as well + */ + key->type = BTRFS_INODE_ITEM_KEY; + ret = copy_metadata(root, fd, key); + close(fd); + if (ret && !ignore_errors) + goto out; + } + } + if (verbose) printf("Done searching %s\n", in_dir); +out: btrfs_free_path(path); - return 0; + return ret; } static int do_list_roots(struct btrfs_root *root) @@ -1138,6 +1244,7 @@ "", "-s get snapshots", "-x get extended attributes", + "-m|--metadata restore owner, mode and times", "-v verbose", "-i ignore errors", "-o overwrite", @@ -1152,7 +1259,7 @@ " restore only filenames matching regex,", " you have to use following syntax (possibly quoted):", " ^/(|home(|/username(|/Desktop(|/.*))))$", - "-c ignore case (--path-regrex only)", + "-c ignore case (--path-regex only)", NULL }; @@ -1176,15 +1283,15 @@ while (1) { int opt; - int option_index = 0; static const struct option long_options[] = { - { "path-regex", 1, NULL, 256}, - { "dry-run", 0, NULL, 'D'}, + { "path-regex", required_argument, NULL, 256}, + { "dry-run", no_argument, NULL, 'D'}, + { "metadata", no_argument, NULL, 'm'}, { NULL, 0, NULL, 0} }; - opt = getopt_long(argc, argv, "sxviot:u:df:r:lDc", long_options, - &option_index); + opt = getopt_long(argc, argv, "sxviot:u:dmf:r:lDc", long_options, + NULL); if (opt < 0) break; @@ -1229,6 +1336,9 @@ case 'l': list_roots = 1; break; + case 'm': + restore_metadata = 1; + break; case 'D': dry_run = 1; break; @@ -1283,7 +1393,7 @@ } } - memset(path_name, 0, 4096); + memset(path_name, 0, PATH_MAX); strncpy(dir_name, argv[optind + 1], sizeof dir_name); dir_name[sizeof dir_name - 1] = 0; diff -Nru btrfs-tools-3.19.1/cmds-subvolume.c btrfs-tools-4.0/cmds-subvolume.c --- btrfs-tools-3.19.1/cmds-subvolume.c 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/cmds-subvolume.c 2015-04-29 14:56:22.000000000 +0000 @@ -404,7 +404,7 @@ while(1) { int c; static const struct option long_options[] = { - {"sort", 1, NULL, 'S'}, + {"sort", required_argument, NULL, 'S'}, {NULL, 0, NULL, 0} }; diff -Nru btrfs-tools-3.19.1/configure btrfs-tools-4.0/configure --- btrfs-tools-3.19.1/configure 2015-03-25 17:44:13.000000000 +0000 +++ btrfs-tools-4.0/configure 2015-04-29 14:56:50.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for btrfs-progs v3.19.1. +# Generated by GNU Autoconf 2.69 for btrfs-progs v4.0. # # Report bugs to . # @@ -580,8 +580,8 @@ # Identity of this package. PACKAGE_NAME='btrfs-progs' PACKAGE_TARNAME='btrfs-progs' -PACKAGE_VERSION='v3.19.1' -PACKAGE_STRING='btrfs-progs v3.19.1' +PACKAGE_VERSION='v4.0' +PACKAGE_STRING='btrfs-progs v4.0' PACKAGE_BUGREPORT='linux-btrfs@vger.kernel.org' PACKAGE_URL='http://btrfs.wiki.kernel.org' @@ -1287,7 +1287,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures btrfs-progs v3.19.1 to adapt to many kinds of systems. +\`configure' configures btrfs-progs v4.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1352,7 +1352,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of btrfs-progs v3.19.1:";; + short | recursive ) echo "Configuration of btrfs-progs v4.0:";; esac cat <<\_ACEOF @@ -1461,7 +1461,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -btrfs-progs configure v3.19.1 +btrfs-progs configure v4.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1830,7 +1830,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by btrfs-progs $as_me v3.19.1, which was +It was created by btrfs-progs $as_me v4.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -6375,7 +6375,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by btrfs-progs $as_me v3.19.1, which was +This file was extended by btrfs-progs $as_me v4.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6438,7 +6438,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -btrfs-progs config.status v3.19.1 +btrfs-progs config.status v4.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -Nru btrfs-tools-3.19.1/ctree.h btrfs-tools-4.0/ctree.h --- btrfs-tools-3.19.1/ctree.h 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/ctree.h 2015-04-29 14:56:22.000000000 +0000 @@ -936,6 +936,7 @@ struct btrfs_block_group_item item; struct btrfs_space_info *space_info; struct btrfs_free_space_ctl *free_space_ctl; + u64 bytes_super; u64 pinned; u64 flags; int cached; diff -Nru btrfs-tools-3.19.1/debian/btrfs-tools.install btrfs-tools-4.0/debian/btrfs-tools.install --- btrfs-tools-3.19.1/debian/btrfs-tools.install 2014-10-23 21:00:58.000000000 +0000 +++ btrfs-tools-4.0/debian/btrfs-tools.install 2015-05-03 21:41:07.000000000 +0000 @@ -1,3 +1,3 @@ -btrfs-calc-size /sbin -btrfs-select-super /sbin -ioctl.h /usr/include/btrfs +btrfs-calc-size /bin +btrfs-select-super /bin +ioctl.h /usr/include/btrfs diff -Nru btrfs-tools-3.19.1/debian/btrfs-tools-udeb.install btrfs-tools-4.0/debian/btrfs-tools-udeb.install --- btrfs-tools-3.19.1/debian/btrfs-tools-udeb.install 2014-10-23 21:00:58.000000000 +0000 +++ btrfs-tools-4.0/debian/btrfs-tools-udeb.install 2015-05-03 21:41:07.000000000 +0000 @@ -1,2 +1,2 @@ -btrfs /sbin -mkfs.btrfs /sbin +btrfs /bin +mkfs.btrfs /bin diff -Nru btrfs-tools-3.19.1/debian/changelog btrfs-tools-4.0/debian/changelog --- btrfs-tools-3.19.1/debian/changelog 2015-04-03 08:49:12.000000000 +0000 +++ btrfs-tools-4.0/debian/changelog 2015-06-04 21:39:07.000000000 +0000 @@ -1,44 +1,26 @@ -btrfs-tools (3.19.1-0~ppa12.04+4) precise; urgency=medium +btrfs-tools (4.0-2~ppa12.04+1) precise; urgency=medium - * Remove override_dh_auto_build which seems not necessary and makes build failing. - - -- Nicolas Derive Fri, 03 Apr 2015 10:33:05 +0200 - -btrfs-tools (3.19.1-0~ppa15.04+3) vivid; urgency=medium - - * Add missing pkg-config build-dep. - - -- Nicolas Derive Thu, 02 Apr 2015 22:36:31 +0200 - -btrfs-tools (3.19.1-0~ppa15.04+2) vivid; urgency=medium - - * Add missing dh-autoreconf and autotools-dev build-deps. - - -- Nicolas Derive Thu, 02 Apr 2015 22:29:26 +0200 - -btrfs-tools (3.19.1-0~ppa15.04+1) vivid; urgency=medium - - * New upstream release - - -- Nicolas Derive Thu, 02 Apr 2015 22:13:13 +0200 - -btrfs-tools (3.18.2-0~ppa15.04+1) vivid; urgency=medium - - * New upstream release, remove upstreamed patch. + * Merge from Debian Unstable. - -- Nicolas Derive Sun, 01 Mar 2015 13:59:33 +0100 + -- Nicolas Derive Thu, 04 Jun 2015 23:38:02 +0200 -btrfs-tools (3.17.3-0~ppa15.04+1) vivid; urgency=medium +btrfs-tools (4.0-2) unstable; urgency=medium - * New upstream release, remove upstreamed patches. + * Adjust initramfs hooks and udev rules for move of all binaries to + /bin. (Closes: #784234) - -- Nicolas Derive Sun, 01 Mar 2015 13:14:56 +0100 + -- Dimitri John Ledkov Mon, 04 May 2015 18:51:07 +0100 -btrfs-tools (3.17-1.1~ppa14.10+1) utopic; urgency=medium +btrfs-tools (4.0-1) unstable; urgency=medium - * Merge from Debian Unstable. + * New upstream release. + * Drop all patches. + * Experiment with dropping udev rules, in favour of systemd-udev builtin + integration. (Closes: #772744) + * Move all binaries to /bin (Closes: #770806) + * Switch to autoconf based build system. - -- Nicolas Derive Fri, 20 Feb 2015 14:00:54 +0100 + -- Dimitri John Ledkov Sun, 18 Jan 2015 00:14:20 +0000 btrfs-tools (3.17-1.1) unstable; urgency=medium diff -Nru btrfs-tools-3.19.1/debian/control btrfs-tools-4.0/debian/control --- btrfs-tools-3.19.1/debian/control 2015-04-02 20:36:29.000000000 +0000 +++ btrfs-tools-4.0/debian/control 2015-05-03 22:17:15.000000000 +0000 @@ -3,10 +3,8 @@ Priority: optional Maintainer: Dimitri John Ledkov Build-Depends: debhelper (>= 9), - autotools-dev, - pkg-config, - dh-autoreconf, e2fslibs-dev, + pkg-config, libacl1-dev, libblkid-dev, liblzo2-dev, diff -Nru btrfs-tools-3.19.1/debian/.git-dpm btrfs-tools-4.0/debian/.git-dpm --- btrfs-tools-3.19.1/debian/.git-dpm 2014-10-23 21:00:58.000000000 +0000 +++ btrfs-tools-4.0/debian/.git-dpm 2015-05-03 21:41:07.000000000 +0000 @@ -1,8 +1,8 @@ # see git-dpm(1) from git-dpm package -7c125e55fd530ee01a9ddc88111f7e7d77360fed -7c125e55fd530ee01a9ddc88111f7e7d77360fed -7dbe85914fa3fc9149d6bbb2cc7e75ff8d02a4e9 -7dbe85914fa3fc9149d6bbb2cc7e75ff8d02a4e9 -btrfs-tools_3.17.orig.tar.xz -09bdb95277031e3206707db9c92da649d5fb4300 -370560 +5c1400222c18f1cabc9817c9dd2ea511cf9de8f6 +5c1400222c18f1cabc9817c9dd2ea511cf9de8f6 +5c1400222c18f1cabc9817c9dd2ea511cf9de8f6 +5c1400222c18f1cabc9817c9dd2ea511cf9de8f6 +btrfs-tools_4.0.orig.tar.xz +82866eaa7baccc984883457cedf45b52a437e348 +1102500 diff -Nru btrfs-tools-3.19.1/debian/local/btrfs.hook btrfs-tools-4.0/debian/local/btrfs.hook --- btrfs-tools-3.19.1/debian/local/btrfs.hook 2014-10-23 21:00:58.000000000 +0000 +++ btrfs-tools-4.0/debian/local/btrfs.hook 2015-05-04 17:47:46.000000000 +0000 @@ -18,12 +18,12 @@ . /usr/share/initramfs-tools/hook-functions -if [ -x /sbin/btrfs ] +if [ -x /bin/btrfs ] then - copy_exec /sbin/btrfs /sbin - copy_exec /sbin/btrfs-zero-log + copy_exec /bin/btrfs /bin + copy_exec /bin/btrfs-zero-log if [ ! -x /usr/share/initramfs-tools/hooks/fsck ] && [ ! -x /etc/initramfs-tools/hooks/fsck ] then - copy_exec /sbin/fsck.btrfs /sbin + copy_exec /bin/fsck.btrfs /bin fi fi diff -Nru btrfs-tools-3.19.1/debian/local/btrfs.local-premount btrfs-tools-4.0/debian/local/btrfs.local-premount --- btrfs-tools-3.19.1/debian/local/btrfs.local-premount 2014-10-23 21:00:58.000000000 +0000 +++ btrfs-tools-4.0/debian/local/btrfs.local-premount 2015-05-04 17:48:13.000000000 +0000 @@ -16,8 +16,8 @@ ;; esac -if [ -x /sbin/btrfs ] +if [ -x /bin/btrfs ] then modprobe btrfs - /sbin/btrfs device scan 2> /dev/null + /bin/btrfs device scan 2> /dev/null fi diff -Nru btrfs-tools-3.19.1/debian/local/btrfs-lvm.udev btrfs-tools-4.0/debian/local/btrfs-lvm.udev --- btrfs-tools-3.19.1/debian/local/btrfs-lvm.udev 2014-10-23 21:00:58.000000000 +0000 +++ btrfs-tools-4.0/debian/local/btrfs-lvm.udev 2015-05-04 17:48:00.000000000 +0000 @@ -1,6 +1,6 @@ SUBSYSTEM!="block", GOTO="btrfs_lvm_end" ENV{DM_UUID}!="LVM-?*", GOTO="btrfs_lvm_end" RUN+="/sbin/modprobe btrfs" -RUN+="/sbin/btrfs device scan $env{DEVNAME}" +RUN+="/bin/btrfs device scan $env{DEVNAME}" LABEL="btrfs_lvm_end" diff -Nru btrfs-tools-3.19.1/debian/local/btrfs.udev btrfs-tools-4.0/debian/local/btrfs.udev --- btrfs-tools-3.19.1/debian/local/btrfs.udev 2014-10-23 21:00:58.000000000 +0000 +++ btrfs-tools-4.0/debian/local/btrfs.udev 2015-05-04 17:48:26.000000000 +0000 @@ -2,6 +2,6 @@ ACTION!="add|change", GOTO="btrfs_end" ENV{ID_FS_TYPE}!="btrfs", GOTO="btrfs_end" RUN+="/sbin/modprobe btrfs" -RUN+="/sbin/btrfs device scan $env{DEVNAME}" +RUN+="/bin/btrfs device scan $env{DEVNAME}" LABEL="btrfs_end" diff -Nru btrfs-tools-3.19.1/debian/rules btrfs-tools-4.0/debian/rules --- btrfs-tools-3.19.1/debian/rules 2015-04-03 08:34:39.000000000 +0000 +++ btrfs-tools-4.0/debian/rules 2015-05-03 21:57:42.000000000 +0000 @@ -13,18 +13,20 @@ CFLAGS := $(patsubst -O2,-Os,$(CFLAGS)) %: - dh ${@} + dh ${@} --parallel -override_dh_auto_install: - dh_auto_install -- DESTDIR=$(CURDIR)/debian/btrfs-tools prefix=/usr bindir=/sbin mandir=/usr/share/man libdir=/usr/lib/$(DEB_HOST_MULTIARCH) +override_dh_auto_configure: + dh_auto_configure -- --bindir=/bin - # Adding udev integration - install -D -m 0644 debian/local/btrfs.udev debian/btrfs-tools/lib/udev/rules.d/70-btrfs.rules - install -D -m 0644 debian/local/btrfs-lvm.udev debian/btrfs-tools/lib/udev/rules.d/80-btrfs-lvm.rules +override_dh_auto_install: + dh_auto_install --destdir=debian/btrfs-tools # Adding initramfs-tools integration install -D -m 0755 debian/local/btrfs.hook debian/btrfs-tools/usr/share/initramfs-tools/hooks/btrfs install -D -m 0755 debian/local/btrfs.local-premount debian/btrfs-tools/usr/share/initramfs-tools/scripts/local-premount/btrfs +# Needs autopkgtest +override_dh_auto_test: + override_dh_strip: dh_strip --dbg-package=btrfs-tools-dbg diff -Nru btrfs-tools-3.19.1/Documentation/btrfs.asciidoc btrfs-tools-4.0/Documentation/btrfs.asciidoc --- btrfs-tools-3.19.1/Documentation/btrfs.asciidoc 1970-01-01 00:00:00.000000000 +0000 +++ btrfs-tools-4.0/Documentation/btrfs.asciidoc 2015-04-29 14:56:22.000000000 +0000 @@ -0,0 +1,121 @@ +btrfs(8) +======== + +NAME +---- +btrfs - control a btrfs filesystem + +SYNOPSIS +-------- +*btrfs* [] + +DESCRIPTION +----------- +*btrfs* is used to control the filesystem and the files and directories stored. +It is the tool to create or destroy a snapshot or a subvolume for the +filesystem, to defrag a file or a directory, flush the data to the disk, +to resize the filesystem, to scan the device. + +It is possible to abbreviate the commands unless the commands are ambiguous. +For example: it is possible to run *btrfs sub snaps* instead of +*btrfs subvolume snapshot*. +But *btrfs file s* is not allowed, because *file s* may be interpreted +both as *filesystem show* and as *filesystem sync*. + +If a command is terminated by '--help', the detailed help is showed. +If the passed command matches more commands, +detailed help of all the matched commands is showed. For example +*btrfs dev --help* shows the help of all *device** commands. + +COMMANDS +-------- +*balance*:: + Balance btrfs filesystem chunks across single or several devices. + + See `btrfs-balance`(8) for details. + +*check*:: + Do off-line check on a btrfs filesystem. + + See `btrfs-check`(8) for details. + +*device*:: + Manage devices managed by btrfs, including add/delete/scan and so + on. + + See `btrfs-device`(8) for details. + +*filesystem*:: + Manage a btrfs filesystem, including label setting/sync and so on. + + See `btrfs-filesystem`(8) for details. + +*inspect-internal*:: + Debug tools for developers/hackers. + + See `btrfs-inspect-internal`(8) for details. + +*property*:: + Get/set a property from/to a btrfs object. + + See `btrfs-property`(8) for details. + +*qgroup*:: + Manage quota group(qgroup) for btrfs filesystem. + + See `btrfs-qgroup`(8) for details. + +*quota*:: + Manage quota on btrfs filesystem like enabling/rescan and etc. + + See `btrfs-quota`(8) and `btrfs-qgroup`(8) for details. + +*receive*:: + Receive subvolume data from stdin/file for restore and etc. + + See `btrfs-receive`(8) for details. + +*replace*:: + Replace btrfs devices. + + See `btrfs-replace`(8) for details. + +*rescue*:: + Try to rescue damaged btrfs filesystem. + + See `btrfs-rescue`(8) for details. + +*restore*:: + Manage a btrfs filesystem, including label setting/sync and so on. + + See `btrfs-restore`(8) for details. + +*scrub*:: + Scrub a btrfs filesystem. + + See `btrfs-scrub`(8) for details. + +*send*:: + Send subvolume data to stdout/file for backup and etc. + + See `btrfs-send`(8) for details. + +*subvolume*:: + Create/delete/list/manage btrfs subvolume. + + See `btrfs-subvolume`(8) for details. + +EXIT STATUS +----------- +*btrfs* returns a zero exit status if it succeeds. Non zero is returned in +case of failure. + +AVAILABILITY +------------ +*btrfs* is part of btrfs-progs. +Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for +further details. + +SEE ALSO +-------- +`mkfs.btrfs`(8), `ionice`(1), +`btrfs-balance`(8), +`btrfs-check`(8), +`btrfs-device`(8), +`btrfs-filesystem`(8), +`btrfs-inspect-internal`(8), +`btrfs-property`(8), +`btrfs-qgroup`(8), +`btrfs-quota`(8), +`btrfs-receive`(8), +`btrfs-replace`(8), +`btrfs-rescue`(8), +`btrfs-restore`(8), +`btrfs-scrub`(8), +`btrfs-send`(8), +`btrfs-subvolume`(8), diff -Nru btrfs-tools-3.19.1/Documentation/btrfs-balance.asciidoc btrfs-tools-4.0/Documentation/btrfs-balance.asciidoc --- btrfs-tools-3.19.1/Documentation/btrfs-balance.asciidoc 1970-01-01 00:00:00.000000000 +0000 +++ btrfs-tools-4.0/Documentation/btrfs-balance.asciidoc 2015-04-29 14:56:22.000000000 +0000 @@ -0,0 +1,140 @@ +btrfs-balance(8) +================ + +NAME +---- +btrfs-balance - balance btrfs filesystem + +SYNOPSIS +-------- +*btrfs balance* + +DESCRIPTION +----------- +*btrfs balance* is used to balance chunks in a btrfs filesystem across +multiple or even single device. + +See `btrfs-device`(8) for more details about the effect on device management. + +NOTE: The balance subcommand also exists under the *filesystem* namespace. This +still works for backward compatibility but is deprecated and should not be +used anymore. + +NOTE: A short syntax *btrfs balance * works due to backward compatibility +but is deprecated and should not be used anymore. Use *btrfs balance start* +command instead. + +SUBCOMMAND +---------- +*cancel* :: +Cancel running or paused balance. + +*pause* :: +Pause running balance. + +*resume* :: +Resume interrupted balance. + +*start* [options] :: +Balance chunks across the devices *online*. ++ +Balance and/or convert (change allocation profile of) chunks that +passed all filters in a comma-separated list of filters for a +particular chunk type. +If filter list is not given balance all chunks of that type. +In case none of the -d, -m or -s options is +given balance all chunks in a filesystem. ++ +`Options` ++ +-d[]:::: +act on data chunks. See `FILTERS` section for details about . +-m[]:::: +act on metadata chunks. See `FILTERS` section for details about . +-s[]:::: +act on system chunks (only under -f). See `FILTERS` section for details about . +-v:::: +be verbose +-f:::: +force reducing of metadata integrity + +*status* [-v] :: +Show status of running or paused balance. ++ +If '-v' option is given, output will be verbose. + +FILTERS +------- +From kernel 3.3 onwards, btrfs balance can limit its action to a subset of the +full filesystem, and can be used to change the replication configuration (e.g. +moving data from single to RAID-1). This functionality is accessed through the +'-d', '-m' or '-s' options to btrfs balance start, which filter on data, +metadata and system blocks respectively. + +A filter has the following stucture: :: +'type'[='params'][,'type'=...] + +The available types are: + +*profiles*:: +Balances only block groups with the given replication profiles. Parameters +are a list of profile names separated by |. + +*usage*:: +Balances only block groups with usage under the given percentage. The +value of 0 is allowed and will clean up completely unused block groups, this +should not require any new space allocated. You may want to use usage=0 in +case balance is returnin ENOSPC and your filesystem is not too full. + +*devid*:: +Balances only block groups which have at least one chunk on the given +device (by btrfs device ID -- use btrfs fi show to list device IDs) + +*drange*:: +Balances only block groups which overlap with the given byte range on any +device. (Use in conjunction with "devid" to filter on a specific device). The +parameter is a range specified as . + +*vrange*:: +Balances only block groups which overlap with the given byte range in the +filesystem's internal virtual address space. This is the address space that +most reports from btrfs in the kernel log use. The parameter is a range +specified as . + +*convert*:: +Convert each selected block group to the given profile name identified by +parameters. + +*limit*:: +Process only given number of chunks, after all filters apply. This can be used +to specifically target a chunk in connection with other filters (drange, +vrange) or just simply limit the amount of work done by a single balance run. + +*soft*:: +Takes no parameters. Only has meaning when converting between profiles. +When doing convert from one profile to another and soft mode is on, +restriper won't touch chunks that already have the target profile. This is +useful if e.g. half of the FS was converted earlier. ++ +The soft mode switch is (like every other filter) per-type. This means +that we can convert for example meta chunks the "hard" way while converting +data chunks selectively with soft switch. + +Profile names, used in profiles and convert are one of: 'raid0', 'raid1', +'raid10', 'raid5', 'raid6', 'dup', 'single'. + +EXIT STATUS +----------- +*btrfs balance* returns a zero exit status if it succeeds. Non zero is +returned in case of failure. + +AVAILABILITY +------------ +*btrfs* is part of btrfs-progs. +Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for +further details. + +SEE ALSO +-------- +`mkfs.btrfs`(8), +`btrfs-device`(8) diff -Nru btrfs-tools-3.19.1/Documentation/btrfs-balance.txt btrfs-tools-4.0/Documentation/btrfs-balance.txt --- btrfs-tools-3.19.1/Documentation/btrfs-balance.txt 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/Documentation/btrfs-balance.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -btrfs-balance(8) -================ - -NAME ----- -btrfs-balance - balance btrfs filesystem - -SYNOPSIS --------- -*btrfs balance* - -DESCRIPTION ------------ -*btrfs balance* is used to balance chunks in a btrfs filesystem across -multiple or even single device. - -See `btrfs-device`(8) for more details about the effect on device management. - -NOTE: The balance subcommand also exists under the *filesystem* namespace. This -still works for backward compatibility but is deprecated and should not be -used anymore. - -NOTE: A short syntax *btrfs balance * works due to backward compatibility -but is deprecated and should not be used anymore. Use *btrfs balance start* -command instead. - -SUBCOMMAND ----------- -*cancel* :: -Cancel running or paused balance. - -*pause* :: -Pause running balance. - -*resume* :: -Resume interrupted balance. - -*start* [options] :: -Balance chunks across the devices *online*. -+ -Balance and/or convert (change allocation profile of) chunks that -passed all filters in a comma-separated list of filters for a -particular chunk type. -If filter list is not given balance all chunks of that type. -In case none of the -d, -m or -s options is -given balance all chunks in a filesystem. -+ -`Options` -+ --d[]:::: -act on data chunks. See `FILTERS` section for details about . --m[]:::: -act on metadata chunks. See `FILTERS` section for details about . --s[]:::: -act on system chunks (only under -f). See `FILTERS` section for details about . --v:::: -be verbose --f:::: -force reducing of metadata integrity - -*status* [-v] :: -Show status of running or paused balance. -+ -If '-v' option is given, output will be verbose. - -FILTERS -------- -From kernel 3.3 onwards, btrfs balance can limit its action to a subset of the -full filesystem, and can be used to change the replication configuration (e.g. -moving data from single to RAID-1). This functionality is accessed through the -'-d', '-m' or '-s' options to btrfs balance start, which filter on data, -metadata and system blocks respectively. - -A filter has the following stucture: :: -'type'[='params'][,'type'=...] - -The available types are: - -*profiles*:: -Balances only block groups with the given replication profiles. Parameters -are a list of profile names separated by |. - -*usage*:: -Balances only block groups with usage under the given percentage. The -value of 0 is allowed and will clean up completely unused block groups, this -should not require any new space allocated. You may want to use usage=0 in -case balance is returnin ENOSPC and your filesystem is not too full. - -*devid*:: -Balances only block groups which have at least one chunk on the given -device (by btrfs device ID -- use btrfs fi show to list device IDs) - -*drange*:: -Balances only block groups which overlap with the given byte range on any -device. (Use in conjunction with "devid" to filter on a specific device). The -parameter is a range specified as . - -*vrange*:: -Balances only block groups which overlap with the given byte range in the -filesystem's internal virtual address space. This is the address space that -most reports from btrfs in the kernel log use. The parameter is a range -specified as . - -*convert*:: -Convert each selected block group to the given profile name identified by -parameters. - -*limit*:: -Process only given number of chunks, after all filters apply. This can be used -to specifically target a chunk in connection with other filters (drange, -vrange) or just simply limit the amount of work done by a single balance run. - -*soft*:: -Takes no parameters. Only has meaning when converting between profiles. -When doing convert from one profile to another and soft mode is on, -restriper won't touch chunks that already have the target profile. This is -useful if e.g. half of the FS was converted earlier. -+ -The soft mode switch is (like every other filter) per-type. This means -that we can convert for example meta chunks the "hard" way while converting -data chunks selectively with soft switch. - -Profile names, used in profiles and convert are one of: 'raid0', 'raid1', -'raid10', 'raid5', 'raid6', 'dup', 'single'. - -EXIT STATUS ------------ -*btrfs balance* returns a zero exit status if it succeeds. Non zero is -returned in case of failure. - -AVAILABILITY ------------- -*btrfs* is part of btrfs-progs. -Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for -further details. - -SEE ALSO --------- -`mkfs.btrfs`(8), -`btrfs-device`(8) diff -Nru btrfs-tools-3.19.1/Documentation/btrfs-check.asciidoc btrfs-tools-4.0/Documentation/btrfs-check.asciidoc --- btrfs-tools-3.19.1/Documentation/btrfs-check.asciidoc 1970-01-01 00:00:00.000000000 +0000 +++ btrfs-tools-4.0/Documentation/btrfs-check.asciidoc 2015-04-29 14:56:22.000000000 +0000 @@ -0,0 +1,58 @@ +btrfs-check(8) +============== + +NAME +---- +btrfs-check - check or repair an unmounted btrfs filesystem + +SYNOPSIS +-------- +*btrfs check* [options] + +DESCRIPTION +----------- +*btrfs check* is used to check or repair an unmounted btrfs filesystem. + +NOTE: Since btrfs is under development, the *btrfs check* capabilities are +continuously enhanced. It's highly recommended to read the following btrfs +wiki before executing *btrfs check* with '--repair' option: + +https://btrfs.wiki.kernel.org/index.php/Btrfsck + +*btrfsck* is an alias of *btrfs check* command and is now deprecated. + +OPTIONS +------- +-s|--super :: +use th superblock copy, valid values are 0 up to 2 if the +respective superblock offset is within the fileystem +--repair:: +try to repair the filesystem +--init-csum-tree:: +create a new CRC tree and recalculate all checksums +--init-extent-tree:: +create a new extent tree +--check-data-csum:: +verify checkums of data blocks +--qgroup-report:: +verify qgroup accounting and compare against filesystem accounting +--subvol-extents :: +show extent state for a subvolume +--tree-root :: +use the given bytenr for the tree root + +EXIT STATUS +----------- +*btrfs check* returns a zero exit status if it succeeds. Non zero is +returned in case of failure. + +AVAILABILITY +------------ +*btrfs* is part of btrfs-progs. +Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for +further details. + +SEE ALSO +-------- +`mkfs.btrfs`(8), +`btrfs-scrub`(8), +`btrfs-rescue`(8) diff -Nru btrfs-tools-3.19.1/Documentation/btrfs-check.txt btrfs-tools-4.0/Documentation/btrfs-check.txt --- btrfs-tools-3.19.1/Documentation/btrfs-check.txt 2015-03-25 17:43:42.000000000 +0000 +++ btrfs-tools-4.0/Documentation/btrfs-check.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -btrfs-check(8) -============== - -NAME ----- -btrfs-check - check or repair an unmounted btrfs filesystem - -SYNOPSIS --------- -*btrfs check* [options] - -DESCRIPTION ------------ -*btrfs check* is used to check or repair an unmounted btrfs filesystem. - -NOTE: Since btrfs is under development, the *btrfs check* capabilities are -continuously enhanced. It's highly recommended to read the following btrfs -wiki before executing *btrfs check* with '--repair' option: + -https://btrfs.wiki.kernel.org/index.php/Btrfsck - -*btrfsck* is an alias of *btrfs check* command and is now deprecated. - -OPTIONS -------- --s|--super :: -use th superblock copy, valid values are 0 up to 2 if the -respective superblock offset is within the fileystem ---repair:: -try to repair the filesystem ---init-csum-tree:: -create a new CRC tree and recalculate all checksums ---init-extent-tree:: -create a new extent tree ---check-data-csum:: -verify checkums of data blocks ---qgroup-report:: -verify qgroup accounting and compare against filesystem accounting ---subvol-extents :: -show extent state for a subvolume ---tree-root :: -use the given bytenr for the tree root - -EXIT STATUS ------------ -*btrfs check* returns a zero exit status if it succeeds. Non zero is -returned in case of failure. - -AVAILABILITY ------------- -*btrfs* is part of btrfs-progs. -Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for -further details. - -SEE ALSO --------- -`mkfs.btrfs`(8), -`btrfs-scrub`(8), -`btrfs-rescue`(8) diff -Nru btrfs-tools-3.19.1/Documentation/btrfs-convert.asciidoc btrfs-tools-4.0/Documentation/btrfs-convert.asciidoc --- btrfs-tools-3.19.1/Documentation/btrfs-convert.asciidoc 1970-01-01 00:00:00.000000000 +0000 +++ btrfs-tools-4.0/Documentation/btrfs-convert.asciidoc 2015-04-29 14:56:22.000000000 +0000 @@ -0,0 +1,59 @@ +btrfs-convert(8) +================ + +NAME +---- +btrfs-convert - convert from ext2/3/4 filesystem to btrfs or rollback + +SYNOPSIS +-------- +*btrfs-convert* [options] + +DESCRIPTION +----------- +*btrfs-convert* is used to convert existed ext2/3/4 to btrfs filesystem, +and the original filesystem image is accessible as from separate subvolume +named 'ext2_saved' as file image. + +WARNING: If one hopes to rollback to ext2/3/4, they should not execute +*btrfs balance* command on converted btrfs, since it will change the extent +layout and make *btrfs-convert* unable to rollback. + +NOTE: If one is satisfied with converted btrfs, and not longer wants to +rollback to ext2/3/4, it is highly recommended to remove 'ext2_saved' subvolume +and execute *btrfs filesystem defragment* and *btrfs balance* command on the +converted btrfs. + +OPTIONS +------- +-d|--no-datasum:: +Disable data checksum calculations and set NODATASUM file flag. This can speed +up the conversion. +-i|--no-xattr:: +Ignore xattrs and ACLs. +-n|--no-inline:: +Disable inlining of small files to metadata blocks. +-N|--nodesize :: +Set filesystem nodesize, the tree block size in which btrfs stores data. +The default value is 16KB (16384) or the page size, whichever is bigger. +Must be a multiple of the sectorsize, but not larger than 65536. +-r|--rollback:: +Roll back to ext2fs. +-l|--label