btrfs-progs: convert: Fix inline file extent creation condition
[platform/upstream/btrfs-progs.git] / convert / source-ext2.c
index f286d07..a2af121 100644 (file)
@@ -17,6 +17,8 @@
 #if BTRFSCONVERT_EXT2
 
 #include "kerncompat.h"
+#include <linux/limits.h>
+#include <pthread.h>
 #include "disk-io.h"
 #include "transaction.h"
 #include "utils.h"
@@ -33,10 +35,12 @@ static int ext2_open_fs(struct btrfs_convert_context *cctx, const char *name)
        ext2_filsys ext2_fs;
        ext2_ino_t ino;
        u32 ro_feature;
+       int open_flag = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
 
-       ret = ext2fs_open(name, 0, 0, 0, unix_io_manager, &ext2_fs);
+       ret = ext2fs_open(name, open_flag, 0, 0, unix_io_manager, &ext2_fs);
        if (ret) {
-               fprintf(stderr, "ext2fs_open: %s\n", error_message(ret));
+               if (ret != EXT2_ET_BAD_MAGIC)
+                       fprintf(stderr, "ext2fs_open: %s\n", error_message(ret));
                return -1;
        }
        /*
@@ -91,6 +95,7 @@ static int ext2_open_fs(struct btrfs_convert_context *cctx, const char *name)
        return 0;
 fail:
        ext2fs_close(ext2_fs);
+       ext2fs_free(ext2_fs);
        return -1;
 }
 
@@ -129,26 +134,30 @@ static int ext2_read_used_space(struct btrfs_convert_context *cctx)
 {
        ext2_filsys fs = (ext2_filsys)cctx->fs_data;
        blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
-       struct cache_tree *used_tree = &cctx->used;
+       struct cache_tree *used_tree = &cctx->used_space;
        char *block_bitmap = NULL;
        unsigned long i;
        int block_nbytes;
        int ret = 0;
 
        block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
-       /* Shouldn't happen */
-       BUG_ON(!fs->block_map);
+       if (!block_nbytes) {
+               error("EXT2_CLUSTERS_PER_GROUP too small: %llu",
+                       (unsigned long long)(EXT2_CLUSTERS_PER_GROUP(fs->super)));
+               return -EINVAL;
+       }
 
        block_bitmap = malloc(block_nbytes);
        if (!block_bitmap)
                return -ENOMEM;
 
        for (i = 0; i < fs->group_desc_count; i++) {
-               ret = ext2fs_get_block_bitmap_range(fs->block_map, blk_itr,
+               ret = ext2fs_get_block_bitmap_range2(fs->block_map, blk_itr,
                                                block_nbytes * 8, block_bitmap);
                if (ret) {
                        error("fail to get bitmap from ext2, %s",
-                             strerror(-ret));
+                               error_message(ret));
+                       ret = -EINVAL;
                        break;
                }
                ret = __ext2_add_one_block(fs, block_bitmap, i, used_tree);
@@ -171,6 +180,7 @@ static void ext2_close_fs(struct btrfs_convert_context *cctx)
                cctx->volume_name = NULL;
        }
        ext2fs_close(cctx->fs_data);
+       ext2fs_free(cctx->fs_data);
 }
 
 static u8 ext2_filetype_conversion_table[EXT2_FT_MAX] = {
@@ -279,18 +289,18 @@ static int ext2_create_file_extents(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root, u64 objectid,
                               struct btrfs_inode_item *btrfs_inode,
                               ext2_filsys ext2_fs, ext2_ino_t ext2_ino,
-                              int datacsum, int packing)
+                              u32 convert_flags)
 {
        int ret;
        char *buffer = NULL;
        errcode_t err;
        u32 last_block;
-       u32 sectorsize = root->sectorsize;
+       u32 sectorsize = root->fs_info->sectorsize;
        u64 inode_size = btrfs_stack_inode_size(btrfs_inode);
        struct blk_iterate_data data;
 
        init_blk_iterate_data(&data, trans, root, btrfs_inode, objectid,
-                             datacsum);
+                       convert_flags & CONVERT_FLAG_DATACSUM);
 
        err = ext2fs_block_iterate2(ext2_fs, ext2_ino, BLOCK_FLAG_DATA_ONLY,
                                    NULL, ext2_block_iterate_proc, &data);
