btrfs-progs: extent-tree: Introduce functions to free in-memory block group cache
[platform/upstream/btrfs-progs.git] / utils.c
diff --git a/utils.c b/utils.c
index 1783737..39b295a 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -177,9 +177,7 @@ int test_uuid_unique(char *fs_uuid)
 /*
  * @fs_uuid - if NULL, generates a UUID, returns back the new filesystem UUID
  */
-int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
-              u64 blocks[7], u64 num_bytes, u32 nodesize,
-              u32 sectorsize, u32 stripesize, u64 features)
+int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
 {
        struct btrfs_super_block super;
        struct extent_buffer *buf = NULL;
@@ -200,59 +198,61 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        u64 ref_root;
        u32 array_size;
        u32 item_size;
-       int skinny_metadata = !!(features &
+       int skinny_metadata = !!(cfg->features &
                                 BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA);
+       u64 num_bytes;
 
-       first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize * 2 - 1;
-       first_free &= ~((u64)sectorsize - 1);
+       first_free = BTRFS_SUPER_INFO_OFFSET + cfg->sectorsize * 2 - 1;
+       first_free &= ~((u64)cfg->sectorsize - 1);
 
        memset(&super, 0, sizeof(super));
 
-       num_bytes = (num_bytes / sectorsize) * sectorsize;
-       if (fs_uuid && *fs_uuid) {
-               if (uuid_parse(fs_uuid, super.fsid) != 0) {
-                       fprintf(stderr, "could not parse UUID: %s\n", fs_uuid);
+       num_bytes = (cfg->num_bytes / cfg->sectorsize) * cfg->sectorsize;
+       if (cfg->fs_uuid && *cfg->fs_uuid) {
+               if (uuid_parse(cfg->fs_uuid, super.fsid) != 0) {
+                       fprintf(stderr, "could not parse UUID: %s\n",
+                               cfg->fs_uuid);
                        ret = -EINVAL;
                        goto out;
                }
-               if (!test_uuid_unique(fs_uuid)) {
-                       fprintf(stderr, "non-unique UUID: %s\n", fs_uuid);
+               if (!test_uuid_unique(cfg->fs_uuid)) {
+                       fprintf(stderr, "non-unique UUID: %s\n", cfg->fs_uuid);
                        ret = -EBUSY;
                        goto out;
                }
        } else {
                uuid_generate(super.fsid);
-               if (fs_uuid)
-                       uuid_unparse(super.fsid, fs_uuid);
+               if (cfg->fs_uuid)
+                       uuid_unparse(super.fsid, cfg->fs_uuid);
        }
        uuid_generate(super.dev_item.uuid);
        uuid_generate(chunk_tree_uuid);
 
-       btrfs_set_super_bytenr(&super, blocks[0]);
+       btrfs_set_super_bytenr(&super, cfg->blocks[0]);
        btrfs_set_super_num_devices(&super, 1);
        btrfs_set_super_magic(&super, BTRFS_MAGIC);
        btrfs_set_super_generation(&super, 1);
-       btrfs_set_super_root(&super, blocks[1]);
-       btrfs_set_super_chunk_root(&super, blocks[3]);
+       btrfs_set_super_root(&super, cfg->blocks[1]);
+       btrfs_set_super_chunk_root(&super, cfg->blocks[3]);
        btrfs_set_super_total_bytes(&super, num_bytes);
-       btrfs_set_super_bytes_used(&super, 6 * nodesize);
-       btrfs_set_super_sectorsize(&super, sectorsize);
-       btrfs_set_super_leafsize(&super, nodesize);
-       btrfs_set_super_nodesize(&super, nodesize);
-       btrfs_set_super_stripesize(&super, stripesize);
+       btrfs_set_super_bytes_used(&super, 6 * cfg->nodesize);
+       btrfs_set_super_sectorsize(&super, cfg->sectorsize);
+       btrfs_set_super_leafsize(&super, cfg->nodesize);
+       btrfs_set_super_nodesize(&super, cfg->nodesize);
+       btrfs_set_super_stripesize(&super, cfg->stripesize);
        btrfs_set_super_csum_type(&super, BTRFS_CSUM_TYPE_CRC32);
        btrfs_set_super_chunk_root_generation(&super, 1);
        btrfs_set_super_cache_generation(&super, -1);
-       btrfs_set_super_incompat_flags(&super, features);
-       if (label)
-               strncpy(super.label, label, BTRFS_LABEL_SIZE - 1);
+       btrfs_set_super_incompat_flags(&super, cfg->features);
+       if (cfg->label)
+               strncpy(super.label, cfg->label, BTRFS_LABEL_SIZE - 1);
 
-       buf = malloc(sizeof(*buf) + max(sectorsize, nodesize));
+       buf = malloc(sizeof(*buf) + max(cfg->sectorsize, cfg->nodesize));
 
        /* create the tree of root objects */
-       memset(buf->data, 0, nodesize);
-       buf->len = nodesize;
-       btrfs_set_header_bytenr(buf, blocks[1]);
+       memset(buf->data, 0, cfg->nodesize);
+       buf->len = cfg->nodesize;
+       btrfs_set_header_bytenr(buf, cfg->blocks[1]);
        btrfs_set_header_nritems(buf, 4);
        btrfs_set_header_generation(buf, 1);
        btrfs_set_header_backref_rev(buf, BTRFS_MIXED_BACKREF_REV);
@@ -270,10 +270,10 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        btrfs_set_stack_inode_generation(inode_item, 1);
        btrfs_set_stack_inode_size(inode_item, 3);
        btrfs_set_stack_inode_nlink(inode_item, 1);
-       btrfs_set_stack_inode_nbytes(inode_item, nodesize);
+       btrfs_set_stack_inode_nbytes(inode_item, cfg->nodesize);
        btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
        btrfs_set_root_refs(&root_item, 1);
-       btrfs_set_root_used(&root_item, nodesize);
+       btrfs_set_root_used(&root_item, cfg->nodesize);
        btrfs_set_root_generation(&root_item, 1);
 
        memset(&disk_key, 0, sizeof(disk_key));
@@ -281,8 +281,8 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        btrfs_set_disk_key_offset(&disk_key, 0);
        nritems = 0;
 
-       itemoff = __BTRFS_LEAF_DATA_SIZE(nodesize) - sizeof(root_item);
-       btrfs_set_root_bytenr(&root_item, blocks[2]);
+       itemoff = __BTRFS_LEAF_DATA_SIZE(cfg->nodesize) - sizeof(root_item);
+       btrfs_set_root_bytenr(&root_item, cfg->blocks[2]);
        btrfs_set_disk_key_objectid(&disk_key, BTRFS_EXTENT_TREE_OBJECTID);
        btrfs_set_item_key(buf, &disk_key, nritems);
        btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
@@ -293,7 +293,7 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        nritems++;
 
        itemoff = itemoff - sizeof(root_item);
-       btrfs_set_root_bytenr(&root_item, blocks[4]);
+       btrfs_set_root_bytenr(&root_item, cfg->blocks[4]);
        btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_TREE_OBJECTID);
        btrfs_set_item_key(buf, &disk_key, nritems);
        btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
@@ -305,7 +305,7 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        nritems++;
 
        itemoff = itemoff - sizeof(root_item);
-       btrfs_set_root_bytenr(&root_item, blocks[5]);
+       btrfs_set_root_bytenr(&root_item, cfg->blocks[5]);
        btrfs_set_disk_key_objectid(&disk_key, BTRFS_FS_TREE_OBJECTID);
        btrfs_set_item_key(buf, &disk_key, nritems);
        btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
@@ -317,7 +317,7 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        nritems++;
 
        itemoff = itemoff - sizeof(root_item);
-       btrfs_set_root_bytenr(&root_item, blocks[6]);
+       btrfs_set_root_bytenr(&root_item, cfg->blocks[6]);
        btrfs_set_disk_key_objectid(&disk_key, BTRFS_CSUM_TREE_OBJECTID);
        btrfs_set_item_key(buf, &disk_key, nritems);
        btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff);
@@ -330,28 +330,28 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 
 
        csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, nodesize, blocks[1]);
-       if (ret != nodesize) {
+       ret = pwrite(fd, buf->data, cfg->nodesize, cfg->blocks[1]);
+       if (ret != cfg->nodesize) {
                ret = (ret < 0 ? -errno : -EIO);
                goto out;
        }
 
        /* create the items for the extent tree */
        memset(buf->data + sizeof(struct btrfs_header), 0,
-               nodesize - sizeof(struct btrfs_header));
+               cfg->nodesize - sizeof(struct btrfs_header));
        nritems = 0;
-       itemoff = __BTRFS_LEAF_DATA_SIZE(nodesize);
+       itemoff = __BTRFS_LEAF_DATA_SIZE(cfg->nodesize);
        for (i = 1; i < 7; i++) {
                item_size = sizeof(struct btrfs_extent_item);
                if (!skinny_metadata)
                        item_size += sizeof(struct btrfs_tree_block_info);
 
-               BUG_ON(blocks[i] < first_free);
-               BUG_ON(blocks[i] < blocks[i - 1]);
+               BUG_ON(cfg->blocks[i] < first_free);
+               BUG_ON(cfg->blocks[i] < cfg->blocks[i - 1]);
 
                /* create extent item */
                itemoff -= item_size;
-               btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
+               btrfs_set_disk_key_objectid(&disk_key, cfg->blocks[i]);
                if (skinny_metadata) {
                        btrfs_set_disk_key_type(&disk_key,
                                                BTRFS_METADATA_ITEM_KEY);
@@ -359,7 +359,7 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
                } else {
                        btrfs_set_disk_key_type(&disk_key,
                                                BTRFS_EXTENT_ITEM_KEY);
-                       btrfs_set_disk_key_offset(&disk_key, nodesize);
+                       btrfs_set_disk_key_offset(&disk_key, cfg->nodesize);
                }
                btrfs_set_item_key(buf, &disk_key, nritems);
                btrfs_set_item_offset(buf, btrfs_item_nr(nritems),
@@ -376,7 +376,7 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
 
                /* create extent ref */
                ref_root = reference_root_table[i];
-               btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
+               btrfs_set_disk_key_objectid(&disk_key, cfg->blocks[i]);
                btrfs_set_disk_key_offset(&disk_key, ref_root);
                btrfs_set_disk_key_type(&disk_key, BTRFS_TREE_BLOCK_REF_KEY);
                btrfs_set_item_key(buf, &disk_key, nritems);
@@ -385,22 +385,22 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
                btrfs_set_item_size(buf, btrfs_item_nr(nritems), 0);
                nritems++;
        }
-       btrfs_set_header_bytenr(buf, blocks[2]);
+       btrfs_set_header_bytenr(buf, cfg->blocks[2]);
        btrfs_set_header_owner(buf, BTRFS_EXTENT_TREE_OBJECTID);
        btrfs_set_header_nritems(buf, nritems);
        csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, nodesize, blocks[2]);
-       if (ret != nodesize) {
+       ret = pwrite(fd, buf->data, cfg->nodesize, cfg->blocks[2]);
+       if (ret != cfg->nodesize) {
                ret = (ret < 0 ? -errno : -EIO);
                goto out;
        }
 
        /* create the chunk tree */
        memset(buf->data + sizeof(struct btrfs_header), 0,
-               nodesize - sizeof(struct btrfs_header));
+               cfg->nodesize - sizeof(struct btrfs_header));
        nritems = 0;
        item_size = sizeof(*dev_item);
-       itemoff = __BTRFS_LEAF_DATA_SIZE(nodesize) - item_size;
+       itemoff = __BTRFS_LEAF_DATA_SIZE(cfg->nodesize) - item_size;
 
        /* first device 1 (there is no device 0) */
        btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_ITEMS_OBJECTID);
@@ -416,9 +416,9 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        btrfs_set_device_total_bytes(buf, dev_item, num_bytes);
        btrfs_set_device_bytes_used(buf, dev_item,
                                    BTRFS_MKFS_SYSTEM_GROUP_SIZE);
-       btrfs_set_device_io_align(buf, dev_item, sectorsize);
-       btrfs_set_device_io_width(buf, dev_item, sectorsize);
-       btrfs_set_device_sector_size(buf, dev_item, sectorsize);
+       btrfs_set_device_io_align(buf, dev_item, cfg->sectorsize);
+       btrfs_set_device_io_width(buf, dev_item, cfg->sectorsize);
+       btrfs_set_device_sector_size(buf, dev_item, cfg->sectorsize);
        btrfs_set_device_type(buf, dev_item, 0);
 
        write_extent_buffer(buf, super.dev_item.uuid,
@@ -447,9 +447,9 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        btrfs_set_chunk_owner(buf, chunk, BTRFS_EXTENT_TREE_OBJECTID);
        btrfs_set_chunk_stripe_len(buf, chunk, 64 * 1024);
        btrfs_set_chunk_type(buf, chunk, BTRFS_BLOCK_GROUP_SYSTEM);
-       btrfs_set_chunk_io_align(buf, chunk, sectorsize);
-       btrfs_set_chunk_io_width(buf, chunk, sectorsize);
-       btrfs_set_chunk_sector_size(buf, chunk, sectorsize);
+       btrfs_set_chunk_io_align(buf, chunk, cfg->sectorsize);
+       btrfs_set_chunk_io_width(buf, chunk, cfg->sectorsize);
+       btrfs_set_chunk_sector_size(buf, chunk, cfg->sectorsize);
        btrfs_set_chunk_num_stripes(buf, chunk, 1);
        btrfs_set_stripe_devid_nr(buf, chunk, 0, 1);
        btrfs_set_stripe_offset_nr(buf, chunk, 0, 0);
@@ -472,21 +472,21 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
        ptr += item_size;
        btrfs_set_super_sys_array_size(&super, array_size);
 
-       btrfs_set_header_bytenr(buf, blocks[3]);
+       btrfs_set_header_bytenr(buf, cfg->blocks[3]);
        btrfs_set_header_owner(buf, BTRFS_CHUNK_TREE_OBJECTID);
        btrfs_set_header_nritems(buf, nritems);
        csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, nodesize, blocks[3]);
-       if (ret != nodesize) {
+       ret = pwrite(fd, buf->data, cfg->nodesize, cfg->blocks[3]);
+       if (ret != cfg->nodesize) {
                ret = (ret < 0 ? -errno : -EIO);
                goto out;
        }
 
        /* create the device tree */
        memset(buf->data + sizeof(struct btrfs_header), 0,
-               nodesize - sizeof(struct btrfs_header));
+               cfg->nodesize - sizeof(struct btrfs_header));
        nritems = 0;
-       itemoff = __BTRFS_LEAF_DATA_SIZE(nodesize) -
+       itemoff = __BTRFS_LEAF_DATA_SIZE(cfg->nodesize) -
                sizeof(struct btrfs_dev_extent);
 
        btrfs_set_disk_key_objectid(&disk_key, 1);
@@ -511,49 +511,49 @@ int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid,
                                    BTRFS_MKFS_SYSTEM_GROUP_SIZE);
        nritems++;
 
