Use same code for flex_bg and no flex_bg; check for gdt_csum feature before adjusting free_inodes_count; the tool now works correctly on ext2
parent
36ac4a8330
commit
b8f52b6c8b
|
@ -4,11 +4,13 @@
|
||||||
# To test growing: INODES=2048, then ./realloc-inodes test-clean.img 8192
|
# To test growing: INODES=2048, then ./realloc-inodes test-clean.img 8192
|
||||||
|
|
||||||
INODES=2048
|
INODES=2048
|
||||||
|
FILE=test-ext4-grow.img
|
||||||
|
FS=ext4
|
||||||
|
|
||||||
dd if=/dev/zero of=test-clean.img bs=1k seek=32767 count=1
|
dd if=/dev/zero of=$FILE bs=1k seek=32767 count=1
|
||||||
/sbin/mkfs.ext4 -F -b 1024 -m 0 -g 2048 -N $INODES test-clean.img
|
/sbin/mkfs.$FS -F -b 1024 -m 0 -g 2048 -N $INODES $FILE
|
||||||
mkdir -p dir
|
mkdir -p dir
|
||||||
mount -o loop test-clean.img dir
|
mount -o loop $FILE dir
|
||||||
# For block moving test: create a sparse file with many extents
|
# For block moving test: create a sparse file with many extents
|
||||||
dd if=/dev/urandom of=dir/f_random bs=1k count=1
|
dd if=/dev/urandom of=dir/f_random bs=1k count=1
|
||||||
for i in {1..1200}; do
|
for i in {1..1200}; do
|
||||||
|
|
158
realloc-inodes.c
158
realloc-inodes.c
|
@ -409,7 +409,7 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
dgrp_t grp, flex_grp, flex_count;
|
dgrp_t grp, flex_grp, flex_count;
|
||||||
__u32 unus;
|
__u32 unus;
|
||||||
int i_per_g_diff = rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super);
|
int i_per_g_diff = rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super);
|
||||||
int flexbg_size = 0, n_grp, i, retval = 0;
|
int flexbg_size, n_grp, i, retval = 0;
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
ext2fs_flush(rd->fs);
|
ext2fs_flush(rd->fs);
|
||||||
if (!rd->fs->block_map)
|
if (!rd->fs->block_map)
|
||||||
|
@ -418,71 +418,77 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
}
|
}
|
||||||
if (rd->new_inode_blocks_per_group != rd->fs->inode_blocks_per_group)
|
if (rd->new_inode_blocks_per_group != rd->fs->inode_blocks_per_group)
|
||||||
{
|
{
|
||||||
// Move inode tables if flex_bg is active
|
|
||||||
if (EXT2_HAS_INCOMPAT_FEATURE(rd->fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)
|
if (EXT2_HAS_INCOMPAT_FEATURE(rd->fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)
|
||||||
&& rd->fs->super->s_log_groups_per_flex)
|
&& rd->fs->super->s_log_groups_per_flex)
|
||||||
{
|
{
|
||||||
flexbg_size = 1 << rd->fs->super->s_log_groups_per_flex;
|
flexbg_size = 1 << rd->fs->super->s_log_groups_per_flex;
|
||||||
flex_count = (rd->fs->group_desc_count + flexbg_size - 1) / flexbg_size;
|
}
|
||||||
retval = ext2fs_get_mem(EXT2_BLOCK_SIZE(rd->fs->super) * rd->new_inode_blocks_per_group * flexbg_size, &buf);
|
else
|
||||||
if (retval)
|
{
|
||||||
|
flexbg_size = 1;
|
||||||
|
}
|
||||||
|
flex_count = (rd->fs->group_desc_count + flexbg_size - 1) / flexbg_size;
|
||||||
|
retval = ext2fs_get_mem(EXT2_BLOCK_SIZE(rd->fs->super) * rd->new_inode_blocks_per_group * flexbg_size, &buf);
|
||||||
|
if (retval)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (flex_grp = 0; flex_grp < flex_count; flex_grp++)
|
||||||
|
{
|
||||||
|
memset(buf, 0, EXT2_BLOCK_SIZE(rd->fs->super) * rd->new_inode_blocks_per_group * flexbg_size);
|
||||||
|
n_grp = flexbg_size;
|
||||||
|
if (flex_grp*flexbg_size+n_grp > rd->fs->group_desc_count)
|
||||||
{
|
{
|
||||||
goto out;
|
n_grp = rd->fs->group_desc_count-flex_grp*flexbg_size;
|
||||||
}
|
}
|
||||||
for (flex_grp = 0; flex_grp < flex_count; flex_grp++)
|
// Read inode table(s)
|
||||||
|
for (grp = flex_grp*flexbg_size, i = 0; i < n_grp; grp++, i++)
|
||||||
{
|
{
|
||||||
memset(buf, 0, EXT2_BLOCK_SIZE(rd->fs->super) * rd->new_inode_blocks_per_group * flexbg_size);
|
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
|
||||||
n_grp = flexbg_size;
|
|
||||||
if (flex_grp*flexbg_size+n_grp > rd->fs->group_desc_count)
|
|
||||||
{
|
{
|
||||||
n_grp = rd->fs->group_desc_count-flex_grp*flexbg_size;
|
blk = ext2fs_inode_table_loc(rd->fs, grp);
|
||||||
}
|
retval = io_channel_read_blk64(rd->fs->io, blk,
|
||||||
// Read inode tables
|
min(rd->fs->inode_blocks_per_group, rd->new_inode_blocks_per_group),
|
||||||
for (grp = flex_grp*flexbg_size, i = 0; i < n_grp; grp++, i++)
|
buf + i*rd->new_inode_blocks_per_group*EXT2_BLOCK_SIZE(rd->fs->super));
|
||||||
{
|
if (retval)
|
||||||
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
|
|
||||||
{
|
{
|
||||||
blk = ext2fs_inode_table_loc(rd->fs, grp);
|
goto out;
|
||||||
retval = io_channel_read_blk64(rd->fs->io, blk,
|
|
||||||
min(rd->fs->inode_blocks_per_group, rd->new_inode_blocks_per_group),
|
|
||||||
buf + i*rd->new_inode_blocks_per_group*EXT2_BLOCK_SIZE(rd->fs->super));
|
|
||||||
if (retval)
|
|
||||||
{
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Write inode table to the new place
|
}
|
||||||
it_start = ext2fs_inode_table_loc(rd->fs, flex_grp*flexbg_size);
|
// Write inode table(s) to the new place
|
||||||
blk = rd->new_inode_blocks_per_group * n_grp;
|
it_start = ext2fs_inode_table_loc(rd->fs, flex_grp*flexbg_size);
|
||||||
retval = io_channel_write_blk64(rd->fs->io, it_start, blk, buf);
|
blk = rd->new_inode_blocks_per_group * n_grp;
|
||||||
if (retval)
|
retval = io_channel_write_blk64(rd->fs->io, it_start, blk, buf);
|
||||||
|
if (retval)
|
||||||
|
{
|
||||||
|
// Exiting with badly corrupted filesystem :-(
|
||||||
|
printf("Error moving inode tables for %u groups, starting from %u\n", n_grp, flex_grp*flexbg_size);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
// Mark/unmark extra inode table blocks
|
||||||
|
if (rd->new_inode_blocks_per_group < rd->fs->inode_blocks_per_group)
|
||||||
|
{
|
||||||
|
ext2fs_unmark_block_bitmap_range2(rd->fs->block_map, it_start+blk,
|
||||||
|
(rd->fs->inode_blocks_per_group-rd->new_inode_blocks_per_group)*n_grp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ext2fs_mark_block_bitmap_range2(rd->fs->block_map, it_start+rd->fs->inode_blocks_per_group*n_grp,
|
||||||
|
(rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group)*n_grp);
|
||||||
|
}
|
||||||
|
ext2fs_bg_free_blocks_count_set(rd->fs, flex_grp*flexbg_size,
|
||||||
|
ext2fs_bg_free_blocks_count(rd->fs, flex_grp*flexbg_size) -
|
||||||
|
(rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group)*flexbg_size);
|
||||||
|
// Change inode table locations and free inode counts
|
||||||
|
for (grp = flex_grp*flexbg_size, i = 0; i < n_grp; grp++, i++)
|
||||||
|
{
|
||||||
|
blk = it_start + rd->new_inode_blocks_per_group*i;
|
||||||
|
ext2fs_inode_table_loc_set(rd->fs, grp, blk);
|
||||||
|
ext2fs_bg_free_inodes_count_set(rd->fs, grp,
|
||||||
|
ext2fs_bg_free_inodes_count(rd->fs, grp) + i_per_g_diff);
|
||||||
|
if (EXT2_HAS_RO_COMPAT_FEATURE(rd->fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
|
||||||
{
|
{
|
||||||
// The FS is badly corrupted now :-(
|
|
||||||
printf("Error moving inode tables for %u groups, starting from %u\n", n_grp, flex_grp*flexbg_size);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
// Mark/unmark extra inode table blocks
|
|
||||||
if (rd->new_inode_blocks_per_group < rd->fs->inode_blocks_per_group)
|
|
||||||
{
|
|
||||||
ext2fs_unmark_block_bitmap_range2(rd->fs->block_map, it_start+blk,
|
|
||||||
(rd->fs->inode_blocks_per_group-rd->new_inode_blocks_per_group)*n_grp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ext2fs_mark_block_bitmap_range2(rd->fs->block_map, it_start+rd->fs->inode_blocks_per_group*n_grp,
|
|
||||||
(rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group)*n_grp);
|
|
||||||
}
|
|
||||||
ext2fs_bg_free_blocks_count_set(rd->fs, flex_grp*flexbg_size,
|
|
||||||
ext2fs_bg_free_blocks_count(rd->fs, flex_grp*flexbg_size) -
|
|
||||||
(rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group)*flexbg_size);
|
|
||||||
// Change inode table locations and free inode counts
|
|
||||||
for (grp = flex_grp*flexbg_size, i = 0; i < n_grp; grp++, i++)
|
|
||||||
{
|
|
||||||
blk = it_start + rd->new_inode_blocks_per_group*i;
|
|
||||||
ext2fs_inode_table_loc_set(rd->fs, grp, blk);
|
|
||||||
ext2fs_bg_free_inodes_count_set(rd->fs, grp,
|
|
||||||
ext2fs_bg_free_inodes_count(rd->fs, grp) + i_per_g_diff);
|
|
||||||
unus = ext2fs_bg_itable_unused(rd->fs, grp);
|
unus = ext2fs_bg_itable_unused(rd->fs, grp);
|
||||||
if (i_per_g_diff > 0)
|
if (i_per_g_diff > 0)
|
||||||
{
|
{
|
||||||
|
@ -502,53 +508,17 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Mark/unmark extra inode table blocks (without flex_bg)
|
|
||||||
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
|
|
||||||
{
|
|
||||||
it_start = ext2fs_inode_table_loc(rd->fs, grp);
|
|
||||||
if (rd->new_inode_blocks_per_group < rd->fs->inode_blocks_per_group)
|
|
||||||
{
|
|
||||||
ext2fs_unmark_block_bitmap_range2(rd->fs->block_map, it_start,
|
|
||||||
rd->fs->inode_blocks_per_group-rd->new_inode_blocks_per_group);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ext2fs_mark_block_bitmap_range2(rd->fs->block_map, it_start,
|
|
||||||
rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group);
|
|
||||||
}
|
|
||||||
ext2fs_bg_free_blocks_count_set(rd->fs, grp, ext2fs_bg_free_blocks_count(rd->fs, grp) -
|
|
||||||
rd->new_inode_blocks_per_group + rd->fs->inode_blocks_per_group);
|
|
||||||
ext2fs_bg_free_inodes_count_set(rd->fs, grp, ext2fs_bg_free_inodes_count(rd->fs, grp) +
|
|
||||||
rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super));
|
|
||||||
unus = ext2fs_bg_itable_unused(rd->fs, grp);
|
|
||||||
if (i_per_g_diff > 0)
|
|
||||||
{
|
|
||||||
unus += i_per_g_diff;
|
|
||||||
}
|
|
||||||
else if (unus < (unsigned)-i_per_g_diff)
|
|
||||||
{
|
|
||||||
unus = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unus = unus + i_per_g_diff;
|
|
||||||
}
|
|
||||||
ext2fs_bg_itable_unused_set(rd->fs, grp, unus);
|
|
||||||
ext2fs_bg_flags_clear(rd->fs, grp, EXT2_BG_BLOCK_UNINIT);
|
|
||||||
ext2fs_group_desc_csum_set(rd->fs, grp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Bitmaps don't need to be moved because a single bitmap is always a single FS block
|
||||||
ext2fs_mark_bb_dirty(rd->fs);
|
ext2fs_mark_bb_dirty(rd->fs);
|
||||||
retval = rd->fs->write_bitmaps(rd->fs);
|
retval = rd->fs->write_bitmaps(rd->fs);
|
||||||
if (retval)
|
if (retval)
|
||||||
{
|
{
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
rd->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
|
|
||||||
rd->fs->write_bitmaps = NULL;
|
rd->fs->write_bitmaps = NULL;
|
||||||
|
// Explicitly set 'overwrite backup superblocks' flag
|
||||||
|
rd->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
|
||||||
ext2fs_free_blocks_count_add(rd->fs->super, rd->fs->group_desc_count * (rd->fs->inode_blocks_per_group - rd->new_inode_blocks_per_group));
|
ext2fs_free_blocks_count_add(rd->fs->super, rd->fs->group_desc_count * (rd->fs->inode_blocks_per_group - rd->new_inode_blocks_per_group));
|
||||||
rd->fs->super->s_free_inodes_count += rd->fs->group_desc_count * (rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super));
|
rd->fs->super->s_free_inodes_count += rd->fs->group_desc_count * (rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super));
|
||||||
rd->fs->super->s_inodes_per_group = rd->new_inodes_per_group;
|
rd->fs->super->s_inodes_per_group = rd->new_inodes_per_group;
|
||||||
|
@ -556,7 +526,7 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
ext2fs_mark_super_dirty(rd->fs);
|
ext2fs_mark_super_dirty(rd->fs);
|
||||||
if (rd->new_inodes_per_group > rd->old_inodes_per_group)
|
if (rd->new_inodes_per_group > rd->old_inodes_per_group)
|
||||||
{
|
{
|
||||||
// Mark newly allocated inodes as free
|
// Mark newly allocated inodes as free in the bitmap
|
||||||
__u32 ino;
|
__u32 ino;
|
||||||
ext2fs_read_inode_bitmap(rd->fs);
|
ext2fs_read_inode_bitmap(rd->fs);
|
||||||
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
|
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
|
||||||
|
|
Loading…
Reference in New Issue