@@ -299,8 +309,9 @@ static int ext2_create_file_extents(struct btrfs_trans_handle *trans,
        ret = data.errcode;
        if (ret)
                goto fail;
-       if (packing && data.first_block == 0 && data.num_blocks > 0 &&
-           inode_size <= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
+       if ((convert_flags & CONVERT_FLAG_INLINE_DATA) && data.first_block == 0
+           && data.num_blocks > 0 && inode_size < sectorsize
+           && inode_size <= BTRFS_MAX_INLINE_DATA_SIZE(root->fs_info)) {
                u64 num_bytes = data.num_blocks * sectorsize;
                u64 disk_bytenr = data.disk_block * sectorsize;
                u64 nbytes;
@@ -339,7 +350,7 @@ error:
        return -1;
 }
 
-static int ext2_create_symbol_link(struct btrfs_trans_handle *trans,
+static int ext2_create_symlink(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root, u64 objectid,
                              struct btrfs_inode_item *btrfs_inode,
                              ext2_filsys ext2_fs, ext2_ino_t ext2_ino,
@@ -348,10 +359,12 @@ static int ext2_create_symbol_link(struct btrfs_trans_handle *trans,
        int ret;
        char *pathname;
        u64 inode_size = btrfs_stack_inode_size(btrfs_inode);
-       if (ext2fs_inode_data_blocks(ext2_fs, ext2_inode)) {
+       if (ext2fs_inode_data_blocks2(ext2_fs, ext2_inode)) {
                btrfs_set_stack_inode_size(btrfs_inode, inode_size + 1);
                ret = ext2_create_file_extents(trans, root, objectid,
-                               btrfs_inode, ext2_fs, ext2_ino, 1, 1);
+                               btrfs_inode, ext2_fs, ext2_ino,
+                               CONVERT_FLAG_DATACSUM |
+                               CONVERT_FLAG_INLINE_DATA);
                btrfs_set_stack_inode_size(btrfs_inode, inode_size);
                return ret;
        }
@@ -409,33 +422,11 @@ static int ext2_xattr_check_entry(struct ext2_ext_attr_entry *entry,
 {
        size_t value_size = entry->e_value_size;
 
-       if (entry->e_value_block != 0 || value_size > size ||
-           entry->e_value_offs + value_size > size)
+       if (value_size > size || entry->e_value_offs + value_size > size)
                return -EIO;
        return 0;
 }
 
-static inline int ext2_acl_count(size_t size)
-{
-       ssize_t s;
-       size -= sizeof(ext2_acl_header);
-       s = size - 4 * sizeof(ext2_acl_entry_short);
-       if (s < 0) {
-               if (size % sizeof(ext2_acl_entry_short))
-                       return -1;
-               return size / sizeof(ext2_acl_entry_short);
-       } else {
-               if (s % sizeof(ext2_acl_entry))
-                       return -1;
-               return s / sizeof(ext2_acl_entry) + 4;
-       }
-}
-
-static inline size_t acl_ea_size(int count)
-{
-       return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
-}
-
 static int ext2_acl_to_xattr(void *dst, const void *src,
                             size_t dst_size, size_t src_size)
 {
@@ -530,7 +521,7 @@ static int ext2_copy_single_xattr(struct btrfs_trans_handle *trans,
        }
        strncpy(namebuf, xattr_prefix_table[name_index], XATTR_NAME_MAX);
        strncat(namebuf, EXT2_EXT_ATTR_NAME(entry), entry->e_name_len);
-       if (name_len + datalen > BTRFS_LEAF_DATA_SIZE(root) -
+       if (name_len + datalen > BTRFS_LEAF_DATA_SIZE(root->fs_info) -
            sizeof(struct btrfs_item) - sizeof(struct btrfs_dir_item)) {
                fprintf(stderr, "skip large xattr on inode %Lu name %.*s\n",
                        objectid - INO_OFFSET, name_len, namebuf);
@@ -620,9 +611,9 @@ static int ext2_copy_extended_attrs(struct btrfs_trans_handle *trans,
                ret = -ENOMEM;
                goto out;
        }
-       err = ext2fs_read_ext_attr(ext2_fs, ext2_inode->i_file_acl, buffer);
+       err = ext2fs_read_ext_attr2(ext2_fs, ext2_inode->i_file_acl, buffer);
        if (err) {
-               fprintf(stderr, "ext2fs_read_ext_attr: %s\n",
+               fprintf(stderr, "ext2fs_read_ext_attr2: %s\n",
                        error_message(err));
                ret = -1;
                goto out;
@@ -650,21 +641,12 @@ out:
                free(ext2_inode);
        return ret;
 }
-#define MINORBITS      20
-#define MKDEV(ma, mi)  (((ma) << MINORBITS) | (mi))
 
 static inline dev_t old_decode_dev(u16 val)
 {
        return MKDEV((val >> 8) & 255, val & 255);
 }
 
-static inline dev_t new_decode_dev(u32 dev)
-{
-       unsigned major = (dev & 0xfff00) >> 8;
-       unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
-       return MKDEV(major, minor);
-}
-
 static void ext2_copy_inode_item(struct btrfs_inode_item *dst,
                           struct ext2_inode *src, u32 blocksize)
 {
@@ -704,7 +686,7 @@ static void ext2_copy_inode_item(struct btrfs_inode_item *dst,
                                old_decode_dev(src->i_block[0]));
                } else {
                        btrfs_set_stack_inode_rdev(dst,
-                               new_decode_dev(src->i_block[1]));
+                               decode_dev(src->i_block[1]));
                }
        }
        memset(&dst->reserved, 0, sizeof(dst->reserved));
@@ -735,7 +717,7 @@ static int ext2_check_state(struct btrfs_convert_context *cctx)
 static void ext2_convert_inode_flags(struct btrfs_inode_item *dst,
                                     struct ext2_inode *src)
 {
-       u64 flags = 0;
+       u64 flags = btrfs_stack_inode_flags(dst);
 
        COPY_ONE_EXT2_FLAG(flags, src, APPEND);
        COPY_ONE_EXT2_FLAG(flags, src, SYNC);
@@ -754,7 +736,7 @@ static int ext2_copy_single_inode(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root, u64 objectid,
                             ext2_filsys ext2_fs, ext2_ino_t ext2_ino,
                             struct ext2_inode *ext2_inode,
-                            int datacsum, int packing, int noxattr)
+                            u32 convert_flags)
 {
        int ret;
        struct btrfs_inode_item btrfs_inode;
@@ -763,7 +745,8 @@ static int ext2_copy_single_inode(struct btrfs_trans_handle *trans,
                return 0;
 
        ext2_copy_inode_item(&btrfs_inode, ext2_inode, ext2_fs->blocksize);
-       if (!datacsum && S_ISREG(ext2_inode->i_mode)) {
+       if (!(convert_flags & CONVERT_FLAG_DATACSUM)
+           && S_ISREG(ext2_inode->i_mode)) {
                u32 flags = btrfs_stack_inode_flags(&btrfs_inode) |
                            BTRFS_INODE_NODATASUM;
                btrfs_set_stack_inode_flags(&btrfs_inode, flags);
@@ -773,14 +756,14 @@ static int ext2_copy_single_inode(struct btrfs_trans_handle *trans,
        switch (ext2_inode->i_mode & S_IFMT) {
        case S_IFREG:
                ret = ext2_create_file_extents(trans, root, objectid,
-                       &btrfs_inode, ext2_fs, ext2_ino, datacsum, packing);
+                       &btrfs_inode, ext2_fs, ext2_ino, convert_flags);
                break;
        case S_IFDIR:
                ret = ext2_create_dir_entries(trans, root, objectid,
                                &btrfs_inode, ext2_fs, ext2_ino);
                break;
        case S_IFLNK:
-               ret = ext2_create_symbol_link(trans, root, objectid,
+               ret = ext2_create_symlink(trans, root, objectid,
                                &btrfs_inode, ext2_fs, ext2_ino, ext2_inode);
                break;
        default:
@@ -790,7 +773,7 @@ static int ext2_copy_single_inode(struct btrfs_trans_handle *trans,
        if (ret)
                return ret;
 
-       if (!noxattr) {
+       if (convert_flags & CONVERT_FLAG_XATTR) {
                ret = ext2_copy_extended_attrs(trans, root, objectid,
                                &btrfs_inode, ext2_fs, ext2_ino);
                if (ret)
@@ -799,12 +782,19 @@ static int ext2_copy_single_inode(struct btrfs_trans_handle *trans,
        return btrfs_insert_inode(trans, root, objectid, &btrfs_inode);
 }
 
+static int ext2_is_special_inode(ext2_ino_t ino)
+{
+       if (ino < EXT2_GOOD_OLD_FIRST_INO && ino != EXT2_ROOT_INO)
+               return 1;
+       return 0;
+}
+
 /*
  * scan ext2's inode bitmap and copy all used inodes.
  */
 static int ext2_copy_inodes(struct btrfs_convert_context *cctx,
                            struct btrfs_root *root,
-                           int datacsum, int packing, int noxattr, struct task_ctx *p)
+                           u32 convert_flags, struct task_ctx *p)
 {
        ext2_filsys ext2_fs = cctx->fs_data;
        int ret;
@@ -816,8 +806,8 @@ static int ext2_copy_inodes(struct btrfs_convert_context *cctx,
        struct btrfs_trans_handle *trans;
 
        trans = btrfs_start_transaction(root, 1);
-       if (!trans)
-               return -ENOMEM;
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        err = ext2fs_open_inode_scan(ext2_fs, 0, &ext2_scan);
        if (err) {
                fprintf(stderr, "ext2fs_open_inode_scan: %s\n", error_message(err));
@@ -828,23 +818,22 @@ static int ext2_copy_inodes(struct btrfs_convert_context *cctx,
                /* no more inodes */
                if (ext2_ino == 0)
                        break;
-               /* skip special inode in ext2fs */
-               if (ext2_ino < EXT2_GOOD_OLD_FIRST_INO &&
-                   ext2_ino != EXT2_ROOT_INO)
+               if (ext2_is_special_inode(ext2_ino))
                        continue;
                objectid = ext2_ino + INO_OFFSET;
                ret = ext2_copy_single_inode(trans, root,
                                        objectid, ext2_fs, ext2_ino,
-                                       &ext2_inode, datacsum, packing,
-                                       noxattr);
+                                       &ext2_inode, convert_flags);
+               pthread_mutex_lock(&p->mutex);
                p->cur_copy_inodes++;
+               pthread_mutex_unlock(&p->mutex);
                if (ret)
                        return ret;
                if (trans->blocks_used >= 4096) {
                        ret = btrfs_commit_transaction(trans, root);
                        BUG_ON(ret);
                        trans = btrfs_start_transaction(root, 1);
-                       BUG_ON(!trans);
+                       BUG_ON(IS_ERR(trans));
                }
        }
        if (err) {