-       btrfs_set_header_bytenr(buf, blocks[4]);
+       btrfs_set_header_bytenr(buf, cfg->blocks[4]);
        btrfs_set_header_owner(buf, BTRFS_DEV_TREE_OBJECTID);
        btrfs_set_header_nritems(buf, nritems);
        csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, nodesize, blocks[4]);
-       if (ret != nodesize) {
+       ret = pwrite(fd, buf->data, cfg->nodesize, cfg->blocks[4]);
+       if (ret != cfg->nodesize) {
                ret = (ret < 0 ? -errno : -EIO);
                goto out;
        }
 
        /* create the FS root */
        memset(buf->data + sizeof(struct btrfs_header), 0,
-               nodesize - sizeof(struct btrfs_header));
-       btrfs_set_header_bytenr(buf, blocks[5]);
+               cfg->nodesize - sizeof(struct btrfs_header));
+       btrfs_set_header_bytenr(buf, cfg->blocks[5]);
        btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID);
        btrfs_set_header_nritems(buf, 0);
        csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, nodesize, blocks[5]);
-       if (ret != nodesize) {
+       ret = pwrite(fd, buf->data, cfg->nodesize, cfg->blocks[5]);
+       if (ret != cfg->nodesize) {
                ret = (ret < 0 ? -errno : -EIO);
                goto out;
        }
        /* finally create the csum root */
        memset(buf->data + sizeof(struct btrfs_header), 0,
-               nodesize - sizeof(struct btrfs_header));
-       btrfs_set_header_bytenr(buf, blocks[6]);
+               cfg->nodesize - sizeof(struct btrfs_header));
+       btrfs_set_header_bytenr(buf, cfg->blocks[6]);
        btrfs_set_header_owner(buf, BTRFS_CSUM_TREE_OBJECTID);
        btrfs_set_header_nritems(buf, 0);
        csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, nodesize, blocks[6]);
