btrfs-progs: mkfs: Enhance minimal device size calculation to fix mkfs failure on...
[platform/upstream/btrfs-progs.git] / mkfs / main.c
index 72834c9..90fab59 100644 (file)
 #include "transaction.h"
 #include "utils.h"
 #include "list_sort.h"
+#include "help.h"
+#include "mkfs/common.h"
+#include "fsfeatures.h"
+
+int path_cat_out(char *out, const char *p1, const char *p2);
 
 static u64 index_cnt = 2;
 static int verbose = 1;
@@ -64,6 +69,7 @@ struct mkfs_allocation {
 static int create_metadata_block_groups(struct btrfs_root *root, int mixed,
                                struct mkfs_allocation *allocation)
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_trans_handle *trans;
        u64 bytes_used;
        u64 chunk_start = 0;
@@ -71,10 +77,11 @@ static int create_metadata_block_groups(struct btrfs_root *root, int mixed,
        int ret;
 
        trans = btrfs_start_transaction(root, 1);
-       bytes_used = btrfs_super_bytes_used(root->fs_info->super_copy);
+       BUG_ON(IS_ERR(trans));
+       bytes_used = btrfs_super_bytes_used(fs_info->super_copy);
 
        root->fs_info->system_allocs = 1;
-       ret = btrfs_make_block_group(trans, root, bytes_used,
+       ret = btrfs_make_block_group(trans, fs_info, bytes_used,
                                     BTRFS_BLOCK_GROUP_SYSTEM,
                                     BTRFS_FIRST_CHUNK_TREE_OBJECTID,
                                     0, BTRFS_MKFS_SYSTEM_GROUP_SIZE);
@@ -83,7 +90,7 @@ static int create_metadata_block_groups(struct btrfs_root *root, int mixed,
                return ret;
 
        if (mixed) {
-               ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
+               ret = btrfs_alloc_chunk(trans, fs_info,
                                        &chunk_start, &chunk_size,
                                        BTRFS_BLOCK_GROUP_METADATA |
                                        BTRFS_BLOCK_GROUP_DATA);
@@ -93,7 +100,7 @@ static int create_metadata_block_groups(struct btrfs_root *root, int mixed,
                }
                if (ret)
                        return ret;
-               ret = btrfs_make_block_group(trans, root, 0,
+               ret = btrfs_make_block_group(trans, fs_info, 0,
                                             BTRFS_BLOCK_GROUP_METADATA |
                                             BTRFS_BLOCK_GROUP_DATA,
                                             BTRFS_FIRST_CHUNK_TREE_OBJECTID,
@@ -102,7 +109,7 @@ static int create_metadata_block_groups(struct btrfs_root *root, int mixed,
                        return ret;
                allocation->mixed += chunk_size;
        } else {
-               ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
+               ret = btrfs_alloc_chunk(trans, fs_info,
                                        &chunk_start, &chunk_size,
                                        BTRFS_BLOCK_GROUP_METADATA);
                if (ret == -ENOSPC) {
@@ -111,7 +118,7 @@ static int create_metadata_block_groups(struct btrfs_root *root, int mixed,
                }
                if (ret)
                        return ret;
-               ret = btrfs_make_block_group(trans, root, 0,
+               ret = btrfs_make_block_group(trans, fs_info, 0,
                                             BTRFS_BLOCK_GROUP_METADATA,
                                             BTRFS_FIRST_CHUNK_TREE_OBJECTID,
                                             chunk_start, chunk_size);
@@ -131,12 +138,13 @@ static int create_data_block_groups(struct btrfs_trans_handle *trans,
                struct btrfs_root *root, int mixed,
                struct mkfs_allocation *allocation)
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
        u64 chunk_start = 0;
        u64 chunk_size = 0;
        int ret = 0;
 
        if (!mixed) {
-               ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
+               ret = btrfs_alloc_chunk(trans, fs_info,
                                        &chunk_start, &chunk_size,
                                        BTRFS_BLOCK_GROUP_DATA);
                if (ret == -ENOSPC) {
@@ -145,7 +153,7 @@ static int create_data_block_groups(struct btrfs_trans_handle *trans,
                }
                if (ret)
                        return ret;
-               ret = btrfs_make_block_group(trans, root, 0,
+               ret = btrfs_make_block_group(trans, fs_info, 0,
                                             BTRFS_BLOCK_GROUP_DATA,
                                             BTRFS_FIRST_CHUNK_TREE_OBJECTID,
                                             chunk_start, chunk_size);
@@ -158,8 +166,8 @@ err:
        return ret;
 }
 
-static int make_root_dir(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-               struct mkfs_allocation *allocation)
+static int make_root_dir(struct btrfs_trans_handle *trans,
+               struct btrfs_root *root)
 {
        struct btrfs_key location;
        int ret;
@@ -241,11 +249,12 @@ static int create_one_raid_group(struct btrfs_trans_handle *trans,
                              struct mkfs_allocation *allocation)
 
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
        u64 chunk_start;
        u64 chunk_size;
        int ret;
 
-       ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
+       ret = btrfs_alloc_chunk(trans, fs_info,
                                &chunk_start, &chunk_size, type);
        if (ret == -ENOSPC) {
                error("not enough free space to allocate chunk");
@@ -254,7 +263,7 @@ static int create_one_raid_group(struct btrfs_trans_handle *trans,
        if (ret)
                return ret;
 
-       ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0,
+       ret = btrfs_make_block_group(trans, fs_info, 0,
                                     type, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
                                     chunk_start, chunk_size);
 
@@ -314,13 +323,12 @@ static int create_raid_groups(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-static int create_data_reloc_tree(struct btrfs_trans_handle *trans,
-                                 struct btrfs_root *root)
+static int create_tree(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *root, u64 objectid)
 {
        struct btrfs_key location;
        struct btrfs_root_item root_item;
        struct extent_buffer *tmp;
-       u64 objectid = BTRFS_DATA_RELOC_TREE_OBJECTID;
        int ret;
 
        ret = btrfs_copy_root(trans, root, root->node, &tmp, objectid);
@@ -429,6 +437,14 @@ static int add_directory_items(struct btrfs_trans_handle *trans,
                filetype = BTRFS_FT_REG_FILE;
        if (S_ISLNK(st->st_mode))
                filetype = BTRFS_FT_SYMLINK;
+       if (S_ISSOCK(st->st_mode))
+               filetype = BTRFS_FT_SOCK;
+       if (S_ISCHR(st->st_mode))
+               filetype = BTRFS_FT_CHRDEV;
+       if (S_ISBLK(st->st_mode))
+               filetype = BTRFS_FT_BLKDEV;
+       if (S_ISFIFO(st->st_mode))
+               filetype = BTRFS_FT_FIFO;
 
        ret = btrfs_insert_dir_item(trans, root, name, name_len,
                                    parent_inum, &location,
@@ -448,7 +464,7 @@ static int fill_inode_item(struct btrfs_trans_handle *trans,
                           struct btrfs_inode_item *dst, struct stat *src)
 {
        u64 blocks = 0;
-       u64 sectorsize = root->sectorsize;
+       u64 sectorsize = root->fs_info->sectorsize;
 
        /*
         * btrfs_inode_item has some reserved fields
@@ -541,8 +557,8 @@ static u64 calculate_dir_inode_size(const char *dirname)
 static int add_inode_items(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct stat *st, const char *name,
-                          u64 self_objectid, ino_t parent_inum,
-                          int dir_index_cnt, struct btrfs_inode_item *inode_ret)
+                          u64 self_objectid,
+                          struct btrfs_inode_item *inode_ret)
 {
        int ret;
        struct btrfs_inode_item btrfs_inode;
@@ -642,15 +658,14 @@ fail:
 static int add_file_items(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root,
                          struct btrfs_inode_item *btrfs_inode, u64 objectid,
-                         ino_t parent_inum, struct stat *st,
-                         const char *path_name, int out_fd)
+                         struct stat *st, const char *path_name)
 {
        int ret = -1;
        ssize_t ret_read;
        u64 bytes_read = 0;
        struct btrfs_key key;
        int blocks;
-       u32 sectorsize = root->sectorsize;
+       u32 sectorsize = root->fs_info->sectorsize;
        u64 first_block = 0;
        u64 file_pos = 0;
        u64 cur_bytes;
@@ -714,7 +729,7 @@ again:
         * keep our extent size at 1MB max, this makes it easier to work inside
         * the tiny block groups created during mkfs
         */
-       cur_bytes = min(total_bytes, 1024ULL * 1024);
+       cur_bytes = min(total_bytes, (u64)SZ_1M);
        ret = btrfs_reserve_extent(trans, root, cur_bytes, 0, 0, (u64)-1,
                                   &key, 1);
        if (ret)
@@ -751,7 +766,7 @@ again:
                if (ret)
                        goto end;
 
-               ret = write_and_map_eb(trans, root, eb);
+               ret = write_and_map_eb(root->fs_info, eb);
                if (ret) {
                        error("failed to write %s", path_name);
                        goto end;
@@ -780,23 +795,9 @@ end:
        return ret;
 }
 
-static char *make_path(const char *dir, const char *name)
-{
-       char *path;
-
-       path = malloc(strlen(dir) + strlen(name) + 2);
-       if (!path)
-               return NULL;
-       strcpy(path, dir);
-       if (dir[strlen(dir) - 1] != '/')
-               strcat(path, "/");
-       strcat(path, name);
-       return path;
-}
-
 static int traverse_directory(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root, const char *dir_name,
-                             struct directory_name_entry *dir_head, int out_fd)
+                             struct directory_name_entry *dir_head)
 {
        int ret = 0;
 
@@ -901,7 +902,6 @@ static int traverse_directory(struct btrfs_trans_handle *trans,
 
                        ret = add_inode_items(trans, root, &st,
                                              cur_file->d_name, cur_inum,
-                                             parent_inum, dir_index_cnt,
                                              &cur_inode);
                        if (ret == -EEXIST) {
                                if (st.st_nlink <= 1) {
@@ -929,20 +929,34 @@ static int traverse_directory(struct btrfs_trans_handle *trans,
                        }
 
                        if (S_ISDIR(st.st_mode)) {
+                               char tmp[PATH_MAX];
+
                                dir_entry = malloc(sizeof(struct directory_name_entry));
                                if (!dir_entry) {
                                        ret = -ENOMEM;
                                        goto fail;
                                }
                                dir_entry->dir_name = cur_file->d_name;
-                               dir_entry->path = make_path(parent_dir_entry->path,
-                                                           cur_file->d_name);
+                               if (path_cat_out(tmp, parent_dir_entry->path,
+                                                       cur_file->d_name)) {
+                                       error("invalid path: %s/%s",
+                                                       parent_dir_entry->path,
+                                                       cur_file->d_name);
+                                       ret = -EINVAL;
+                                       goto fail;
+                               }
+                               dir_entry->path = strdup(tmp);
+                               if (!dir_entry->path) {
+                                       error("not enough memory to store path");
+                                       ret = -ENOMEM;
+                                       goto fail;
+                               }
                                dir_entry->inum = cur_inum;
                                list_add_tail(&dir_entry->list, &dir_head->list);
                        } else if (S_ISREG(st.st_mode)) {
                                ret = add_file_items(trans, root, &cur_inode,
-                                                    cur_inum, parent_inum, &st,
-                                                    cur_file->d_name, out_fd);
+                                                    cur_inum, &st,
+                                                    cur_file->d_name);
                                if (ret) {
                                        error("unable to add file items for %s: %d",
                                                cur_file->d_name, ret);
@@ -983,49 +997,49 @@ static int create_chunks(struct btrfs_trans_handle *trans,
                         u64 size_of_data,
                         struct mkfs_allocation *allocation)
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
        u64 chunk_start;
        u64 chunk_size;
        u64 meta_type = BTRFS_BLOCK_GROUP_METADATA;
        u64 data_type = BTRFS_BLOCK_GROUP_DATA;
-       u64 minimum_data_chunk_size = 8 * 1024 * 1024;
+       u64 minimum_data_chunk_size = SZ_8M;
        u64 i;
        int ret;
 
        for (i = 0; i < num_of_meta_chunks; i++) {
-               ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
+               ret = btrfs_alloc_chunk(trans, fs_info,
                                        &chunk_start, &chunk_size, meta_type);
                if (ret)
                        return ret;
-               ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0,
+               ret = btrfs_make_block_group(trans, fs_info, 0,
                                             meta_type, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
                                             chunk_start, chunk_size);
                allocation->metadata += chunk_size;
                if (ret)
                        return ret;
                set_extent_dirty(&root->fs_info->free_space_cache,
-                                chunk_start, chunk_start + chunk_size - 1, 0);
+                                chunk_start, chunk_start + chunk_size - 1);
        }
 
        if (size_of_data < minimum_data_chunk_size)
                size_of_data = minimum_data_chunk_size;
 
-       ret = btrfs_alloc_data_chunk(trans, root->fs_info->extent_root,
+       ret = btrfs_alloc_data_chunk(trans, fs_info,
                                     &chunk_start, size_of_data, data_type, 0);
        if (ret)
                return ret;
-       ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0,
+       ret = btrfs_make_block_group(trans, fs_info, 0,
                                     data_type, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
                                     chunk_start, size_of_data);
        allocation->data += size_of_data;
        if (ret)
                return ret;
        set_extent_dirty(&root->fs_info->free_space_cache,
-                        chunk_start, chunk_start + size_of_data - 1, 0);
+                        chunk_start, chunk_start + size_of_data - 1);
        return ret;
 }
 
-static int make_image(const char *source_dir, struct btrfs_root *root,
-               int out_fd)
+static int make_image(const char *source_dir, struct btrfs_root *root)
 {
        int ret;
        struct btrfs_trans_handle *trans;
@@ -1043,7 +1057,8 @@ static int make_image(const char *source_dir, struct btrfs_root *root,
        INIT_LIST_HEAD(&dir_head.list);
 
        trans = btrfs_start_transaction(root, 1);
-       ret = traverse_directory(trans, root, source_dir, &dir_head, out_fd);
+       BUG_ON(IS_ERR(trans));
+       ret = traverse_directory(trans, root, source_dir, &dir_head);
        if (ret) {
                error("unable to traverse directory %s: %d", source_dir, ret);
                goto fail;
@@ -1058,6 +1073,19 @@ static int make_image(const char *source_dir, struct btrfs_root *root,
                printf("Making image is completed.\n");
        return 0;
 fail:
+       /*
+        * Since we don't have btrfs_abort_transaction() yet, uncommitted trans
+        * will trigger a BUG_ON().
+        *
+        * However before mkfs is fully finished, the magic number is invalid,
+        * so even we commit transaction here, the fs still can't be mounted.
+        *
+        * To do a graceful error out, here we commit transaction as a
+        * workaround.
+        * Since we have already hit some problem, the return value doesn't
+        * matter now.
+        */
+       btrfs_commit_transaction(trans, root);
        while (!list_empty(&dir_head.list)) {
                dir_entry = list_entry(dir_head.list.next,
                                       struct directory_name_entry, list);
@@ -1091,9 +1119,9 @@ static u64 size_sourcedir(const char *dir_name, u64 sectorsize,
        u64 dir_size = 0;
        u64 total_size = 0;
        int ret;
-       u64 default_chunk_size = 8 * 1024 * 1024;       /* 8MB */
-       u64 allocated_meta_size = 8 * 1024 * 1024;      /* 8MB */
-       u64 allocated_total_size = 20 * 1024 * 1024;    /* 20MB */
+       u64 default_chunk_size = SZ_8M;
+       u64 allocated_meta_size = SZ_8M;
+       u64 allocated_total_size = 20 * SZ_1M;  /* 20MB */
        u64 num_of_meta_chunks = 0;
        u64 num_of_data_chunks = 0;
        u64 num_of_allocated_meta_chunks =
@@ -1321,6 +1349,7 @@ static int cleanup_temp_chunks(struct btrfs_fs_info *fs_info,
 
        btrfs_init_path(&path);
        trans = btrfs_start_transaction(root, 1);
+       BUG_ON(IS_ERR(trans));
 
        key.objectid = 0;
        key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
@@ -1334,6 +1363,9 @@ static int cleanup_temp_chunks(struct btrfs_fs_info *fs_info,
                ret = btrfs_search_slot(trans, root, &key, &path, 0, 0);
                if (ret < 0)
                        goto out;
+               /* Don't pollute ret for >0 case */
+               if (ret > 0)
+                       ret = 0;
 
                btrfs_item_key_to_cpu(path.nodes[0], &found_key,
                                      path.slots[0]);
@@ -1397,7 +1429,6 @@ int main(int argc, char **argv)
        char *label = NULL;
        u64 block_count = 0;
        u64 dev_block_count = 0;
-       u64 blocks[7];
        u64 alloc_start = 0;
        u64 metadata_profile = 0;
        u64 data_profile = 0;
@@ -1406,8 +1437,9 @@ int main(int argc, char **argv)
        u32 sectorsize = 4096;
        u32 stripesize = 4096;
        int zero_end = 1;
-       int fd;
+       int fd = -1;
        int ret;
+       int close_ret;
        int i;
        int mixed = 0;
        int nodesize_forced = 0;
@@ -1421,6 +1453,7 @@ int main(int argc, char **argv)
        u64 num_of_meta_chunks = 0;
        u64 size_of_data = 0;
        u64 source_dir_size = 0;
+       u64 min_dev_size;
        int dev_cnt = 0;
        int saved_optind;
        char fs_uuid[BTRFS_UUID_UNPARSED_SIZE] = { 0 };
@@ -1492,12 +1525,12 @@ int main(int argc, char **argv)
                                        error("unrecognized filesystem feature '%s'",
                                                        tmp);
                                        free(orig);
-                                       exit(1);
+                                       goto error;
                                }
                                free(orig);
                                if (features & BTRFS_FEATURE_LIST_ALL) {
                                        btrfs_list_all_fs_features(0);
-                                       exit(0);
+                                       goto success;
                                }
                                break;
                                }
@@ -1511,8 +1544,7 @@ int main(int argc, char **argv)
                        case 'V':
                                printf("mkfs.btrfs, part of %s\n",
                                                PACKAGE_STRING);
-                               exit(0);
-                               break;
+                               goto success;
                        case 'r':
                                source_dir = optarg;
                                source_dir_set = 1;
@@ -1547,7 +1579,7 @@ int main(int argc, char **argv)
 
        if (source_dir_set && dev_cnt > 1) {
                error("the option -r is limited to a single device");
-               exit(1);
+               goto error;
        }
 
        if (*fs_uuid) {
@@ -1555,19 +1587,23 @@ int main(int argc, char **argv)
 
                if (uuid_parse(fs_uuid, dummy_uuid) != 0) {
                        error("could not parse UUID: %s", fs_uuid);
-                       exit(1);
+                       goto error;
                }
                if (!test_uuid_unique(fs_uuid)) {
                        error("non-unique UUID: %s", fs_uuid);
-                       exit(1);
+                       goto error;
                }
        }
 
        while (dev_cnt-- > 0) {
                file = argv[optind++];
                if (is_block_device(file) == 1)
-                       if (test_dev_for_mkfs(file, force_overwrite))
-                               exit(1);
+                       ret = test_dev_for_mkfs(file, force_overwrite);
+               else
+                       ret = test_status_for_mkfs(file, force_overwrite);
+
+               if (ret)
+                       goto error;
        }
 
        optind = saved_optind;
@@ -1602,7 +1638,7 @@ int main(int argc, char **argv)
                        if (metadata_profile != data_profile) {
                                error(
        "with mixed block groups data and metadata profiles must be the same");
-                               exit(1);
+                               goto error;
                        }
                }
 
@@ -1624,44 +1660,46 @@ int main(int argc, char **argv)
 
        if (btrfs_check_nodesize(nodesize, sectorsize,
                                 features))
-               exit(1);
+               goto error;
 
        if (sectorsize < sizeof(struct btrfs_super_block)) {
                error("sectorsize smaller than superblock: %u < %zu",
                                sectorsize, sizeof(struct btrfs_super_block));
-               exit(1);
+               goto error;
        }
 
+       min_dev_size = btrfs_min_dev_size(nodesize, mixed, metadata_profile,
+                                         data_profile);
        /* Check device/block_count after the nodesize is determined */
-       if (block_count && block_count < btrfs_min_dev_size(nodesize)) {
+       if (block_count && block_count < min_dev_size) {
                error("size %llu is too small to make a usable filesystem",
                        block_count);
                error("minimum size for btrfs filesystem is %llu",
-                       btrfs_min_dev_size(nodesize));
-               exit(1);
+                       min_dev_size);
+               goto error;
        }
        for (i = saved_optind; i < saved_optind + dev_cnt; i++) {
                char *path;
 
                path = argv[i];
-               ret = test_minimum_size(path, nodesize);
+               ret = test_minimum_size(path, min_dev_size);
                if (ret < 0) {
                        error("failed to check size for %s: %s",
                                path, strerror(-ret));
-                       exit (1);
+                       goto error;
                }
                if (ret > 0) {
                        error("'%s' is too small to make a usable filesystem",
                                path);
                        error("minimum size for each btrfs device is %llu",
-                               btrfs_min_dev_size(nodesize));
-                       exit(1);
+                               min_dev_size);
+                       goto error;
                }
        }
        ret = test_num_disk_vs_raid(metadata_profile, data_profile,
                        dev_cnt, mixed, ssd);
        if (ret)
-               exit(1);
+               goto error;
 
        dev_cnt--;
 
@@ -1674,7 +1712,7 @@ int main(int argc, char **argv)
                fd = open(file, O_RDWR);
                if (fd < 0) {
                        error("unable to open %s: %s", file, strerror(errno));
-                       exit(1);
+                       goto error;
                }
                ret = btrfs_prepare_device(fd, file, &dev_block_count,
                                block_count,
@@ -1682,22 +1720,21 @@ int main(int argc, char **argv)
                                (discard ? PREP_DEVICE_DISCARD : 0) |
                                (verbose ? PREP_DEVICE_VERBOSE : 0));
                if (ret) {
-                       close(fd);
-                       exit(1);
+                       goto error;
                }
                if (block_count && block_count > dev_block_count) {
                        error("%s is smaller than requested size, expected %llu, found %llu",
                                        file,
                                        (unsigned long long)block_count,
                                        (unsigned long long)dev_block_count);
-                       exit(1);
+                       goto error;
                }
        } else {
                fd = open(file, O_CREAT | O_RDWR,
                                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
                if (fd < 0) {
                        error("unable to open %s: %s", file, strerror(errno));
-                       exit(1);
+                       goto error;
                }
 
                source_dir_size = size_sourcedir(source_dir, sectorsize,
@@ -1707,7 +1744,7 @@ int main(int argc, char **argv)
                ret = zero_output_file(fd, block_count);
                if (ret) {
                        error("unable to zero the output file");
-                       exit(1);
+                       goto error;
                }
                /* our "device" is the new image file */
                dev_block_count = block_count;
@@ -1717,13 +1754,7 @@ int main(int argc, char **argv)
        if (dev_block_count < BTRFS_MKFS_SYSTEM_GROUP_SIZE) {
                error("device is too small to make filesystem, must be at least %llu",
                                (unsigned long long)BTRFS_MKFS_SYSTEM_GROUP_SIZE);
-               exit(1);
-       }
-
-       blocks[0] = BTRFS_SUPER_INFO_OFFSET;
-       for (i = 1; i < 7; i++) {
-               blocks[i] = BTRFS_SUPER_INFO_OFFSET + 1024 * 1024 +
-                       nodesize * i;
+               goto error;
        }
 
        if (group_profile_max_safe_loss(metadata_profile) <
@@ -1733,7 +1764,6 @@ int main(int argc, char **argv)
 
        mkfs_cfg.label = label;
        memcpy(mkfs_cfg.fs_uuid, fs_uuid, sizeof(mkfs_cfg.fs_uuid));
-       memcpy(mkfs_cfg.blocks, blocks, sizeof(blocks));
        mkfs_cfg.num_bytes = dev_block_count;
        mkfs_cfg.nodesize = nodesize;
        mkfs_cfg.sectorsize = sectorsize;
@@ -1743,41 +1773,42 @@ int main(int argc, char **argv)
        ret = make_btrfs(fd, &mkfs_cfg);
        if (ret) {
                error("error during mkfs: %s", strerror(-ret));
-               exit(1);
+               goto error;
        }
 
        fs_info = open_ctree_fs_info(file, 0, 0, 0,
                        OPEN_CTREE_WRITES | OPEN_CTREE_FS_PARTIAL);
        if (!fs_info) {
                error("open ctree failed");
-               close(fd);
-               exit(1);
+               goto error;
        }
+       close(fd);
+       fd = -1;
        root = fs_info->fs_root;
        fs_info->alloc_start = alloc_start;
 
        ret = create_metadata_block_groups(root, mixed, &allocation);
        if (ret) {
                error("failed to create default block groups: %d", ret);
-               exit(1);
+               goto error;
        }
 
        trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
+       if (IS_ERR(trans)) {
                error("failed to start transaction");
-               exit(1);
+               goto error;
        }
 
        ret = create_data_block_groups(trans, root, mixed, &allocation);
        if (ret) {
                error("failed to create default data block groups: %d", ret);
-               exit(1);
+               goto error;
        }
 
-       ret = make_root_dir(trans, root, &allocation);
+       ret = make_root_dir(trans, root);
        if (ret) {
                error("failed to setup the root directory: %d", ret);
-               exit(1);
+               goto error;
        }
 
        ret = btrfs_commit_transaction(trans, root);
@@ -1787,9 +1818,9 @@ int main(int argc, char **argv)
        }
 
        trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
+       if (IS_ERR(trans)) {
                error("failed to start transaction");
-               exit(1);
+               goto error;
        }
 
        if (dev_cnt == 0)
@@ -1806,7 +1837,7 @@ int main(int argc, char **argv)
                fd = open(file, O_RDWR);
                if (fd < 0) {
                        error("unable to open %s: %s", file, strerror(errno));
-                       exit(1);
+                       goto error;
                }
                ret = btrfs_device_already_in_root(root, fd,
                                                   BTRFS_SUPER_INFO_OFFSET);
@@ -1822,8 +1853,7 @@ int main(int argc, char **argv)
                                (zero_end ? PREP_DEVICE_ZERO_END : 0) |
                                (discard ? PREP_DEVICE_DISCARD : 0));
                if (ret) {
-                       close(fd);
-                       exit(1);
+                       goto error;
                }
 
                ret = btrfs_add_to_fsid(trans, root, fd, file, dev_block_count,
@@ -1852,7 +1882,7 @@ raid_groups:
                }
        }
 
-       ret = create_data_reloc_tree(trans, root);
+       ret = create_tree(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID);
        if (ret) {
                error("unable to create data reloc tree: %d", ret);
                goto out;
@@ -1866,6 +1896,7 @@ raid_groups:
 
        if (source_dir_set) {
                trans = btrfs_start_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
                ret = create_chunks(trans, root,
                                    num_of_meta_chunks, size_of_data,
                                    &allocation);
@@ -1879,7 +1910,7 @@ raid_groups:
                        goto out;
                }
 
-               ret = make_image(source_dir, root, fd);
+               ret = make_image(source_dir, root);
                if (ret) {
                        error("error wihle filling filesystem: %d", ret);
                        goto out;
@@ -1931,9 +1962,9 @@ raid_groups:
         */
        fs_info->finalize_on_close = 1;
 out:
-       ret = close_ctree(root);
+       close_ret = close_ctree(root);
 
-       if (!ret) {
+       if (!close_ret) {
                optind = saved_optind;
                dev_cnt = argc - optind;
                while (dev_cnt-- > 0) {
@@ -1947,4 +1978,12 @@ out:
        free(label);
 
        return !!ret;
+error:
+       if (fd > 0)
+               close(fd);
+
+       free(label);
+       exit(1);
+success:
+       exit(0);
 }