btrfs-progs: check: fix missing newlines
[platform/upstream/btrfs-progs.git] / btrfs-convert.c
index fbe911f..4b4cea4 100644 (file)
 #include "utils.h"
 #include "task-utils.h"
 
+#if BTRFSCONVERT_EXT2
 #include <ext2fs/ext2_fs.h>
 #include <ext2fs/ext2fs.h>
 #include <ext2fs/ext2_ext_attr.h>
 
 #define INO_OFFSET (BTRFS_FIRST_FREE_OBJECTID - EXT2_ROOT_INO)
-#define CONV_IMAGE_SUBVOL_OBJECTID BTRFS_FIRST_FREE_OBJECTID
 
 /*
  * Compatibility code for e2fsprogs 1.41 which doesn't support RO compat flag
 #define EXT2FS_B2C(fs, blk)            (blk)
 #endif
 
+#endif
+
+#define CONV_IMAGE_SUBVOL_OBJECTID BTRFS_FIRST_FREE_OBJECTID
+
 struct task_ctx {
        uint32_t max_copy_inodes;
        uint32_t cur_copy_inodes;
@@ -99,6 +103,7 @@ struct btrfs_convert_operations {
                         struct btrfs_root *root, int datacsum,
                         int packing, int noxattr, struct task_ctx *p);
        void (*close_fs)(struct btrfs_convert_context *cctx);
+       int (*check_state)(struct btrfs_convert_context *cctx);
 };
 
 static void init_convert_context(struct btrfs_convert_context *cctx)
@@ -128,6 +133,11 @@ static inline void convert_close_fs(struct btrfs_convert_context *cctx)
        cctx->convert_ops->close_fs(cctx);
 }
 
+static inline int convert_check_state(struct btrfs_convert_context *cctx)
+{
+       return cctx->convert_ops->check_state(cctx);
+}
+
 static int intersect_with_sb(u64 bytenr, u64 num_bytes)
 {
        int i;
@@ -273,7 +283,7 @@ static int record_file_blocks(struct blk_iterate_data *data,
        int ret = 0;
        struct btrfs_root *root = data->root;
        struct btrfs_root *convert_root = data->convert_root;
-       struct btrfs_path *path;
+       struct btrfs_path path;
        u64 file_pos = file_block * root->sectorsize;
        u64 old_disk_bytenr = disk_block * root->sectorsize;
        u64 num_bytes = num_blocks * root->sectorsize;
@@ -285,9 +295,7 @@ static int record_file_blocks(struct blk_iterate_data *data,
                                data->objectid, data->inode, file_pos, 0,
                                num_bytes);
 
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
+       btrfs_init_path(&path);
 
        /*
         * Search real disk bytenr from convert root
@@ -306,11 +314,11 @@ static int record_file_blocks(struct blk_iterate_data *data,
                key.type = BTRFS_EXTENT_DATA_KEY;
                key.offset = cur_off;
 
-               ret = btrfs_search_slot(NULL, convert_root, &key, path, 0, 0);
+               ret = btrfs_search_slot(NULL, convert_root, &key, &path, 0, 0);
                if (ret < 0)
                        break;
                if (ret > 0) {
-                       ret = btrfs_previous_item(convert_root, path,
+                       ret = btrfs_previous_item(convert_root, &path,
                                                  data->convert_ino,
                                                  BTRFS_EXTENT_DATA_KEY);
                        if (ret < 0)
@@ -320,8 +328,8 @@ static int record_file_blocks(struct blk_iterate_data *data,
                                break;
                        }
                }
-               node = path->nodes[0];
-               slot = path->slots[0];
+               node = path.nodes[0];
+               slot = path.slots[0];
                btrfs_item_key_to_cpu(node, &key, slot);
                BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY ||
                       key.objectid != data->convert_ino ||
@@ -330,7 +338,7 @@ static int record_file_blocks(struct blk_iterate_data *data,
                extent_disk_bytenr = btrfs_file_extent_disk_bytenr(node, fi);
                extent_num_bytes = btrfs_file_extent_disk_num_bytes(node, fi);
                BUG_ON(cur_off - key.offset >= extent_num_bytes);
-               btrfs_release_path(path);
+               btrfs_release_path(&path);
 
                if (extent_disk_bytenr)
                        real_disk_bytenr = cur_off - key.offset +
@@ -353,7 +361,7 @@ static int record_file_blocks(struct blk_iterate_data *data,
                 * need to waste CPU cycles now.
                 */
        }
-       btrfs_free_path(path);
+       btrfs_release_path(&path);
        return ret;
 }
 