-       if (ret != nodesize) {
+       ret = pwrite(fd, buf->data, cfg->nodesize, cfg->blocks[6]);
+       if (ret != cfg->nodesize) {
                ret = (ret < 0 ? -errno : -EIO);
                goto out;
        }
 
        /* and write out the super block */
-       BUG_ON(sizeof(super) > sectorsize);
-       memset(buf->data, 0, sectorsize);
+       BUG_ON(sizeof(super) > cfg->sectorsize);
+       memset(buf->data, 0, cfg->sectorsize);
        memcpy(buf->data, &super, sizeof(super));
-       buf->len = sectorsize;
+       buf->len = cfg->sectorsize;
        csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, sectorsize, blocks[0]);
-       if (ret != sectorsize) {
+       ret = pwrite(fd, buf->data, cfg->sectorsize, cfg->blocks[0]);
+       if (ret != cfg->sectorsize) {
                ret = (ret < 0 ? -errno : -EIO);
                goto out;
        }
@@ -1060,7 +1060,7 @@ out:
  */
 int open_path_or_dev_mnt(const char *path, DIR **dirstream)
 {
-       char mp[BTRFS_PATH_NAME_MAX + 1];
+       char mp[PATH_MAX];
        int fdmnt;
 
        if (is_block_device(path)) {
@@ -1409,8 +1409,8 @@ int btrfs_register_one_device(const char *fname)
                        strerror(errno));
                return -errno;
        }
-       strncpy(args.name, fname, BTRFS_PATH_NAME_MAX);
-       args.name[BTRFS_PATH_NAME_MAX-1] = 0;
+       memset(&args, 0, sizeof(args));
+       strncpy_null(args.name, fname);
        ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args);
        e = errno;
        if (ret < 0) {
@@ -1479,6 +1479,24 @@ out:
        return ret;
 }
 
