summaryrefslogtreecommitdiff
path: root/btrfs-convert.c
diff options
context:
space:
mode:
Diffstat (limited to 'btrfs-convert.c')
-rw-r--r--btrfs-convert.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/btrfs-convert.c b/btrfs-convert.c
index e9e6d0b3..28ac84d1 100644
--- a/btrfs-convert.c
+++ b/btrfs-convert.c
@@ -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;