btrfs-progs: check: introduce function to check dir_item
[platform/upstream/btrfs-progs.git] / btrfs-convert.c
index 9e04805..4b4cea4 100644 (file)
@@ -103,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)
@@ -132,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;
@@ -277,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;
@@ -289,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
@@ -310,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)
@@ -324,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 ||
@@ -334,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 +
@@ -357,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;
 }
 
@@ -424,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);
 
        /*
@@ -514,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)
@@ -952,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;
@@ -969,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);
@@ -985,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
@@ -1040,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;
 }
@@ -1063,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;
@@ -1078,28 +1090,25 @@ static struct btrfs_root* link_subvol(struct btrfs_root *root,
        if (len == 0 || len > BTRFS_NAME_LEN)
                return NULL;
 
-       path = btrfs_alloc_path();
-       if (!path)
-               return NULL;
-
+       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);
+       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);
        if (!trans) {
@@ -1111,14 +1120,14 @@ static struct btrfs_root* link_subvol(struct btrfs_root *root,
        key.offset = 0;
        key.type =  BTRFS_INODE_ITEM_KEY;
 
-       ret = btrfs_lookup_inode(trans, root, path, &key, 1);
+       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],
+       leaf = path.nodes[0];
+       inode_item = btrfs_item_ptr(leaf, path.slots[0],
                                    struct btrfs_inode_item);
 
        key.objectid = root_objectid;
@@ -1143,7 +1152,7 @@ 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,
@@ -1178,7 +1187,7 @@ static struct btrfs_root* link_subvol(struct btrfs_root *root,
                new_root = NULL;
        }
 fail:
-       btrfs_free_path(path);
+       btrfs_init_path(&path);
        return new_root;
 }
 
@@ -1487,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;
        }
 
@@ -2171,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
@@ -2194,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:
@@ -2289,6 +2335,7 @@ static const struct btrfs_convert_operations ext2_convert_ops = {
        .read_used_space        = ext2_read_used_space,
        .copy_inodes            = ext2_copy_inodes,
        .close_fs               = ext2_close_fs,
+       .check_state            = ext2_check_state,
 };
 
 #endif
@@ -2315,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;
 }
 
@@ -2325,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;
@@ -2341,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;
@@ -2374,10 +2424,8 @@ 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) {
@@ -2473,7 +2521,6 @@ static int do_convert(const char *devname, int datacsum, int packing,
                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);
@@ -2491,11 +2538,8 @@ fail:
        clean_convert_context(&cctx);
        if (fd != -1)
                close(fd);
-       if (is_btrfs)
-               warning(
-"an error occurred during chunk mapping fixup, filesystem mountable but not finalized");
-       else
-               error("conversion aborted");
+       warning(
+"an error occurred during conversion, filesystem is partially created but not finalized and not mountable");
        return -1;
 }
 
@@ -2593,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);
@@ -2660,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;
        }
 
@@ -2690,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;
        }
@@ -2705,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;
        }
 
@@ -2715,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];
@@ -2726,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];
@@ -2736,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;
        }
@@ -2756,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],
@@ -2802,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;
        }
 
@@ -2811,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
@@ -2852,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;
        }
 
@@ -2879,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;
                }
        }
@@ -2907,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);
@@ -2924,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;
        }
        /*
@@ -2933,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;
 }
 
@@ -2978,7 +3034,7 @@ static void print_usage(void)
        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("Suported filesystems:\n");
+       printf("Supported filesystems:\n");
        printf("\text2/3/4: %s\n", BTRFSCONVERT_EXT2 ? "yes" : "no");
 }
 
@@ -3038,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);
@@ -3056,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);
@@ -3073,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);
                                }
@@ -3110,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;
        }