@@ -420,8 +428,16 @@ static int create_image_file_range(struct btrfs_trans_handle *trans,
        int i;
        int ret;
 
-       BUG_ON(bytenr != round_down(bytenr, root->sectorsize));
-       BUG_ON(len != round_down(len, root->sectorsize));
+       if (bytenr != round_down(bytenr, root->sectorsize)) {
+               error("bytenr not sectorsize aligned: %llu",
+                               (unsigned long long)bytenr);
+               return -EINVAL;
+       }
+       if (len != round_down(len, root->sectorsize)) {
+               error("length not sectorsize aligned: %llu",
+                               (unsigned long long)len);
+               return -EINVAL;
+       }
        len = min_t(u64, len, BTRFS_MAX_EXTENT_SIZE);
 
        /*
@@ -510,7 +526,11 @@ static int create_image_file_range(struct btrfs_trans_handle *trans,
                            bg_cache->key.offset - bytenr);
        }
 
-       BUG_ON(len != round_down(len, root->sectorsize));
+       if (len != round_down(len, root->sectorsize)) {
+               error("remaining length not sectorsize aligned: %llu",
+                               (unsigned long long)len);
+               return -EINVAL;
+       }
        ret = btrfs_record_file_extent(trans, root, ino, inode, bytenr,
                                       disk_bytenr, len);
        if (ret < 0)
@@ -948,7 +968,7 @@ static int create_image(struct btrfs_root *root,
 {
        struct btrfs_inode_item buf;
        struct btrfs_trans_handle *trans;
-       struct btrfs_path *path = NULL;
+       struct btrfs_path path;
        struct btrfs_key key;
        struct cache_extent *cache;
        struct cache_tree used_tmp;
@@ -965,6 +985,7 @@ static int create_image(struct btrfs_root *root,
                return -ENOMEM;
 
        cache_tree_init(&used_tmp);
+       btrfs_init_path(&path);
 
        ret = btrfs_find_free_objectid(trans, root, BTRFS_FIRST_FREE_OBJECTID,
                                       &ino);
@@ -981,24 +1002,19 @@ static int create_image(struct btrfs_root *root,
        if (ret < 0)
                goto out;
 
-       path = btrfs_alloc_path();
-       if (!path) {
-               ret = -ENOMEM;
-               goto out;
-       }
        key.objectid = ino;
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
 
-       ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+       ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
        if (ret) {
                ret = (ret > 0 ? -ENOENT : ret);
                goto out;
        }
-       read_extent_buffer(path->nodes[0], &buf,
-                       btrfs_item_ptr_offset(path->nodes[0], path->slots[0]),
+       read_extent_buffer(path.nodes[0], &buf,
+                       btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
                        sizeof(buf));
-       btrfs_release_path(path);
+       btrfs_release_path(&path);
 
        /*
         * Create a new used space cache, which doesn't contain the reserved
@@ -1036,18 +1052,18 @@ static int create_image(struct btrfs_root *root,
        key.objectid = ino;
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
-       ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+       ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
        if (ret) {
                ret = (ret > 0 ? -ENOENT : ret);
                goto out;
        }
        btrfs_set_stack_inode_size(&buf, cfg->num_bytes);
-       write_extent_buffer(path->nodes[0], &buf,
-                       btrfs_item_ptr_offset(path->nodes[0], path->slots[0]),
+       write_extent_buffer(path.nodes[0], &buf,
+                       btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
                        sizeof(buf));
 out:
        free_extent_cache_tree(&used_tmp);
-       btrfs_free_path(path);
+       btrfs_release_path(&path);
        btrfs_commit_transaction(trans, root);
        return ret;
 }
@@ -1059,7 +1075,7 @@ static struct btrfs_root* link_subvol(struct btrfs_root *root,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_root *tree_root = fs_info->tree_root;
        struct btrfs_root *new_root = NULL;
-       struct btrfs_path *path;
+       struct btrfs_path path;
        struct btrfs_inode_item *inode_item;
        struct extent_buffer *leaf;
        struct btrfs_key key;
@@ -1074,35 +1090,44 @@ static struct btrfs_root* link_subvol(struct btrfs_root *root,
        if (len == 0 || len > BTRFS_NAME_LEN)
                return NULL;
 
-       path = btrfs_alloc_path();
-       BUG_ON(!path);
-
+       btrfs_init_path(&path);
        key.objectid = dirid;
        key.type = BTRFS_DIR_INDEX_KEY;
        key.offset = (u64)-1;
 
-       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-       BUG_ON(ret <= 0);
+       ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+       if (ret <= 0) {
+               error("search for DIR_INDEX dirid %llu failed: %d",
+                               (unsigned long long)dirid, ret);
+               goto fail;
+       }
 
-       if (path->slots[0] > 0) {
-               path->slots[0]--;
-               btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+       if (path.slots[0] > 0) {
+               path.slots[0]--;
+               btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
                if (key.objectid == dirid && key.type == BTRFS_DIR_INDEX_KEY)
                        index = key.offset + 1;
        }
-       btrfs_release_path(path);
+       btrfs_release_path(&path);
 
        trans = btrfs_start_transaction(root, 1);
-       BUG_ON(!trans);
+       if (!trans) {
+               error("unable to start transaction");
+               goto fail;
+       }
 
        key.objectid = dirid;
        key.offset = 0;
        key.type =  BTRFS_INODE_ITEM_KEY;
 
-       ret = btrfs_lookup_inode(trans, root, path, &key, 1);
-       BUG_ON(ret);
-       leaf = path->nodes[0];
-       inode_item = btrfs_item_ptr(leaf, path->slots[0],
+       ret = btrfs_lookup_inode(trans, root, &path, &key, 1);
+       if (ret) {
+               error("search for INODE_ITEM %llu failed: %d",
+                               (unsigned long long)dirid, ret);
+               goto fail;
+       }
+       leaf = path.nodes[0];
+       inode_item = btrfs_item_ptr(leaf, path.slots[0],
                                    struct btrfs_inode_item);
 
        key.objectid = root_objectid;
@@ -1127,28 +1152,42 @@ static struct btrfs_root* link_subvol(struct btrfs_root *root,
        btrfs_set_inode_size(leaf, inode_item, len * 2 +
                             btrfs_inode_size(leaf, inode_item));
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(path);
+       btrfs_release_path(&path);
 
        /* add the backref first */
        ret = btrfs_add_root_ref(trans, tree_root, root_objectid,
                                 BTRFS_ROOT_BACKREF_KEY,
                                 root->root_key.objectid,
                                 dirid, index, buf, len);
-       BUG_ON(ret);
+       if (ret) {
+               error("unable to add root backref for %llu: %d",
+                               root->root_key.objectid, ret);
+               goto fail;
+       }
 
        /* now add the forward ref */
        ret = btrfs_add_root_ref(trans, tree_root, root->root_key.objectid,
                                 BTRFS_ROOT_REF_KEY, root_objectid,
                                 dirid, index, buf, len);
+       if (ret) {
+               error("unable to add root ref for %llu: %d",
+                               root->root_key.objectid, ret);
+               goto fail;
+       }
 
        ret = btrfs_commit_transaction(trans, root);
-       BUG_ON(ret);
+       if (ret) {
+               error("transaction commit failed: %d", ret);
+               goto fail;
+       }
 
        new_root = btrfs_read_fs_root(fs_info, &key);
-       if (IS_ERR(new_root))
+       if (IS_ERR(new_root)) {
+               error("unable to fs read root: %lu", PTR_ERR(new_root));
                new_root = NULL;
+       }
 fail:
-       btrfs_free_path(path);
+       btrfs_init_path(&path);
        return new_root;
 }
 
