From 9227c5bbbd0861878ae73f7dceb4deb9e9f06a3c Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 19 Jan 2009 09:02:55 -0500 Subject: 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" --- resize/resize2fs.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/resize/resize2fs.c b/resize/resize2fs.c index e7a08daa..df4dac7f 100644 --- a/resize/resize2fs.c +++ b/resize/resize2fs.c @@ -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; } -- cgit v1.2.3