+/*
+ * Note: this function uses a static per-thread buffer. Do not call this
+ * function more than 10 times within one argument list!
+ */
+const char *pretty_size_mode(u64 size, unsigned mode)
+{
+       static __thread int ps_index = 0;
+       static __thread char ps_array[10][32];
+       char *ret;
+
+       ret = ps_array[ps_index];
+       ps_index++;
+       ps_index %= 10;
+       (void)pretty_size_snprintf(size, ret, 32, mode);
+
+       return ret;
+}
+
 static const char* unit_suffix_binary[] =
        { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
 static const char* unit_suffix_decimal[] =
@@ -1915,8 +1933,10 @@ int open_file_or_dir3(const char *fname, DIR **dirstream, int open_flags)
        }
        if (fd < 0) {
                fd = -1;
-               if (*dirstream)
+               if (*dirstream) {
                        closedir(*dirstream);
+                       *dirstream = NULL;
+               }
        }
        return fd;
 }
@@ -2036,7 +2056,7 @@ int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
        struct btrfs_fs_devices *fs_devices_mnt = NULL;
        struct btrfs_ioctl_dev_info_args *di_args;
        struct btrfs_ioctl_dev_info_args tmp;
-       char mp[BTRFS_PATH_NAME_MAX + 1];
+       char mp[PATH_MAX];
        DIR *dirstream = NULL;
 
        memset(fi_args, 0, sizeof(*fi_args));