@@ -1163,7 +1202,8 @@ static int create_subvol(struct btrfs_trans_handle *trans,
 
        ret = btrfs_copy_root(trans, root, root->node, &tmp,
                              root_objectid);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        memcpy(&root_item, &root->root_item, sizeof(root_item));
        btrfs_set_root_bytenr(&root_item, tmp->start);
@@ -1179,12 +1219,14 @@ static int create_subvol(struct btrfs_trans_handle *trans,
 
        key.offset = (u64)-1;
        new_root = btrfs_read_fs_root(root->fs_info, &key);
-       BUG_ON(!new_root || IS_ERR(new_root));
+       if (!new_root || IS_ERR(new_root)) {
+               error("unable to fs read root: %lu", PTR_ERR(new_root));
+               return PTR_ERR(new_root);
+       }
 
        ret = btrfs_make_root_dir(trans, new_root, BTRFS_FIRST_FREE_OBJECTID);
-       BUG_ON(ret);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -1238,6 +1280,170 @@ static int make_convert_data_block_groups(struct btrfs_trans_handle *trans,
 }
 
 /*
+ * Init the temp btrfs to a operational status.
+ *
+ * It will fix the extent usage accounting(XXX: Do we really need?) and
+ * insert needed data chunks, to ensure all old fs data extents are covered
+ * by DATA chunks, preventing wrong chunks are allocated.
+ *
+ * And also create convert image subvolume and relocation tree.
+ * (XXX: Not need again?)
+ * But the convert image subvolume is *NOT* linked to fs tree yet.
+ */
+static int init_btrfs(struct btrfs_mkfs_config *cfg, struct btrfs_root *root,
+                        struct btrfs_convert_context *cctx, int datacsum,
+                        int packing, int noxattr)
+{
+       struct btrfs_key location;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       int ret;
+
+       /*
+        * Don't alloc any metadata/system chunk, as we don't want
+        * any meta/sys chunk allcated before all data chunks are inserted.
+        * Or we screw up the chunk layout just like the old implement.
+        */
+       fs_info->avoid_sys_chunk_alloc = 1;
+       fs_info->avoid_meta_chunk_alloc = 1;
+       trans = btrfs_start_transaction(root, 1);
+       if (!trans) {
+               error("unable to start transaction");
+               ret = -EINVAL;
+               goto err;
+       }
+       ret = btrfs_fix_block_accounting(trans, root);
+       if (ret)
+               goto err;
+       ret = make_convert_data_block_groups(trans, fs_info, cfg, cctx);
+       if (ret)
+               goto err;
+       ret = btrfs_make_root_dir(trans, fs_info->tree_root,
+                                 BTRFS_ROOT_TREE_DIR_OBJECTID);
+       if (ret)
+               goto err;
+       memcpy(&location, &root->root_key, sizeof(location));
+       location.offset = (u64)-1;
+       ret = btrfs_insert_dir_item(trans, fs_info->tree_root, "default", 7,
+                               btrfs_super_root_dir(fs_info->super_copy),
+                               &location, BTRFS_FT_DIR, 0);
+       if (ret)
+               goto err;
+       ret = btrfs_insert_inode_ref(trans, fs_info->tree_root, "default", 7,
+                               location.objectid,
+                               btrfs_super_root_dir(fs_info->super_copy), 0);
+       if (ret)
+               goto err;
+       btrfs_set_root_dirid(&fs_info->fs_root->root_item,
+                            BTRFS_FIRST_FREE_OBJECTID);
+
+       /* subvol for fs image file */
+       ret = create_subvol(trans, root, CONV_IMAGE_SUBVOL_OBJECTID);
+       if (ret < 0) {
+               error("failed to create subvolume image root: %d", ret);
+               goto err;
+       }
+       /* subvol for data relocation tree */
+       ret = create_subvol(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID);
+       if (ret < 0) {
+               error("failed to create DATA_RELOC root: %d", ret);
+               goto err;
+       }
+
+       ret = btrfs_commit_transaction(trans, root);
+       fs_info->avoid_sys_chunk_alloc = 0;
+       fs_info->avoid_meta_chunk_alloc = 0;
+err:
+       return ret;
+}
+
+/*
+ * Migrate super block to its default position and zero 0 ~ 16k
+ */
+static int migrate_super_block(int fd, u64 old_bytenr, u32 sectorsize)
+{
+       int ret;
+       struct extent_buffer *buf;
+       struct btrfs_super_block *super;
+       u32 len;
+       u32 bytenr;
+
+       buf = malloc(sizeof(*buf) + sectorsize);
+       if (!buf)
+               return -ENOMEM;
+
+       buf->len = sectorsize;
+       ret = pread(fd, buf->data, sectorsize, old_bytenr);
+       if (ret != sectorsize)
+               goto fail;
+
+       super = (struct btrfs_super_block *)buf->data;
+       BUG_ON(btrfs_super_bytenr(super) != old_bytenr);
+       btrfs_set_super_bytenr(super, BTRFS_SUPER_INFO_OFFSET);
+
+       csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
+       ret = pwrite(fd, buf->data, sectorsize, BTRFS_SUPER_INFO_OFFSET);
+       if (ret != sectorsize)
+               goto fail;
+
+       ret = fsync(fd);
+       if (ret)
+               goto fail;
+
+       memset(buf->data, 0, sectorsize);
+       for (bytenr = 0; bytenr < BTRFS_SUPER_INFO_OFFSET; ) {
+               len = BTRFS_SUPER_INFO_OFFSET - bytenr;
+               if (len > sectorsize)
+                       len = sectorsize;
+               ret = pwrite(fd, buf->data, len, bytenr);
+               if (ret != len) {
+                       fprintf(stderr, "unable to zero fill device\n");
+                       break;
+               }
+               bytenr += len;
+       }
+       ret = 0;
+       fsync(fd);
+fail:
+       free(buf);
+       if (ret > 0)
+               ret = -1;
+       return ret;
+}
+
+static int prepare_system_chunk_sb(struct btrfs_super_block *super)
+{
+       struct btrfs_chunk *chunk;
+       struct btrfs_disk_key *key;
+       u32 sectorsize = btrfs_super_sectorsize(super);
+
+       key = (struct btrfs_disk_key *)(super->sys_chunk_array);
+       chunk = (struct btrfs_chunk *)(super->sys_chunk_array +
+                                      sizeof(struct btrfs_disk_key));
+
+       btrfs_set_disk_key_objectid(key, BTRFS_FIRST_CHUNK_TREE_OBJECTID);
+       btrfs_set_disk_key_type(key, BTRFS_CHUNK_ITEM_KEY);
+       btrfs_set_disk_key_offset(key, 0);
+
+       btrfs_set_stack_chunk_length(chunk, btrfs_super_total_bytes(super));
+       btrfs_set_stack_chunk_owner(chunk, BTRFS_EXTENT_TREE_OBJECTID);
+       btrfs_set_stack_chunk_stripe_len(chunk, BTRFS_STRIPE_LEN);
+       btrfs_set_stack_chunk_type(chunk, BTRFS_BLOCK_GROUP_SYSTEM);
+       btrfs_set_stack_chunk_io_align(chunk, sectorsize);
+       btrfs_set_stack_chunk_io_width(chunk, sectorsize);
+       btrfs_set_stack_chunk_sector_size(chunk, sectorsize);
+       btrfs_set_stack_chunk_num_stripes(chunk, 1);
+       btrfs_set_stack_chunk_sub_stripes(chunk, 0);
+       chunk->stripe.devid = super->dev_item.devid;
+       btrfs_set_stack_stripe_offset(&chunk->stripe, 0);
+       memcpy(chunk->stripe.dev_uuid, super->dev_item.uuid, BTRFS_UUID_SIZE);
+       btrfs_set_super_sys_array_size(super, sizeof(*key) + sizeof(*chunk));
+       return 0;
+}
+
+#if BTRFSCONVERT_EXT2
+
+/*
  * Open Ext2fs in readonly mode, read block allocation bitmap and
  * inode bitmap into memory.
  */
@@ -1290,7 +1496,7 @@ static int ext2_open_fs(struct btrfs_convert_context *cctx, const char *name)
 
        if (!(ext2_fs->super->s_feature_incompat &
              EXT2_FEATURE_INCOMPAT_FILETYPE)) {
-               fprintf(stderr, "filetype feature is missing\n");
+               error("filetype feature is missing");
                goto fail;
        }
 
@@ -1974,6 +2180,42 @@ static void ext2_copy_inode_item(struct btrfs_inode_item *dst,
        }
        memset(&dst->reserved, 0, sizeof(dst->reserved));
 }
+static int ext2_check_state(struct btrfs_convert_context *cctx)
+{
+       ext2_filsys fs = cctx->fs_data;
+
+        if (!(fs->super->s_state & EXT2_VALID_FS))
+               return 1;
+       else if (fs->super->s_state & EXT2_ERROR_FS)
+               return 1;
+       else
+               return 0;
+}
+
+/* EXT2_*_FL to BTRFS_INODE_FLAG_* stringification helper */
+#define COPY_ONE_EXT2_FLAG(flags, ext2_inode, name) ({                 \
+       if (ext2_inode->i_flags & EXT2_##name##_FL)                     \
+               flags |= BTRFS_INODE_##name;                            \
+})
+
+/*
+ * Convert EXT2_*_FL to corresponding BTRFS_INODE_* flags
+ *
+ * Only a subset of EXT_*_FL is supported in btrfs.
+ */
+static void ext2_convert_inode_flags(struct btrfs_inode_item *dst,
+                                    struct ext2_inode *src)
+{
+       u64 flags = 0;
+
+       COPY_ONE_EXT2_FLAG(flags, src, APPEND);
+       COPY_ONE_EXT2_FLAG(flags, src, SYNC);
+       COPY_ONE_EXT2_FLAG(flags, src, IMMUTABLE);
+       COPY_ONE_EXT2_FLAG(flags, src, NODUMP);
+       COPY_ONE_EXT2_FLAG(flags, src, NOATIME);
+       COPY_ONE_EXT2_FLAG(flags, src, DIRSYNC);
+       btrfs_set_stack_inode_flags(dst, flags);
+}
 
 /*
  * copy a single inode. do all the required works, such as cloning
@@ -1997,6 +2239,7 @@ static int ext2_copy_single_inode(struct btrfs_trans_handle *trans,
                            BTRFS_INODE_NODATASUM;
                btrfs_set_stack_inode_flags(&btrfs_inode, flags);
        }
+       ext2_convert_inode_flags(&btrfs_inode, ext2_inode);
 
        switch (ext2_inode->i_mode & S_IFMT) {
        case S_IFREG:
@@ -2086,171 +2329,21 @@ static int ext2_copy_inodes(struct btrfs_convert_context *cctx,
        return ret;
 }
 
-/*
- * Init the temp btrfs to a operational status.
- *
- * It will fix the extent usage accounting(XXX: Do we really need?) and
- * insert needed data chunks, to ensure all old fs data extents are covered
- * by DATA chunks, preventing wrong chunks are allocated.
- *
- * And also create convert image subvolume and relocation tree.
- * (XXX: Not need again?)
- * But the convert image subvolume is *NOT* linked to fs tree yet.
- */
-static int init_btrfs(struct btrfs_mkfs_config *cfg, struct btrfs_root *root,
-                        struct btrfs_convert_context *cctx, int datacsum,
-                        int packing, int noxattr)
-{
-       struct btrfs_key location;
-       struct btrfs_trans_handle *trans;
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       int ret;
-
-       /*
-        * Don't alloc any metadata/system chunk, as we don't want
-        * any meta/sys chunk allcated before all data chunks are inserted.
-        * Or we screw up the chunk layout just like the old implement.
-        */
-       fs_info->avoid_sys_chunk_alloc = 1;
-       fs_info->avoid_meta_chunk_alloc = 1;
-       trans = btrfs_start_transaction(root, 1);
-       BUG_ON(!trans);
-       ret = btrfs_fix_block_accounting(trans, root);
-       if (ret)
-               goto err;
-       ret = make_convert_data_block_groups(trans, fs_info, cfg, cctx);
-       if (ret)
-               goto err;
-       ret = btrfs_make_root_dir(trans, fs_info->tree_root,
-                                 BTRFS_ROOT_TREE_DIR_OBJECTID);
-       if (ret)
-               goto err;
-       memcpy(&location, &root->root_key, sizeof(location));
-       location.offset = (u64)-1;
-       ret = btrfs_insert_dir_item(trans, fs_info->tree_root, "default", 7,
-                               btrfs_super_root_dir(fs_info->super_copy),
-                               &location, BTRFS_FT_DIR, 0);
-       if (ret)
-               goto err;
-       ret = btrfs_insert_inode_ref(trans, fs_info->tree_root, "default", 7,
-                               location.objectid,
-                               btrfs_super_root_dir(fs_info->super_copy), 0);
-       if (ret)
-               goto err;
-       btrfs_set_root_dirid(&fs_info->fs_root->root_item,
-                            BTRFS_FIRST_FREE_OBJECTID);
-
-       /* subvol for fs image file */
-       ret = create_subvol(trans, root, CONV_IMAGE_SUBVOL_OBJECTID);
-       if (ret < 0)
-               goto err;
-       /* subvol for data relocation tree */
-       ret = create_subvol(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID);
-       if (ret < 0)
-               goto err;
-
-       ret = btrfs_commit_transaction(trans, root);
-       fs_info->avoid_sys_chunk_alloc = 0;
-       fs_info->avoid_meta_chunk_alloc = 0;
-err:
-       return ret;
-}
-
-/*
- * Migrate super block to its default position and zero 0 ~ 16k
- */
-static int migrate_super_block(int fd, u64 old_bytenr, u32 sectorsize)
-{
-       int ret;
-       struct extent_buffer *buf;
-       struct btrfs_super_block *super;
-       u32 len;
-       u32 bytenr;
-
-       BUG_ON(sectorsize < sizeof(*super));
-       buf = malloc(sizeof(*buf) + sectorsize);
-       if (!buf)
-               return -ENOMEM;
-
-       buf->len = sectorsize;
-       ret = pread(fd, buf->data, sectorsize, old_bytenr);
-       if (ret != sectorsize)
-               goto fail;
-
-       super = (struct btrfs_super_block *)buf->data;
-       BUG_ON(btrfs_super_bytenr(super) != old_bytenr);
-       btrfs_set_super_bytenr(super, BTRFS_SUPER_INFO_OFFSET);
-
-       csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, sectorsize, BTRFS_SUPER_INFO_OFFSET);
-       if (ret != sectorsize)
-               goto fail;
-
-       ret = fsync(fd);
-       if (ret)
-               goto fail;
-
-       memset(buf->data, 0, sectorsize);
-       for (bytenr = 0; bytenr < BTRFS_SUPER_INFO_OFFSET; ) {
-               len = BTRFS_SUPER_INFO_OFFSET - bytenr;
-               if (len > sectorsize)
-                       len = sectorsize;
-               ret = pwrite(fd, buf->data, len, bytenr);
-               if (ret != len) {
-                       fprintf(stderr, "unable to zero fill device\n");
-                       break;
-               }
-               bytenr += len;
-       }
-       ret = 0;
-       fsync(fd);
-fail:
-       free(buf);
-       if (ret > 0)
-               ret = -1;
-       return ret;
-}
-
-static int prepare_system_chunk_sb(struct btrfs_super_block *super)
-{
-       struct btrfs_chunk *chunk;
-       struct btrfs_disk_key *key;
-       u32 sectorsize = btrfs_super_sectorsize(super);
-
-       key = (struct btrfs_disk_key *)(super->sys_chunk_array);
-       chunk = (struct btrfs_chunk *)(super->sys_chunk_array +
-                                      sizeof(struct btrfs_disk_key));
-
-       btrfs_set_disk_key_objectid(key, BTRFS_FIRST_CHUNK_TREE_OBJECTID);
-       btrfs_set_disk_key_type(key, BTRFS_CHUNK_ITEM_KEY);
-       btrfs_set_disk_key_offset(key, 0);
-
-       btrfs_set_stack_chunk_length(chunk, btrfs_super_total_bytes(super));
-       btrfs_set_stack_chunk_owner(chunk, BTRFS_EXTENT_TREE_OBJECTID);
-       btrfs_set_stack_chunk_stripe_len(chunk, BTRFS_STRIPE_LEN);
-       btrfs_set_stack_chunk_type(chunk, BTRFS_BLOCK_GROUP_SYSTEM);
-       btrfs_set_stack_chunk_io_align(chunk, sectorsize);
-       btrfs_set_stack_chunk_io_width(chunk, sectorsize);
-       btrfs_set_stack_chunk_sector_size(chunk, sectorsize);
-       btrfs_set_stack_chunk_num_stripes(chunk, 1);
-       btrfs_set_stack_chunk_sub_stripes(chunk, 0);
-       chunk->stripe.devid = super->dev_item.devid;
-       btrfs_set_stack_stripe_offset(&chunk->stripe, 0);
-       memcpy(chunk->stripe.dev_uuid, super->dev_item.uuid, BTRFS_UUID_SIZE);
-       btrfs_set_super_sys_array_size(super, sizeof(*key) + sizeof(*chunk));
-       return 0;
-}
-
 static const struct btrfs_convert_operations ext2_convert_ops = {
        .name                   = "ext2",
        .open_fs                = ext2_open_fs,
        .read_used_space        = ext2_read_used_space,
        .copy_inodes            = ext2_copy_inodes,
        .close_fs               = ext2_close_fs,
+       .check_state            = ext2_check_state,
 };
 
