btrfs-progs: utils: Introduce new function for convert

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>
This commit is contained in:
Qu Wenruo 2016-01-29 13:03:14 +08:00 committed by David Sterba
parent 522ef705e3
commit 330ca2d6df
4 changed files with 118 additions and 26 deletions

View 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));

2
mkfs.c
View File

@ -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);

91
utils.c
View File

@ -181,10 +181,97 @@ int test_uuid_unique(char *fs_uuid)
return unique;
}
/*
* 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;

27
utils.h
View File

@ -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,