btrfs-progs: convert: report available space before conversion happens

Now if an ENOSPC error happened, the free space report would help user
to determine if it's a real ENOSPC or a bug in convert.

The reported free space is the calculated free space, which doesn't
include super block space, nor merged data chunks.

The free space is always smaller than the reported available space of
the original fs, as we need extra padding space for used space to avoid
too fragmented data chunks.

The output would be:

$ ./btrfs-convert /dev/sda
create btrfs filesystem:
        blocksize: 4096
        nodesize:  16384
        features:  extref, skinny-metadata (default)
        checksum:  crc32c
free space report:
        total:     10737418240
        free:      0 (0.00%)
ERROR: unable to create initial ctree: No space left on device
WARNING: an error occurred during conversion, the original filesystem is not modified

Signed-off-by: Qu Wenruo <wqu@suse.com>
[ put total, free to separate lines ]
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2020-07-29 16:40:38 +08:00 committed by David Sterba
parent 5587635716
commit d353a5b3c2
3 changed files with 36 additions and 2 deletions

View File

@ -35,6 +35,7 @@ struct btrfs_convert_context {
u64 inodes_count;
u64 free_inodes_count;
u64 total_bytes;
u64 free_bytes_initial;
char *volume_name;
const struct btrfs_convert_operations *convert_ops;
@ -47,6 +48,13 @@ struct btrfs_convert_context {
/* Free space which is not covered by data_chunks */
struct cache_tree free_space;
/*
* Free space reserved for ENOSPC report, it's just a copy free_space.
* But after initial calculation, free_space_initial is no longer
* updated, so we have a good idea on how much free space we really
* have for btrfs.
*/
struct cache_tree free_space_initial;
void *fs_data;
};

View File

@ -727,6 +727,24 @@ out:
return ret;
}
static int copy_free_space_tree(struct btrfs_convert_context *cctx)
{
struct cache_tree *src = &cctx->free_space;
struct cache_tree *dst = &cctx->free_space_initial;
struct cache_extent *cache;
int ret = 0;
for (cache = search_cache_extent(src, 0);
cache;
cache = next_cache_extent(cache)) {
ret = add_merge_cache_extent(dst, cache->start, cache->size);
if (ret < 0)
return ret;
cctx->free_bytes_initial += cache->size;
}
return ret;
}
/*
* Read used space, and since we have the used space,
* calculate data_chunks and free for later mkfs
@ -740,7 +758,10 @@ static int convert_read_used_space(struct btrfs_convert_context *cctx)
return ret;
ret = calculate_available_space(cctx);
return ret;
if (ret < 0)
return ret;
return copy_free_space_tree(cctx);
}
/*
@ -1165,7 +1186,10 @@ static int do_convert(const char *devname, u32 convert_flags, u32 nodesize,
printf("\tnodesize: %u\n", nodesize);
printf("\tfeatures: %s\n", features_buf);
printf("\tchecksum: %s\n", btrfs_super_csum_name(csum_type));
printf("free space report:\n");
printf("\ttotal: %llu\n",cctx.total_bytes);
printf("\tfree: %llu (%.2f%%)\n", cctx.free_bytes_initial,
100.0 * cctx.free_bytes_initial / cctx.total_bytes);
memset(&mkfs_cfg, 0, sizeof(mkfs_cfg));
mkfs_cfg.csum_type = csum_type;
mkfs_cfg.label = cctx.volume_name;

View File

@ -74,6 +74,7 @@ void init_convert_context(struct btrfs_convert_context *cctx)
cache_tree_init(&cctx->used_space);
cache_tree_init(&cctx->data_chunks);
cache_tree_init(&cctx->free_space);
cache_tree_init(&cctx->free_space_initial);
}
void clean_convert_context(struct btrfs_convert_context *cctx)
@ -81,6 +82,7 @@ void clean_convert_context(struct btrfs_convert_context *cctx)
free_extent_cache_tree(&cctx->used_space);
free_extent_cache_tree(&cctx->data_chunks);
free_extent_cache_tree(&cctx->free_space);
free_extent_cache_tree(&cctx->free_space_initial);
}
int block_iterate_proc(u64 disk_block, u64 file_block,