Whamcloud - gitweb
resize2fs: Release bitmap and itable blocks in flex_bg filesystems
authorTheodore Ts'o <tytso@mit.edu>
Mon, 19 Jan 2009 14:02:55 +0000 (09:02 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 19 Jan 2009 14:02:55 +0000 (09:02 -0500)
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>
resize/resize2fs.c

index e7a08da..df4dac7 100644 (file)
@@ -232,6 +232,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;
        }