@@ -2327,9 +2347,8 @@ static int group_profile_devs_min(u64 flag)
 }
 
 int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile,
-       u64 dev_cnt, int mixed, char *estr)
+       u64 dev_cnt, int mixed)
 {
-       size_t sz = 100;
        u64 allowed = 0;
 
        switch (dev_cnt) {
@@ -2348,21 +2367,21 @@ int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile,
 
        if (dev_cnt > 1 &&
            ((metadata_profile | data_profile) & BTRFS_BLOCK_GROUP_DUP)) {
-               snprintf(estr, sz,
-                       "DUP is not allowed when FS has multiple devices\n");
+               fprintf(stderr,
+                   "ERROR: DUP is not allowed when FS has multiple devices\n");
                return 1;
        }
        if (metadata_profile & ~allowed) {
-               snprintf(estr, sz,
-                       "unable to create FS with metadata profile %s "
+               fprintf(stderr,
+                       "ERROR: unable to create FS with metadata profile %s "
                        "(have %llu devices but %d devices are required)\n",
                        btrfs_group_profile_str(metadata_profile), dev_cnt,
                        group_profile_devs_min(metadata_profile));
                return 1;
        }
        if (data_profile & ~allowed) {
-               snprintf(estr, sz,
-                       "unable to create FS with data profile %s "
+               fprintf(stderr,
+                       "ERROR: unable to create FS with data profile %s "
                        "(have %llu devices but %d devices are required)\n",
                        btrfs_group_profile_str(data_profile), dev_cnt,
                        group_profile_devs_min(data_profile));
@@ -2370,8 +2389,8 @@ int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile,
        }
 
        if (!mixed && (data_profile & BTRFS_BLOCK_GROUP_DUP)) {
-               snprintf(estr, sz,
-                       "dup for data is allowed only in mixed mode");
+               fprintf(stderr,
+                       "ERROR: DUP for data is allowed only in mixed mode");
                return 1;
        }
        return 0;
@@ -2395,58 +2414,58 @@ int group_profile_max_safe_loss(u64 flags)
        }
 }
 
-/* Check if disk is suitable for btrfs
+/*
+ * Check if a device is suitable for btrfs
  * returns:
- *  1: something is wrong, estr provides the error
+ *  1: something is wrong, an error is printed
  *  0: all is fine
  */
-int test_dev_for_mkfs(char *file, int force_overwrite, char *estr)
+int test_dev_for_mkfs(char *file, int force_overwrite)
 {
        int ret, fd;
-       size_t sz = 100;
        struct stat st;
 
        ret = is_swap_device(file);
        if (ret < 0) {
-               snprintf(estr, sz, "error checking %s status: %s\n", file,
+               fprintf(stderr, "ERROR: checking status of %s: %s\n", file,
                        strerror(-ret));
                return 1;
        }
        if (ret == 1) {
-               snprintf(estr, sz, "%s is a swap device\n", file);
+               fprintf(stderr, "ERROR: %s is a swap device\n", file);
                return 1;
        }
        if (!force_overwrite) {
                if (check_overwrite(file)) {
-                       snprintf(estr, sz, "Use the -f option to force overwrite.\n");
+                       fprintf(stderr, "Use the -f option to force overwrite.\n");
                        return 1;
                }
        }
        ret = check_mounted(file);
        if (ret < 0) {
-               snprintf(estr, sz, "error checking %s mount status\n",
-                       file);
+               fprintf(stderr, "ERROR: checking mount status of %s: %s\n",
+                       file, strerror(-ret));
                return 1;
        }
        if (ret == 1) {
-               snprintf(estr, sz, "%s is mounted\n", file);
+               fprintf(stderr, "ERROR: %s is mounted\n", file);
                return 1;
        }
        /* check if the device is busy */
        fd = open(file, O_RDWR|O_EXCL);
        if (fd < 0) {
-               snprintf(estr, sz, "unable to open %s: %s\n", file,
+               fprintf(stderr, "ERROR: unable to open %s: %s\n", file,
                        strerror(errno));
                return 1;
        }
        if (fstat(fd, &st)) {
-               snprintf(estr, sz, "unable to stat %s: %s\n", file,
+               fprintf(stderr, "ERROR: unable to stat %s: %s\n", file,
                        strerror(errno));
                close(fd);
                return 1;
        }
        if (!S_ISBLK(st.st_mode)) {
-               fprintf(stderr, "'%s' is not a block device\n", file);
+               fprintf(stderr, "ERROR: %s is not a block device\n", file);
                close(fd);
                return 1;
        }
@@ -2852,3 +2871,22 @@ int btrfs_check_nodesize(u32 nodesize, u32 sectorsize)
        }
        return 0;
 }
+
+/*
+ * Copy a path argument from SRC to DEST and check the SRC length if it's at
+ * most PATH_MAX and fits into DEST. DESTLEN is supposed to be exact size of
+ * the buffer.
+ * The destination buffer is zero terminated.
+ * Return < 0 for error, 0 otherwise.
+ */
+int arg_copy_path(char *dest, const char *src, int destlen)
+{
+       size_t len = strlen(src);
+
+       if (len >= PATH_MAX || len >= destlen)
+               return -ENAMETOOLONG;
+
+       __strncpy__null(dest, src, destlen);
+
+       return 0;
+}