btrfs-progs: utils: Introduce new function for convert
authorQu Wenruo <quwenruo@cn.fujitsu.com>
Fri, 29 Jan 2016 05:03:14 +0000 (13:03 +0800)
committerDavid Sterba <dsterba@suse.com>
Tue, 7 Jun 2016 16:15:19 +0000 (18:15 +0200)
Introduce new function make_convert_btrfs() for convert.

This new function will have the following features:
1) Allocate temporary sb/metadata/system chunk, avoiding old used data
2) More structured functions
   No more over 1000 lines function, better function split and code
   reuse

This will finally replace current make_btrfs(), but now only used for
convert.

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

index 89df815..36ffba0 100644 (file)
@@ -108,28 +108,6 @@ struct btrfs_convert_operations {
        void (*close_fs)(struct btrfs_convert_context *cctx);
 };
 
-struct btrfs_convert_context {
-       u32 blocksize;
-       u32 first_data_block;
-       u32 block_count;
-       u32 inodes_count;
-       u32 free_inodes_count;
-       u64 total_bytes;
-       char *volume_name;
-       const struct btrfs_convert_operations *convert_ops;
-
-       /* The accurate used space of old filesystem */
-       struct cache_tree used;
-
-       /* Batched ranges which must be covered by data chunks */
-       struct cache_tree data_chunks;
-
-       /* Free space which is not covered by data_chunks */
-       struct cache_tree free;
-
-       void *fs_data;
-};
-
 static void init_convert_context(struct btrfs_convert_context *cctx)
 {
        cache_tree_init(&cctx->used);
@@ -2834,7 +2812,7 @@ static int do_convert(const char *devname, int datacsum, int packing, int noxatt
        mkfs_cfg.stripesize = blocksize;
        mkfs_cfg.features = features;
 
-       ret = make_btrfs(fd, &mkfs_cfg);
+       ret = make_btrfs(fd, &mkfs_cfg, NULL);
        if (ret) {
                fprintf(stderr, "unable to create initial ctree: %s\n",
                        strerror(-ret));
diff --git a/mkfs.c b/mkfs.c
index aff9a68..4243a4a 100644 (file)
--- a/mkfs.c
+++ b/mkfs.c
@@ -1675,7 +1675,7 @@ int main(int argc, char **argv)
        mkfs_cfg.stripesize = stripesize;
        mkfs_cfg.features = features;
 
-       ret = make_btrfs(fd, &mkfs_cfg);
+       ret = make_btrfs(fd, &mkfs_cfg, NULL);
        if (ret) {
                fprintf(stderr, "error during mkfs: %s\n", strerror(-ret));
                exit(1);
diff --git a/utils.c b/utils.c
index eeff910..71b2200 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -182,9 +182,96 @@ int test_uuid_unique(char *fs_uuid)
 }
 
 /*
+ * Reserve space from free_tree.
+ * The algorithm is very simple, find the first cache_extent with enough space
+ * and allocate from its beginning.
+ */
+static int reserve_free_space(struct cache_tree *free_tree, u64 len,
+                             u64 *ret_start)
+{
+       struct cache_extent *cache;
+       int found = 0;
+
+       BUG_ON(!ret_start);
+       cache = first_cache_extent(free_tree);
+       while (cache) {
+               if (cache->size > len) {
+                       found = 1;
+                       *ret_start = cache->start;
+
+                       cache->size -= len;
+                       if (cache->size == 0) {
+                               remove_cache_extent(free_tree, cache);
+                               free(cache);
+                       } else {
+                               cache->start += len;
+                       }
+                       break;
+               }
+               cache = next_cache_extent(cache);
+       }
+       if (!found)
+               return -ENOSPC;
+       return 0;
+}
+
+/*
+ * Improved version of make_btrfs().
+ *
+ * This one will
+ * 1) Do chunk allocation to avoid used data
+ *    And after this function, extent type matches chunk type
+ * 2) Better structured code
+ *    No super long hand written codes to initialized all tree blocks
+ *    Split into small blocks and reuse codes.
+ *    TODO: Reuse tree operation facilities by introducing new flags
+ */
+static int make_convert_btrfs(int fd, struct btrfs_mkfs_config *cfg,
+                             struct btrfs_convert_context *cctx)
+{
+       struct cache_tree *free = &cctx->free;
+       struct cache_tree *used = &cctx->used;
+       u64 sys_chunk_start;
+       u64 meta_chunk_start;
+       int ret;
+
+       /* Shouldn't happen */
+       BUG_ON(cache_tree_empty(used));
+
+       /*
+        * reserve space for temporary superblock first
+        * Here we allocate a little larger space, to keep later
+        * free space will be STRIPE_LEN aligned
+        */
+       ret = reserve_free_space(free, BTRFS_STRIPE_LEN,
+                                &cfg->super_bytenr);
+       if (ret < 0)
+               goto out;
+
+       /*
+        * Then reserve system chunk space
+        * TODO: Change system group size depending on cctx->total_bytes.
+        * If using current 4M, it can only handle less than one TB for
+        * worst case and then run out of sys space.
+        */
+       ret = reserve_free_space(free, BTRFS_MKFS_SYSTEM_GROUP_SIZE,
+                                &sys_chunk_start);
+       if (ret < 0)
+               goto out;
+       ret = reserve_free_space(free, BTRFS_CONVERT_META_GROUP_SIZE,
+                                &meta_chunk_start);
+       if (ret < 0)
+               goto out;
+
+out:
+       return ret;
+}
+
+/*
  * @fs_uuid - if NULL, generates a UUID, returns back the new filesystem UUID
  */
-int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
+int make_btrfs(int fd, struct btrfs_mkfs_config *cfg,
+               struct btrfs_convert_context *cctx)
 {
        struct btrfs_super_block super;
        struct extent_buffer *buf;
@@ -209,6 +296,8 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
                                 BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA);
        u64 num_bytes;
 
+       if (cctx)
+               return make_convert_btrfs(fd, cfg, cctx);
        buf = malloc(sizeof(*buf) + max(cfg->sectorsize, cfg->nodesize));
        if (!buf)
                return -ENOMEM;
diff --git a/utils.h b/utils.h
index 4fee469..c79f81e 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -46,6 +46,8 @@
        | BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA                \
        | BTRFS_FEATURE_INCOMPAT_NO_HOLES)
 
+#define BTRFS_CONVERT_META_GROUP_SIZE (32 * 1024 * 1024)
+
 #define BTRFS_FEATURE_LIST_ALL         (1ULL << 63)
 
 #define BTRFS_SCAN_MOUNTED     (1ULL << 0)
@@ -123,7 +125,30 @@ struct btrfs_mkfs_config {
        u64 super_bytenr;
 };
 
-int make_btrfs(int fd, struct btrfs_mkfs_config *cfg);
+struct btrfs_convert_context {
+       u32 blocksize;
+       u32 first_data_block;
+       u32 block_count;
+       u32 inodes_count;
+       u32 free_inodes_count;
+       u64 total_bytes;
+       char *volume_name;
+       const struct btrfs_convert_operations *convert_ops;
+
+       /* The accurate used space of old filesystem */
+       struct cache_tree used;
+
+       /* Batched ranges which must be covered by data chunks */
+       struct cache_tree data_chunks;
+
+       /* Free space which is not covered by data_chunks */
+       struct cache_tree free;
+
+       void *fs_data;
+};
+
+int make_btrfs(int fd, struct btrfs_mkfs_config *cfg,
+               struct btrfs_convert_context *cctx);
 int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root, u64 objectid);
 int btrfs_prepare_device(int fd, const char *file, int zero_end,