diff options
author | Dimitri John Ledkov <dimitri.j.ledkov@linux.intel.com> | 2015-10-24 00:09:28 +0100 |
---|---|---|
committer | Dimitri John Ledkov <dimitri.j.ledkov@linux.intel.com> | 2015-10-24 00:09:28 +0100 |
commit | da6658718a64c2855497dec85430775b7ad5f601 (patch) | |
tree | 9359dab24c745ea5410bc0238e4dc34f27a40eb8 /mkfs.c | |
parent | aeb9dfe76e4f258530a96e0f0706d74b8ddc908f (diff) | |
parent | 9170e8eb55a32275ff7219e26f9a870bed95b199 (diff) |
Record btrfs-tools (4.2.2-1) in archive suite sid
Diffstat (limited to 'mkfs.c')
-rw-r--r-- | mkfs.c | 188 |
1 files changed, 171 insertions, 17 deletions
@@ -17,6 +17,7 @@ */ #include "kerncompat.h" +#include "androidcompat.h" #include <sys/ioctl.h> #include <sys/mount.h> @@ -25,7 +26,7 @@ #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> -#include <sys/dir.h> +/* #include <sys/dir.h> included via androidcompat.h */ #include <fcntl.h> #include <unistd.h> #include <getopt.h> @@ -356,6 +357,7 @@ static u64 parse_profile(char *s) return 0; } else { fprintf(stderr, "Unknown profile %s\n", s); + exit(1); } /* not reached */ return 0; @@ -599,7 +601,7 @@ static int add_symbolic_link(struct btrfs_trans_handle *trans, goto fail; } if (ret >= sectorsize) { - fprintf(stderr, "symlink too long for %s", path_name); + fprintf(stderr, "symlink too long for %s\n", path_name); ret = -1; goto fail; } @@ -1177,6 +1179,149 @@ static void list_all_devices(struct btrfs_root *root) printf("\n"); } +static int is_temp_block_group(struct extent_buffer *node, + struct btrfs_block_group_item *bgi, + u64 data_profile, u64 meta_profile, + u64 sys_profile) +{ + u64 flag = btrfs_disk_block_group_flags(node, bgi); + u64 flag_type = flag & BTRFS_BLOCK_GROUP_TYPE_MASK; + u64 flag_profile = flag & BTRFS_BLOCK_GROUP_PROFILE_MASK; + u64 used = btrfs_disk_block_group_used(node, bgi); + + /* + * Chunks meets all the following conditions is a temp chunk + * 1) Empty chunk + * Temp chunk is always empty. + * + * 2) profile dismatch with mkfs profile. + * Temp chunk is always in SINGLE + * + * 3) Size differs with mkfs_alloc + * Special case for SINGLE/SINGLE btrfs. + * In that case, temp data chunk and real data chunk are always empty. + * So we need to use mkfs_alloc to be sure which chunk is the newly + * allocated. + * + * Normally, new chunk size is equal to mkfs one (One chunk) + * If it has multiple chunks, we just refuse to delete any one. + * As they are all single, so no real problem will happen. + * So only use condition 1) and 2) to judge them. + */ + if (used != 0) + return 0; + switch (flag_type) { + case BTRFS_BLOCK_GROUP_DATA: + case BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA: + data_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; + if (flag_profile != data_profile) + return 1; + break; + case BTRFS_BLOCK_GROUP_METADATA: + meta_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; + if (flag_profile != meta_profile) + return 1; + break; + case BTRFS_BLOCK_GROUP_SYSTEM: + sys_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; + if (flag_profile != sys_profile) + return 1; + break; + } + return 0; +} + +/* Note: if current is a block group, it will skip it anyway */ +static int next_block_group(struct btrfs_root *root, + struct btrfs_path *path) +{ + struct btrfs_key key; + int ret = 0; + + while (1) { + ret = btrfs_next_item(root, path); + if (ret) + goto out; + + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); + if (key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) + goto out; + } +out: + return ret; +} + +/* This function will cleanup */ +static int cleanup_temp_chunks(struct btrfs_fs_info *fs_info, + struct mkfs_allocation *alloc, + u64 data_profile, u64 meta_profile, + u64 sys_profile) +{ + struct btrfs_trans_handle *trans = NULL; + struct btrfs_block_group_item *bgi; + struct btrfs_root *root = fs_info->extent_root; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_path *path; + int ret = 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + trans = btrfs_start_transaction(root, 1); + + key.objectid = 0; + key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; + key.offset = 0; + + while (1) { + /* + * as the rest of the loop may modify the tree, we need to + * start a new search each time. + */ + ret = btrfs_search_slot(trans, root, &key, path, 0, 0); + if (ret < 0) + goto out; + + btrfs_item_key_to_cpu(path->nodes[0], &found_key, + path->slots[0]); + if (found_key.objectid < key.objectid) + goto out; + if (found_key.type != BTRFS_BLOCK_GROUP_ITEM_KEY) { + ret = next_block_group(root, path); + if (ret < 0) + goto out; + if (ret > 0) { + ret = 0; + goto out; + } + btrfs_item_key_to_cpu(path->nodes[0], &found_key, + path->slots[0]); + } + + bgi = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_block_group_item); + if (is_temp_block_group(path->nodes[0], bgi, + data_profile, meta_profile, + sys_profile)) { + ret = btrfs_free_block_group(trans, fs_info, + found_key.objectid, found_key.offset); + if (ret < 0) + goto out; + } + btrfs_release_path(path); + key.objectid = found_key.objectid + found_key.offset; + } +out: + if (trans) + btrfs_commit_transaction(trans, root); + btrfs_free_path(path); + return ret; +} + int main(int ac, char **av) { char *file; @@ -1321,9 +1466,8 @@ int main(int ac, char **av) print_usage(c != GETOPT_VAL_HELP); } } + sectorsize = max(sectorsize, (u32)sysconf(_SC_PAGESIZE)); - if (btrfs_check_nodesize(nodesize, sectorsize)) - exit(1); saved_optind = optind; dev_cnt = ac - optind; if (dev_cnt == 0) @@ -1350,7 +1494,7 @@ int main(int ac, char **av) while (dev_cnt-- > 0) { file = av[optind++]; - if (is_block_device(file)) + if (is_block_device(file) == 1) if (test_dev_for_mkfs(file, force_overwrite)) exit(1); } @@ -1397,17 +1541,12 @@ int main(int ac, char **av) } } - if (!nodesize_forced) { + if (!nodesize_forced) nodesize = best_nodesize; - if (btrfs_check_nodesize(nodesize, sectorsize)) - exit(1); - } - if (nodesize != sectorsize) { - fprintf(stderr, "Error: mixed metadata/data block groups " - "require metadata blocksizes equal to the sectorsize\n"); - exit(1); - } } + if (btrfs_check_nodesize(nodesize, sectorsize, + features)) + exit(1); /* Check device/block_count after the nodesize is determined */ if (block_count && block_count < btrfs_min_dev_size(nodesize)) { @@ -1554,7 +1693,10 @@ int main(int ac, char **av) } trans = btrfs_start_transaction(root, 1); - BUG_ON(!trans); + if (!trans) { + fprintf(stderr, "failed to start transaction\n"); + exit(1); + } ret = create_data_block_groups(trans, root, mixed, &allocation); if (ret) { @@ -1571,8 +1713,12 @@ int main(int ac, char **av) btrfs_commit_transaction(trans, root); trans = btrfs_start_transaction(root, 1); + if (!trans) { + fprintf(stderr, "failed to start transaction\n"); + exit(1); + } - if (is_block_device(file)) + if (is_block_device(file) == 1) btrfs_register_one_device(file); if (dev_cnt == 0) @@ -1622,7 +1768,7 @@ int main(int ac, char **av) (unsigned long long)device->devid); } - if (is_block_device(file)) + if (is_block_device(file) == 1) btrfs_register_one_device(file); } @@ -1649,6 +1795,12 @@ raid_groups: ret = make_image(source_dir, root, fd); BUG_ON(ret); } + ret = cleanup_temp_chunks(root->fs_info, &allocation, data_profile, + metadata_profile, metadata_profile); + if (ret < 0) { + fprintf(stderr, "Failed to cleanup temporary chunks\n"); + goto out; + } if (verbose) { char features_buf[64]; @@ -1683,8 +1835,10 @@ raid_groups: list_all_devices(root); } +out: ret = close_ctree(root); BUG_ON(ret); + btrfs_close_all_devices(); free(label); return 0; } |