btrfs-progs: convert: properly work with large ext4 filesystems
On large (blockcount > 32bit) filesystems reading directly super_block->s_blocks_count is not sufficient as the block count is held in 2 separate 32 bit variables. Instead always use the provided ext2fs_blocks_count to read the value. This can result in assertion failure, when the block count is only held in the high 32 bits, in this case s_block_counts would be zero, which would result in btrfs_convert_context::block_count/total_bytes to also be 0 and hit an assertion failure: convert/main.c:1162: do_convert: Assertion `cctx.total_bytes != 0` failed, value 0 btrfs-convert(+0xffb0)[0x557defdabfb0] btrfs-convert(main+0x6c5)[0x557defdaa125] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xea)[0x7f66e1f8bd0a] btrfs-convert(_start+0x2a)[0x557defdab52a] Aborted What's worse it can also result in btrfs-convert mistakenly thinking that a filesystem is smaller than it actually is (ignoring the top 32 bits). Link: https://lore.kernel.org/linux-btrfs/023b5ca9-0610-231b-fc4e-a72fe1377a5a@jansson.tech/ Signed-off-by: Nikolay Borisov <nborisov@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
6f4380a95e
commit
5110ad88cb
|
@ -1134,7 +1134,6 @@ static int do_convert(const char *devname, u32 convert_flags, u32 nodesize,
|
||||||
int ret;
|
int ret;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
u32 blocksize;
|
u32 blocksize;
|
||||||
u64 total_bytes;
|
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
struct btrfs_root *image_root;
|
struct btrfs_root *image_root;
|
||||||
struct btrfs_convert_context cctx;
|
struct btrfs_convert_context cctx;
|
||||||
|
@ -1161,7 +1160,6 @@ static int do_convert(const char *devname, u32 convert_flags, u32 nodesize,
|
||||||
|
|
||||||
ASSERT(cctx.total_bytes != 0);
|
ASSERT(cctx.total_bytes != 0);
|
||||||
blocksize = cctx.blocksize;
|
blocksize = cctx.blocksize;
|
||||||
total_bytes = (u64)blocksize * (u64)cctx.block_count;
|
|
||||||
if (blocksize < 4096) {
|
if (blocksize < 4096) {
|
||||||
error("block size is too small: %u < 4096", blocksize);
|
error("block size is too small: %u < 4096", blocksize);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1223,7 +1221,7 @@ static int do_convert(const char *devname, u32 convert_flags, u32 nodesize,
|
||||||
|
|
||||||
mkfs_cfg.csum_type = csum_type;
|
mkfs_cfg.csum_type = csum_type;
|
||||||
mkfs_cfg.label = cctx.label;
|
mkfs_cfg.label = cctx.label;
|
||||||
mkfs_cfg.num_bytes = total_bytes;
|
mkfs_cfg.num_bytes = cctx.total_bytes;
|
||||||
mkfs_cfg.nodesize = nodesize;
|
mkfs_cfg.nodesize = nodesize;
|
||||||
mkfs_cfg.sectorsize = blocksize;
|
mkfs_cfg.sectorsize = blocksize;
|
||||||
mkfs_cfg.stripesize = blocksize;
|
mkfs_cfg.stripesize = blocksize;
|
||||||
|
|
|
@ -92,8 +92,8 @@ static int ext2_open_fs(struct btrfs_convert_context *cctx, const char *name)
|
||||||
|
|
||||||
cctx->fs_data = ext2_fs;
|
cctx->fs_data = ext2_fs;
|
||||||
cctx->blocksize = ext2_fs->blocksize;
|
cctx->blocksize = ext2_fs->blocksize;
|
||||||
cctx->block_count = ext2_fs->super->s_blocks_count;
|
cctx->block_count = ext2fs_blocks_count(ext2_fs->super);
|
||||||
cctx->total_bytes = (u64)ext2_fs->super->s_blocks_count * ext2_fs->blocksize;
|
cctx->total_bytes = cctx->block_count * cctx->blocksize;
|
||||||
cctx->label = strndup((char *)ext2_fs->super->s_volume_name, 16);
|
cctx->label = strndup((char *)ext2_fs->super->s_volume_name, 16);
|
||||||
cctx->first_data_block = ext2_fs->super->s_first_data_block;
|
cctx->first_data_block = ext2_fs->super->s_first_data_block;
|
||||||
cctx->inodes_count = ext2_fs->super->s_inodes_count;
|
cctx->inodes_count = ext2_fs->super->s_inodes_count;
|
||||||
|
|
Loading…
Reference in New Issue