Whamcloud - gitweb
resize2fs: don't free in-use clusters when moving blocks
authorDarrick J. Wong <darrick.wong@oracle.com>
Mon, 24 Feb 2014 01:54:54 +0000 (20:54 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 24 Feb 2014 01:54:58 +0000 (20:54 -0500)
When we're moving blocks around the filesystem, ensure that freeing
the old blocks only frees the clusters if they're not in use by other
metadata.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
resize/resize2fs.c

index caff422..6b9ca09 100644 (file)
@@ -909,12 +909,12 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
        int             j, has_super;
        dgrp_t          i, max_groups, g;
        blk64_t         blk, group_blk;
-       blk64_t         old_blocks, new_blocks;
+       blk64_t         old_blocks, new_blocks, group_end, cluster_freed;
        blk64_t         new_size;
        unsigned int    meta_bg, meta_bg_size;
        errcode_t       retval;
        ext2_filsys     fs, old_fs;
-       ext2fs_block_bitmap     meta_bmap;
+       ext2fs_block_bitmap     meta_bmap, new_meta_bmap = NULL;
        int             flex_bg;
 
        fs = rfs->new_fs;
@@ -1026,15 +1026,42 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
         * blocks as free.
         */
        if (old_blocks > new_blocks) {
+               if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
+                       retval = ext2fs_allocate_block_bitmap(fs,
+                                                       _("new meta blocks"),
+                                                       &new_meta_bmap);
+                       if (retval)
+                               goto errout;
+
+                       retval = mark_table_blocks(fs, new_meta_bmap);
+                       if (retval)
+                               goto errout;
+               }
+
                for (i = 0; i < max_groups; i++) {
                        if (!ext2fs_bg_has_super(fs, i)) {
                                group_blk += fs->super->s_blocks_per_group;
                                continue;
                        }
-                       for (blk = group_blk+1+new_blocks;
-                            blk < group_blk+1+old_blocks; blk++) {
-                               ext2fs_block_alloc_stats2(fs, blk, -1);
+                       group_end = group_blk + 1 + old_blocks;
+                       for (blk = group_blk + 1 + new_blocks;
+                            blk < group_end;) {
+                               if (new_meta_bmap == NULL ||
+                                   !ext2fs_test_block_bitmap2(new_meta_bmap,
+                                                              blk)) {
+                                       cluster_freed =
+                                               EXT2FS_CLUSTER_RATIO(fs) -
+                                               (blk &
+                                                EXT2FS_CLUSTER_MASK(fs));
+                                       if (cluster_freed > group_end - blk)
+                                               cluster_freed = group_end - blk;
+                                       ext2fs_block_alloc_stats2(fs, blk, -1);
+                                       blk += EXT2FS_CLUSTER_RATIO(fs);
+                                       rfs->needed_blocks -= cluster_freed;
+                                       continue;
+                               }
                                rfs->needed_blocks--;
+                               blk++;
                        }
                        group_blk += fs->super->s_blocks_per_group;
                }
@@ -1180,6 +1207,8 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
        retval = 0;
 
 errout:
+       if (new_meta_bmap)
+               ext2fs_free_block_bitmap(new_meta_bmap);
        if (meta_bmap)
                ext2fs_free_block_bitmap(meta_bmap);
 
@@ -1779,9 +1808,10 @@ static errcode_t move_itables(ext2_resize_t rfs)
        dgrp_t          i, max_groups;
        ext2_filsys     fs = rfs->new_fs;
        char            *cp;
-       blk64_t         old_blk, new_blk, blk;
+       blk64_t         old_blk, new_blk, blk, cluster_freed;
        errcode_t       retval;
        int             j, to_move, moved;
+       ext2fs_block_bitmap     new_bmap = NULL;
 
        max_groups = fs->group_desc_count;
        if (max_groups > rfs->old_fs->group_desc_count)
@@ -1794,6 +1824,17 @@ static errcode_t move_itables(ext2_resize_t rfs)
                        return retval;
        }
 
+       if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
+               retval = ext2fs_allocate_block_bitmap(fs, _("new meta blocks"),
+                                                     &new_bmap);
+               if (retval)
+                       return retval;
+
+               retval = mark_table_blocks(fs, new_bmap);
+               if (retval)
+                       goto errout;
+       }
+
        /*
         * Figure out how many inode tables we need to move
         */
@@ -1871,8 +1912,19 @@ static errcode_t move_itables(ext2_resize_t rfs)
                }
 
                for (blk = ext2fs_inode_table_loc(rfs->old_fs, i), j=0;
-                    j < fs->inode_blocks_per_group ; j++, blk++)
-                       ext2fs_block_alloc_stats2(fs, blk, -1);
+                    j < fs->inode_blocks_per_group;) {
+                       if (new_bmap == NULL ||
+                           !ext2fs_test_block_bitmap2(new_bmap, blk)) {
+                               ext2fs_block_alloc_stats2(fs, blk, -1);
+                               cluster_freed = EXT2FS_CLUSTER_RATIO(fs) -
+                                               (blk & EXT2FS_CLUSTER_MASK(fs));
+                               blk += cluster_freed;
+                               j += cluster_freed;
+                               continue;
+                       }
+                       blk++;
+                       j++;
+               }
 
                ext2fs_inode_table_loc_set(rfs->old_fs, i, new_blk);
                ext2fs_group_desc_csum_set(rfs->old_fs, i);
@@ -1892,9 +1944,11 @@ static errcode_t move_itables(ext2_resize_t rfs)
        if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
                printf("Inode table move finished.\n");
 #endif
-       return 0;
+       retval = 0;
 
 errout:
+       if (new_bmap)
+               ext2fs_free_block_bitmap(new_bmap);
        return retval;
 }