+#endif
+
 static const struct btrfs_convert_operations *convert_operations[] = {
+#if BTRFSCONVERT_EXT2
        &ext2_convert_ops,
+#endif
 };
 
 static int convert_open_fs(const char *devname,
@@ -2269,7 +2362,7 @@ static int convert_open_fs(const char *devname,
                }
        }
 
-       fprintf(stderr, "No file system found to convert.\n");
+       error("no file system found to convert");
        return -1;
 }
 
@@ -2279,7 +2372,6 @@ static int do_convert(const char *devname, int datacsum, int packing,
 {
        int ret;
        int fd = -1;
-       int is_btrfs = 0;
        u32 blocksize;
        u64 total_bytes;
        struct btrfs_root *root;
@@ -2295,6 +2387,10 @@ static int do_convert(const char *devname, int datacsum, int packing,
        ret = convert_open_fs(devname, &cctx);
        if (ret)
                goto fail;
+       ret = convert_check_state(&cctx);
+       if (ret)
+               warning(
+               "source filesystem is not clean, running filesystem check is recommended");
        ret = convert_read_used_space(&cctx);
        if (ret)
                goto fail;
@@ -2302,14 +2398,14 @@ static int do_convert(const char *devname, int datacsum, int packing,
        blocksize = cctx.blocksize;
        total_bytes = (u64)blocksize * (u64)cctx.block_count;
        if (blocksize < 4096) {
-               fprintf(stderr, "block size is too small\n");
+               error("block size is too small: %u < 4096", blocksize);
                goto fail;
        }
        if (btrfs_check_nodesize(nodesize, blocksize, features))
                goto fail;
        fd = open(devname, O_RDWR);
        if (fd < 0) {
-               fprintf(stderr, "unable to open %s\n", devname);
+               error("unable to open %s: %s", devname, strerror(errno));
                goto fail;
        }
        btrfs_parse_features_to_string(features_buf, features);
@@ -2328,34 +2424,31 @@ static int do_convert(const char *devname, int datacsum, int packing,
        mkfs_cfg.stripesize = blocksize;
        mkfs_cfg.features = features;
        /* New convert need these space */
-       mkfs_cfg.fs_uuid = malloc(BTRFS_UUID_UNPARSED_SIZE);
-       mkfs_cfg.chunk_uuid = malloc(BTRFS_UUID_UNPARSED_SIZE);
-       *(mkfs_cfg.fs_uuid) = '\0';
-       *(mkfs_cfg.chunk_uuid) = '\0';
+       memset(mkfs_cfg.chunk_uuid, 0, BTRFS_UUID_UNPARSED_SIZE);
+       memset(mkfs_cfg.fs_uuid, 0, BTRFS_UUID_UNPARSED_SIZE);
 
        ret = make_btrfs(fd, &mkfs_cfg, &cctx);
        if (ret) {
-               fprintf(stderr, "unable to create initial ctree: %s\n",
-                       strerror(-ret));
+               error("unable to create initial ctree: %s", strerror(-ret));
                goto fail;
        }
 
        root = open_ctree_fd(fd, devname, mkfs_cfg.super_bytenr,
                             OPEN_CTREE_WRITES | OPEN_CTREE_FS_PARTIAL);
        if (!root) {
-               fprintf(stderr, "unable to open ctree\n");
+               error("unable to open ctree");
                goto fail;
        }
        ret = init_btrfs(&mkfs_cfg, root, &cctx, datacsum, packing, noxattr);
        if (ret) {
-               fprintf(stderr, "unable to setup the root tree\n");
+               error("unable to setup the root tree: %d", ret);
                goto fail;
        }
 
-       printf("creating %s image file.\n", cctx.convert_ops->name);
+       printf("creating %s image file\n", cctx.convert_ops->name);
        ret = asprintf(&subvol_name, "%s_saved", cctx.convert_ops->name);
        if (ret < 0) {
-               fprintf(stderr, "error allocating subvolume name: %s_saved\n",
+               error("memory allocation failure for subvolume name: %s_saved",
                        cctx.convert_ops->name);
                goto fail;
        }
@@ -2364,17 +2457,17 @@ static int do_convert(const char *devname, int datacsum, int packing,
        key.type = BTRFS_ROOT_ITEM_KEY;
        image_root = btrfs_read_fs_root(root->fs_info, &key);
        if (!image_root) {
-               fprintf(stderr, "unable to create subvol\n");
+               error("unable to create image subvolume");
                goto fail;
        }
        ret = create_image(image_root, &mkfs_cfg, &cctx, fd,
                              mkfs_cfg.num_bytes, "image", datacsum);
        if (ret) {
-               fprintf(stderr, "error during create_image %d\n", ret);
+               error("failed to create %s/image: %d", subvol_name, ret);
                goto fail;
        }
 
-       printf("creating btrfs metadata.\n");
+       printf("creating btrfs metadata");
        ctx.max_copy_inodes = (cctx.inodes_count - cctx.free_inodes_count);
        ctx.cur_copy_inodes = 0;
 
@@ -2385,7 +2478,7 @@ static int do_convert(const char *devname, int datacsum, int packing,
        }
        ret = copy_inodes(&cctx, root, datacsum, packing, noxattr, &ctx);
        if (ret) {
-               fprintf(stderr, "error during copy_inodes %d\n", ret);
+               error("error during copy_inodes %d", ret);
                goto fail;
        }
        if (progress) {
@@ -2394,6 +2487,10 @@ static int do_convert(const char *devname, int datacsum, int packing,
        }
 
        image_root = link_subvol(root, subvol_name, CONV_IMAGE_SUBVOL_OBJECTID);
+       if (!image_root) {
+               error("unable to link subvolume %s", subvol_name);
+               goto fail;
+       }
 
        free(subvol_name);
 
@@ -2401,16 +2498,15 @@ static int do_convert(const char *devname, int datacsum, int packing,
        if (copylabel == 1) {
                __strncpy_null(root->fs_info->super_copy->label,
                                cctx.volume_name, BTRFS_LABEL_SIZE - 1);
-               fprintf(stderr, "copy label '%s'\n",
-                               root->fs_info->super_copy->label);
+               printf("copy label '%s'\n", root->fs_info->super_copy->label);
        } else if (copylabel == -1) {
                strcpy(root->fs_info->super_copy->label, fslabel);
-               fprintf(stderr, "set label to '%s'\n", fslabel);
+               printf("set label to '%s'\n", fslabel);
        }
 
        ret = close_ctree(root);
        if (ret) {
-               fprintf(stderr, "error during close_ctree %d\n", ret);
+               error("close_ctree failed: %d", ret);
                goto fail;
        }
        convert_close_fs(&cctx);
@@ -2422,32 +2518,28 @@ static int do_convert(const char *devname, int datacsum, int packing,
         */
        ret = migrate_super_block(fd, mkfs_cfg.super_bytenr, blocksize);
        if (ret) {
-               fprintf(stderr, "unable to migrate super block\n");
+               error("unable to migrate super block: %d", ret);
                goto fail;
        }
-       is_btrfs = 1;
 
        root = open_ctree_fd(fd, devname, 0,
                        OPEN_CTREE_WRITES | OPEN_CTREE_FS_PARTIAL);
        if (!root) {
-               fprintf(stderr, "unable to open ctree\n");
+               error("unable to open ctree for finalization");
                goto fail;
        }
        root->fs_info->finalize_on_close = 1;
        close_ctree(root);
        close(fd);
 
-       printf("conversion complete.\n");
+       printf("conversion complete");
        return 0;
 fail:
        clean_convert_context(&cctx);
        if (fd != -1)
                close(fd);
-       if (is_btrfs)
-               fprintf(stderr,
-                       "WARNING: an error occurred during chunk mapping fixup, filesystem mountable but not finalized\n");
-       else
-               fprintf(stderr, "conversion aborted\n");
+       warning(
+"an error occurred during conversion, filesystem is partially created but not finalized and not mountable");
        return -1;
 }
 
@@ -2545,7 +2637,7 @@ static int may_rollback(struct btrfs_root *root)
 
                num_stripes = multi->num_stripes;
                physical = multi->stripes[0].physical;
-               kfree(multi);
+               free(multi);
 
                if (num_stripes != 1) {
                        error("num stripes for bytenr %llu is not 1", bytenr);
@@ -2612,24 +2704,24 @@ static int do_rollback(const char *devname)
 
        fd = open(devname, O_RDWR);
        if (fd < 0) {
-               fprintf(stderr, "unable to open %s\n", devname);
+               error("unable to open %s: %s", devname, strerror(errno));
                goto fail;
        }
        root = open_ctree_fd(fd, devname, 0, OPEN_CTREE_WRITES);
        if (!root) {
-               fprintf(stderr, "unable to open ctree\n");
+               error("unable to open ctree");
                goto fail;
        }
        ret = may_rollback(root);
        if (ret < 0) {
-               fprintf(stderr, "unable to do rollback\n");
+               error("unable to do rollback: %d", ret);
                goto fail;
        }
 
        sectorsize = root->sectorsize;
        buf = malloc(sectorsize);
        if (!buf) {
-               fprintf(stderr, "unable to allocate memory\n");
+               error("unable to allocate memory");
                goto fail;
        }
 
@@ -2642,12 +2734,10 @@ static int do_rollback(const char *devname)
                                0);
        btrfs_release_path(&path);
        if (ret > 0) {
-               fprintf(stderr,
-               "ERROR: unable to convert ext2 image subvolume, is it deleted?\n");
+               error("unable to convert ext2 image subvolume, is it deleted?");
                goto fail;
        } else if (ret < 0) {
-               fprintf(stderr,
-                       "ERROR: unable to open ext2_saved, id=%llu: %s\n",
+               error("unable to open ext2_saved, id %llu: %s",
                        (unsigned long long)key.objectid, strerror(-ret));
                goto fail;
        }
@@ -2657,8 +2747,8 @@ static int do_rollback(const char *devname)
        key.offset = (u64)-1;
        image_root = btrfs_read_fs_root(root->fs_info, &key);
        if (!image_root || IS_ERR(image_root)) {
-               fprintf(stderr, "unable to open subvol %llu\n",
-                       (unsigned long long)key.objectid);
+               error("unable to open subvolume %llu: %ld",
+                       (unsigned long long)key.objectid, PTR_ERR(image_root));
                goto fail;
        }
 
@@ -2667,7 +2757,7 @@ static int do_rollback(const char *devname)
        dir = btrfs_lookup_dir_item(NULL, image_root, &path,
                                   root_dir, name, strlen(name), 0);
        if (!dir || IS_ERR(dir)) {
-               fprintf(stderr, "unable to find file %s\n", name);
+               error("unable to find file %s: %ld", name, PTR_ERR(dir));
                goto fail;
        }
        leaf = path.nodes[0];
@@ -2678,7 +2768,7 @@ static int do_rollback(const char *devname)
 
        ret = btrfs_lookup_inode(NULL, image_root, &path, &key, 0);
        if (ret) {
-               fprintf(stderr, "unable to find inode item\n");
+               error("unable to find inode item: %d", ret);
                goto fail;
        }
        leaf = path.nodes[0];
@@ -2688,10 +2778,10 @@ static int do_rollback(const char *devname)
 
        key.objectid = objectid;
        key.offset = 0;
-       btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
+       key.type = BTRFS_EXTENT_DATA_KEY;
        ret = btrfs_search_slot(NULL, image_root, &key, &path, 0, 0);
        if (ret != 0) {
-               fprintf(stderr, "unable to find first file extent\n");
+               error("unable to find first file extent: %d", ret);
                btrfs_release_path(&path);
                goto fail;
        }
@@ -2708,7 +2798,7 @@ static int do_rollback(const char *devname)
 
                btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
                if (key.objectid != objectid || key.offset != offset ||
-                   btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
+                   key.type != BTRFS_EXTENT_DATA_KEY)
                        break;
 
                fi = btrfs_item_ptr(leaf, path.slots[0],
@@ -2754,8 +2844,10 @@ next_extent:
        btrfs_release_path(&path);
 
        if (offset < total_bytes) {
-               fprintf(stderr, "unable to build extent mapping\n");
-               fprintf(stderr, "converted filesystem after balance is unable to rollback\n");
+               error("unable to build extent mapping (offset %llu, total_bytes %llu)",
+                               (unsigned long long)offset,
+                               (unsigned long long)total_bytes);
+               error("converted filesystem after balance is unable to rollback");
                goto fail;
        }
 
@@ -2763,13 +2855,16 @@ next_extent:
        first_free &= ~((u64)sectorsize - 1);
        /* backup for extent #0 should exist */
        if(!test_range_bit(&io_tree, 0, first_free - 1, EXTENT_LOCKED, 1)) {
-               fprintf(stderr, "no backup for the first extent\n");
+               error("no backup for the first extent");
                goto fail;
        }
        /* force no allocation from system block group */
        root->fs_info->system_allocs = -1;
        trans = btrfs_start_transaction(root, 1);
-       BUG_ON(!trans);
+       if (!trans) {
+               error("unable to start transaction");
+               goto fail;
+       }
        /*
         * recow the whole chunk tree, this will remove all chunk tree blocks
         * from system block group
@@ -2804,22 +2899,28 @@ next_extent:
        }
        /* only extent #0 left in system block group? */
        if (num_bytes > first_free) {
-               fprintf(stderr, "unable to empty system block group\n");
+               error(
+       "unable to empty system block group (num_bytes %llu, first_free %llu",
+                               (unsigned long long)num_bytes,
+                               (unsigned long long)first_free);
                goto fail;
        }
        /* create a system chunk that maps the whole device */
        ret = prepare_system_chunk_sb(root->fs_info->super_copy);
        if (ret) {
-               fprintf(stderr, "unable to update system chunk\n");
+               error("unable to update system chunk: %d", ret);
                goto fail;
        }
 
        ret = btrfs_commit_transaction(trans, root);
-       BUG_ON(ret);
+       if (ret) {
+               error("transaction commit failed: %d", ret);
+               goto fail;
+       }
 
        ret = close_ctree(root);
        if (ret) {
-               fprintf(stderr, "error during close_ctree %d\n", ret);
+               error("close_ctree failed: %d", ret);
                goto fail;
        }
 
@@ -2831,9 +2932,8 @@ next_extent:
                        break;
                ret = pwrite(fd, buf, sectorsize, bytenr);
                if (ret != sectorsize) {
-                       fprintf(stderr,
-                               "error during zeroing superblock %d: %d\n",
-                               i, ret);
+                       error("zeroing superblock mirror %d failed: %d",
+                                       i, ret);
                        goto fail;
                }
        }
@@ -2859,13 +2959,15 @@ next_extent:
                        }
                        ret = pread(fd, buf, sectorsize, bytenr);
                        if (ret < 0) {
-                               fprintf(stderr, "error during pread %d\n", ret);
+                               error("reading superblock at %llu failed: %d",
+                                               (unsigned long long)bytenr, ret);
                                goto fail;
                        }
                        BUG_ON(ret != sectorsize);
                        ret = pwrite(fd, buf, sectorsize, start);
                        if (ret < 0) {
-                               fprintf(stderr, "error during pwrite %d\n", ret);
+                               error("writing superblock at %llu failed: %d",
+                                               (unsigned long long)start, ret);
                                goto fail;
                        }
                        BUG_ON(ret != sectorsize);
@@ -2876,8 +2978,8 @@ next_sector:
        }
 
        ret = fsync(fd);
-       if (ret) {
-               fprintf(stderr, "error during fsync %d\n", ret);
+       if (ret < 0) {
+               error("fsync failed: %s", strerror(errno));
                goto fail;
        }
        /*
@@ -2885,33 +2987,35 @@ next_sector:
         */
        ret = pread(fd, buf, sectorsize, sb_bytenr);
        if (ret < 0) {
-               fprintf(stderr, "error during pread %d\n", ret);
+               error("reading primary superblock failed: %s",
+                               strerror(errno));
                goto fail;
        }
        BUG_ON(ret != sectorsize);
        ret = pwrite(fd, buf, sectorsize, BTRFS_SUPER_INFO_OFFSET);
        if (ret < 0) {
-               fprintf(stderr, "error during pwrite %d\n", ret);
+               error("writing primary superblock failed: %s",
+                               strerror(errno));
                goto fail;
        }
        BUG_ON(ret != sectorsize);
        ret = fsync(fd);
-       if (ret) {
-               fprintf(stderr, "error during fsync %d\n", ret);
+       if (ret < 0) {
+               error("fsync failed: %s", strerror(errno));
                goto fail;
        }
 
        close(fd);
        free(buf);
        extent_io_tree_cleanup(&io_tree);
-       printf("rollback complete.\n");
+       printf("rollback complete\n");
        return 0;
 
 fail:
        if (fd != -1)
                close(fd);
        free(buf);
-       fprintf(stderr, "rollback aborted.\n");
+       error("rollback aborted");
        return -1;
 }
 
@@ -2929,6 +3033,9 @@ static void print_usage(void)
        printf("\t-p|--progress          show converting progress (default)\n");
        printf("\t-O|--features LIST     comma separated list of filesystem features\n");
        printf("\t--no-progress          show only overview, not the detailed progress\n");
+       printf("\n");
+       printf("Supported filesystems:\n");
+       printf("\text2/3/4: %s\n", BTRFSCONVERT_EXT2 ? "yes" : "no");
 }
 
 int main(int argc, char *argv[])
@@ -2987,8 +3094,8 @@ int main(int argc, char *argv[])
                        case 'l':
                                copylabel = -1;
                                if (strlen(optarg) >= BTRFS_LABEL_SIZE) {
-                                       fprintf(stderr,
-                               "WARNING: label too long, trimmed to %d bytes\n",
+                                       warning(
+                                       "label too long, trimmed to %d bytes",
                                                BTRFS_LABEL_SIZE - 1);
                                }
                                __strncpy_null(fslabel, optarg, BTRFS_LABEL_SIZE - 1);
@@ -3005,8 +3112,7 @@ int main(int argc, char *argv[])
 
                                tmp = btrfs_parse_fs_features(tmp, &features);
                                if (tmp) {
-                                       fprintf(stderr,
-                                               "Unrecognized filesystem feature '%s'\n",
+                                       error("unrecognized filesystem feature: %s",
                                                        tmp);
                                        free(orig);
                                        exit(1);
@@ -3022,8 +3128,7 @@ int main(int argc, char *argv[])
 
                                        btrfs_parse_features_to_string(buf,
                                                features & ~BTRFS_CONVERT_ALLOWED_FEATURES);
-                                       fprintf(stderr,
-                                               "ERROR: features not allowed for convert: %s\n",
+                                       error("features not allowed for convert: %s",
                                                buf);
                                        exit(1);
                                }
@@ -3059,11 +3164,10 @@ int main(int argc, char *argv[])
        file = argv[optind];
        ret = check_mounted(file);
        if (ret < 0) {
-               fprintf(stderr, "Could not check mount status: %s\n",
-                       strerror(-ret));
+               error("could not check mount status: %s", strerror(-ret));
                return 1;
        } else if (ret) {
-               fprintf(stderr, "%s is mounted\n", file);
+               error("%s is mounted", file);
                return 1;
        }