resize2fs: Release bitmap and itable blocks in flex_bg filesystems

Previously resize2fs assumed that bitmap and inode table blocks were
always located in their respective block group.  However, this is no
longer true with flex_bg.  So it is necessary to check all of the
block groups which will be truncated to see if they have metadata
blocks that need to be marked as no longer being in use in the new,
shrunk filesystem.

This bug fixes resize2fs -M, which would otherwise fail because
without the released blocks, there would not be enough space in the
filesystem.  This bug also avoids (mostly harmless) filesystem
corruptions reported by e2fsck regarding blocks marked in use but not
actually used (these being the bitmap and inode table blocks
associated with the truncated block groups).

Note: in theory it is possible to have block group N utilize bitmap
and inode table blocks in block group N+X with flex_bg.  At the moment
neither mke2fs nor e2fsck will create filesystems like this, which is
good, because resize2fs doesn't handle this case correctly.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
bitmap-optimize
Theodore Ts'o 2009-01-19 09:02:55 -05:00
parent c58a08e673
commit 9227c5bbbd
1 changed files with 37 additions and 0 deletions

View File

@ -231,6 +231,35 @@ static void fix_uninit_block_bitmaps(ext2_filsys fs)
* --------------------------------------------------------------------
*/
/*
* If the group descriptor's bitmap and inode table blocks are valid,
* release them in the specified filesystem data structure
*/
static void free_gdp_blocks(ext2_filsys fs, struct ext2_group_desc *gdp)
{
blk_t blk;
int j;
if (gdp->bg_block_bitmap &&
(gdp->bg_block_bitmap < fs->super->s_blocks_count))
ext2fs_block_alloc_stats(fs, gdp->bg_block_bitmap, -1);
if (gdp->bg_inode_bitmap &&
(gdp->bg_inode_bitmap < fs->super->s_blocks_count))
ext2fs_block_alloc_stats(fs, gdp->bg_inode_bitmap, -1);
if (gdp->bg_inode_table == 0 ||
(gdp->bg_inode_table >= fs->super->s_blocks_count))
return;
for (blk = gdp->bg_inode_table, j = 0;
j < fs->inode_blocks_per_group; j++, blk++) {
if (blk >= fs->super->s_blocks_count)
break;
ext2fs_block_alloc_stats(fs, blk, -1);
}
}
/*
* This routine is shared by the online and offline resize routines.
* All of the information which is adjusted in memory is done here.
@ -374,6 +403,14 @@ retry:
* can exit now.
*/
if (old_fs->group_desc_count > fs->group_desc_count) {
/*
* Check the block groups that we are chopping off
* and free any blocks associated with their metadata
*/
for (i = fs->group_desc_count;
i < old_fs->group_desc_count; i++) {
free_gdp_blocks(fs, &old_fs->group_desc[i]);
}
retval = 0;
goto errout;
}