btrfs-progs: convert: Introduce functions to read used space
authorQu Wenruo <quwenruo@cn.fujitsu.com>
Fri, 29 Jan 2016 05:03:11 +0000 (13:03 +0800)
committerDavid Sterba <dsterba@suse.com>
Tue, 7 Jun 2016 16:15:19 +0000 (18:15 +0200)
Before we do real convert, we need to read and build up used space cache
tree for later data/meta separate chunk layout.

This patch will iterate all used blocks in ext2 filesystem and record it
into cctx->used cache tree, for later use.

This provides the very basic of later btrfs-convert rework.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
btrfs-convert.c

index e9e6d0b..28ac84d 100644 (file)
@@ -93,6 +93,7 @@ struct btrfs_convert_context;
 struct btrfs_convert_operations {
        const char *name;
        int (*open_fs)(struct btrfs_convert_context *cctx, const char *devname);
+       int (*read_used_space)(struct btrfs_convert_context *cctx);
        int (*alloc_block)(struct btrfs_convert_context *cctx, u64 goal,
                           u64 *block_ret);
        int (*alloc_block_range)(struct btrfs_convert_context *cctx, u64 goal,
@@ -257,6 +258,73 @@ fail:
        return -1;
 }
 
+static int __ext2_add_one_block(ext2_filsys fs, char *bitmap,
+                               unsigned long group_nr, struct cache_tree *used)
+{
+       unsigned long offset;
+       unsigned i;
+       int ret = 0;
+
+       offset = fs->super->s_first_data_block;
+       offset /= EXT2FS_CLUSTER_RATIO(fs);
+       offset += group_nr * EXT2_CLUSTERS_PER_GROUP(fs->super);
+       for (i = 0; i < EXT2_CLUSTERS_PER_GROUP(fs->super); i++) {
+               if (ext2fs_test_bit(i, bitmap)) {
+                       u64 start;
+
+                       start = (i + offset) * EXT2FS_CLUSTER_RATIO(fs);
+                       start *= fs->blocksize;
+                       ret = add_merge_cache_extent(used, start,
+                                                    fs->blocksize);
+                       if (ret < 0)
+                               break;
+               }
+       }
+       return ret;
+}
+
+/*
+ * Read all used ext2 space into cctx->used cache tree
+ */
+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;
+       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);
+
+       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,
+                                               block_nbytes * 8, block_bitmap);
+               if (ret) {
+                       error("fail to get bitmap from ext2, %s",
+                             strerror(-ret));
+                       break;
+               }
+               ret = __ext2_add_one_block(fs, block_bitmap, i, used_tree);
+               if (ret < 0) {
+                       error("fail to build used space tree, %s",
+                             strerror(-ret));
+                       break;
+               }
+               blk_itr += EXT2_CLUSTERS_PER_GROUP(fs->super);
+       }
+
+       free(block_bitmap);
+       return ret;
+}
+
 static void ext2_close_fs(struct btrfs_convert_context *cctx)
 {
        if (cctx->volume_name) {
@@ -2445,6 +2513,7 @@ err:
 static const struct btrfs_convert_operations ext2_convert_ops = {
        .name                   = "ext2",
        .open_fs                = ext2_open_fs,
+       .read_used_space        = ext2_read_used_space,
        .alloc_block            = ext2_alloc_block,
        .alloc_block_range      = ext2_alloc_block_range,
        .copy_inodes            = ext2_copy_inodes,
@@ -2478,6 +2547,14 @@ static int convert_open_fs(const char *devname,
        return -1;
 }
 
+/*
+ * Read used space
+ */
+static int convert_read_used_space(struct btrfs_convert_context *cctx)
+{
+       return cctx->convert_ops->read_used_space(cctx);
+}
+
 static int do_convert(const char *devname, int datacsum, int packing, int noxattr,
                u32 nodesize, int copylabel, const char *fslabel, int progress,
                u64 features)
@@ -2501,6 +2578,9 @@ static int do_convert(const char *devname, int datacsum, int packing, int noxatt
        ret = convert_open_fs(devname, &cctx);
        if (ret)
                goto fail;
+       ret = convert_read_used_space(&cctx);
+       if (ret)
+               goto fail;
 
        blocksize = cctx.blocksize;
        total_bytes = (u64)blocksize * (u64)cctx.block_count;